Copy it 🚀

Hold Alt click on text, Copy content, And supports different variable naming styles.

  1. // ==UserScript==
  2. // @name Copy it 🚀
  3. // @name:zh-CN 便捷复制 🚀
  4. // @namespace https://github.com/xianghongai/Tampermonkey-UserScript
  5. // @version 1.5.0
  6. // @description Hold Alt click on text, Copy content, And supports different variable naming styles.
  7. // @description:zh-CN 按住 Alt 键点击文本,复制文本内容,并且,支持不同变量命名风格。
  8. // @author Nicholas Hsiang
  9. // @icon https://xinlu.ink/favicon.ico
  10. // @match http*://*/*
  11. // @exclude *://*.github.dev
  12. // @grant GM_setClipboard
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. function main() {
  17. 'use strict';
  18.  
  19. console.log('🚀 Copy it');
  20.  
  21. let leftAltPressed = false;
  22. let rightAltPressed = false;
  23.  
  24. // https://www.w3schools.com/js/tryit.asp?filename=tryjs_addeventlistener_usecapture
  25. // true: capturing, 当目标元素有添加事件,停止冒泡,以致无法生效,采用捕获模式
  26. // false: bubbling,当目标元素有添加事件,并有其它交互行为 (切换视图、打开弹窗...),以致无法额外触发,采用冒泡模式
  27. document.addEventListener('click', listener, true);
  28.  
  29. // camelCase,capitalize,kebabCase,snakeCase
  30. function listener(event) {
  31. if (event.altKey) {
  32. event.preventDefault();
  33. event.stopPropagation();
  34. let target = event?.composedPath()[0] ?? event.target;
  35. // 获取元素的文本内容
  36. let text = getText(target);
  37. if (rightAltPressed) {
  38. // 1. 复制为 snake_case 风格,按键:右 Alt + Click
  39. return copyTextToClipboard(_.snakeCase(text));
  40. } else if (event.shiftKey && !event.ctrlKey) {
  41. // 2. 复制为 kebab-case 风格,按键:Alt + Shift + Click
  42. return copyTextToClipboard(_.kebabCase(text));
  43. } else if (!event.shiftKey && event.ctrlKey) {
  44. // 3. 复制为 PascalCase 风格,按键:Alt + Ctrl + Click
  45. return copyTextToClipboard(pascalCase(text));
  46. } else if (event.shiftKey && event.ctrlKey) {
  47. // 4. 复制元素的 title 属性,按键:Alt + Ctrl + Shift + Click
  48. text = event.target.title;
  49. return copyTextToClipboard(text);
  50. }
  51. // 0. 复制为纯文本,按键:Alt + Click
  52. return copyTextToClipboard(text);
  53. }
  54. }
  55.  
  56. const VALUE_CONTROLLER = ['INPUT', 'TEXTAREA'];
  57.  
  58. function getText(el) {
  59. let text = '';
  60. if (VALUE_CONTROLLER.includes(el.tagName)) {
  61. const value = `${el.value}`.trim();
  62. const placeholder = el.placeholder ?? '';
  63. text = value === '' ? placeholder : value;
  64. } else if (el.tagName === 'SELECT') {
  65. const selectedOption = el.options[el.selectedIndex];
  66. text = selectedOption.text;
  67. } else if (el.tagName === 'tspan') {
  68. // svg/text/tspan
  69. text = [...el.parentElement.querySelectorAll('tspan')].reduce((acc, cur) => `${acc} ${cur.textContent}`, '')
  70. } else {
  71.  
  72. text = el.innerText;
  73. }
  74. return text.trim();
  75. }
  76.  
  77. function copyTextToClipboard(text) {
  78. GM_setClipboard(text, 'text');
  79. }
  80.  
  81. function pascalCase(input) {
  82. return _.upperFirst(_.camelCase(input));
  83. }
  84.  
  85. // 监听 Alt 键状态
  86. document.addEventListener('keydown', (event) => {
  87. if (event.key === 'Alt') {
  88. event.preventDefault();
  89. if (event.location === 1) leftAltPressed = true;
  90. if (event.location === 2) rightAltPressed = true;
  91. }
  92. });
  93.  
  94. document.addEventListener('keyup', (event) => {
  95. if (event.key === 'Alt') {
  96. if (event.location === 1) leftAltPressed = false;
  97. if (event.location === 2) rightAltPressed = false;
  98. }
  99. });
  100.  
  101. // 浏览器兼容性处理
  102. function isAltPressed(event) {
  103. // 降级处理
  104. return event.altKey || event.keyCode === 18 || event.key === 'Alt';
  105. }
  106.  
  107. function keydown(event) {
  108. // 在 macOS 上,Option (ALT) 键有特殊功能,它用于输入特殊字符和符号。
  109. // 按下 Option+T 时,macOS 可能将其解释为一个特殊字符输入,而不是单纯的修饰键+字母组合,
  110. // 这就导致 JavaScript 事件系统接收到的不是标准的按键事件,而是 "Unidentified"。
  111. // event.code 表示物理按键的位置,与键盘布局无关。
  112. if (event.altKey && event.code === 'KeyT') {
  113. copyTextToClipboard(location.href);
  114. event.preventDefault();
  115. event.stopPropagation();
  116. }
  117. }
  118.  
  119. document.addEventListener('keydown', keydown, true);
  120. }
  121.  
  122.  
  123. /**
  124. * @license
  125. * Lodash (Custom Build) <https://lodash.com/>
  126. * Build: `lodash include="camelCase,capitalize,kebabCase,snakeCase,"`
  127. * Copyright JS Foundation and other contributors <https://js.foundation/>
  128. * Released under MIT license <https://lodash.com/license>
  129. * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
  130. * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
  131. */
  132. ; (function () {
  133.  
  134. /** Used as a safe reference for `undefined` in pre-ES5 environments. */
  135. var undefined;
  136.  
  137. /** Used as the semantic version number. */
  138. var VERSION = '4.17.5';
  139.  
  140. /** Used as references for various `Number` constants. */
  141. var INFINITY = 1 / 0;
  142.  
  143. /** `Object#toString` result references. */
  144. var nullTag = '[object Null]',
  145. symbolTag = '[object Symbol]',
  146. undefinedTag = '[object Undefined]';
  147.  
  148. /** Used to match words composed of alphanumeric characters. */
  149. var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
  150.  
  151. /** Used to match Latin Unicode letters (excluding mathematical operators). */
  152. var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
  153.  
  154. /** Used to compose unicode character classes. */
  155. var rsAstralRange = '\\ud800-\\udfff',
  156. rsComboMarksRange = '\\u0300-\\u036f',
  157. reComboHalfMarksRange = '\\ufe20-\\ufe2f',
  158. rsComboSymbolsRange = '\\u20d0-\\u20ff',
  159. rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
  160. rsDingbatRange = '\\u2700-\\u27bf',
  161. rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
  162. rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
  163. rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
  164. rsPunctuationRange = '\\u2000-\\u206f',
  165. rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
  166. rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
  167. rsVarRange = '\\ufe0e\\ufe0f',
  168. rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
  169.  
  170. /** Used to compose unicode capture groups. */
  171. var rsApos = "['\u2019]",
  172. rsAstral = '[' + rsAstralRange + ']',
  173. rsBreak = '[' + rsBreakRange + ']',
  174. rsCombo = '[' + rsComboRange + ']',
  175. rsDigits = '\\d+',
  176. rsDingbat = '[' + rsDingbatRange + ']',
  177. rsLower = '[' + rsLowerRange + ']',
  178. rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
  179. rsFitz = '\\ud83c[\\udffb-\\udfff]',
  180. rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
  181. rsNonAstral = '[^' + rsAstralRange + ']',
  182. rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
  183. rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
  184. rsUpper = '[' + rsUpperRange + ']',
  185. rsZWJ = '\\u200d';
  186.  
  187. /** Used to compose unicode regexes. */
  188. var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
  189. rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
  190. rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
  191. rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
  192. reOptMod = rsModifier + '?',
  193. rsOptVar = '[' + rsVarRange + ']?',
  194. rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
  195. rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
  196. rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
  197. rsSeq = rsOptVar + reOptMod + rsOptJoin,
  198. rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
  199. rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
  200.  
  201. /** Used to match apostrophes. */
  202. var reApos = RegExp(rsApos, 'g');
  203.  
  204. /**
  205. * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
  206. * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
  207. */
  208. var reComboMark = RegExp(rsCombo, 'g');
  209.  
  210. /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
  211. var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
  212.  
  213. /** Used to match complex or compound words. */
  214. var reUnicodeWord = RegExp([
  215. rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
  216. rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
  217. rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
  218. rsUpper + '+' + rsOptContrUpper,
  219. rsOrdUpper,
  220. rsOrdLower,
  221. rsDigits,
  222. rsEmoji
  223. ].join('|'), 'g');
  224.  
  225. /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
  226. var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');
  227.  
  228. /** Used to detect strings that need a more robust regexp to match words. */
  229. var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
  230.  
  231. /** Used to map Latin Unicode letters to basic Latin letters. */
  232. var deburredLetters = {
  233. // Latin-1 Supplement block.
  234. '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
  235. '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
  236. '\xc7': 'C', '\xe7': 'c',
  237. '\xd0': 'D', '\xf0': 'd',
  238. '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
  239. '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
  240. '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
  241. '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
  242. '\xd1': 'N', '\xf1': 'n',
  243. '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
  244. '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
  245. '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
  246. '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
  247. '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
  248. '\xc6': 'Ae', '\xe6': 'ae',
  249. '\xde': 'Th', '\xfe': 'th',
  250. '\xdf': 'ss',
  251. // Latin Extended-A block.
  252. '\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
  253. '\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
  254. '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
  255. '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
  256. '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
  257. '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
  258. '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
  259. '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
  260. '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
  261. '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
  262. '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
  263. '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
  264. '\u0134': 'J', '\u0135': 'j',
  265. '\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
  266. '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
  267. '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
  268. '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
  269. '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
  270. '\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
  271. '\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
  272. '\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
  273. '\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
  274. '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
  275. '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
  276. '\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
  277. '\u0163': 't', '\u0165': 't', '\u0167': 't',
  278. '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
  279. '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
  280. '\u0174': 'W', '\u0175': 'w',
  281. '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
  282. '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
  283. '\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
  284. '\u0132': 'IJ', '\u0133': 'ij',
  285. '\u0152': 'Oe', '\u0153': 'oe',
  286. '\u0149': "'n", '\u017f': 's'
  287. };
  288.  
  289. /** Detect free variable `global` from Node.js. */
  290. var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
  291.  
  292. /** Detect free variable `self`. */
  293. var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
  294.  
  295. /** Used as a reference to the global object. */
  296. var root = freeGlobal || freeSelf || Function('return this')();
  297.  
  298. /** Detect free variable `exports`. */
  299. var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
  300.  
  301. /** Detect free variable `module`. */
  302. var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
  303.  
  304. /*--------------------------------------------------------------------------*/
  305.  
  306. /**
  307. * A specialized version of `_.map` for arrays without support for iteratee
  308. * shorthands.
  309. *
  310. * @private
  311. * @param {Array} [array] The array to iterate over.
  312. * @param {Function} iteratee The function invoked per iteration.
  313. * @returns {Array} Returns the new mapped array.
  314. */
  315. function arrayMap(array, iteratee) {
  316. var index = -1,
  317. length = array == null ? 0 : array.length,
  318. result = Array(length);
  319.  
  320. while (++index < length) {
  321. result[index] = iteratee(array[index], index, array);
  322. }
  323. return result;
  324. }
  325.  
  326. /**
  327. * A specialized version of `_.reduce` for arrays without support for
  328. * iteratee shorthands.
  329. *
  330. * @private
  331. * @param {Array} [array] The array to iterate over.
  332. * @param {Function} iteratee The function invoked per iteration.
  333. * @param {*} [accumulator] The initial value.
  334. * @param {boolean} [initAccum] Specify using the first element of `array` as
  335. * the initial value.
  336. * @returns {*} Returns the accumulated value.
  337. */
  338. function arrayReduce(array, iteratee, accumulator, initAccum) {
  339. var index = -1,
  340. length = array == null ? 0 : array.length;
  341.  
  342. if (initAccum && length) {
  343. accumulator = array[++index];
  344. }
  345. while (++index < length) {
  346. accumulator = iteratee(accumulator, array[index], index, array);
  347. }
  348. return accumulator;
  349. }
  350.  
  351. /**
  352. * Converts an ASCII `string` to an array.
  353. *
  354. * @private
  355. * @param {string} string The string to convert.
  356. * @returns {Array} Returns the converted array.
  357. */
  358. function asciiToArray(string) {
  359. return string.split('');
  360. }
  361.  
  362. /**
  363. * Splits an ASCII `string` into an array of its words.
  364. *
  365. * @private
  366. * @param {string} The string to inspect.
  367. * @returns {Array} Returns the words of `string`.
  368. */
  369. function asciiWords(string) {
  370. return string.match(reAsciiWord) || [];
  371. }
  372.  
  373. /**
  374. * The base implementation of `_.propertyOf` without support for deep paths.
  375. *
  376. * @private
  377. * @param {Object} object The object to query.
  378. * @returns {Function} Returns the new accessor function.
  379. */
  380. function basePropertyOf(object) {
  381. return function (key) {
  382. return object == null ? undefined : object[key];
  383. };
  384. }
  385.  
  386. /**
  387. * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
  388. * letters to basic Latin letters.
  389. *
  390. * @private
  391. * @param {string} letter The matched letter to deburr.
  392. * @returns {string} Returns the deburred letter.
  393. */
  394. var deburrLetter = basePropertyOf(deburredLetters);
  395.  
  396. /**
  397. * Checks if `string` contains Unicode symbols.
  398. *
  399. * @private
  400. * @param {string} string The string to inspect.
  401. * @returns {boolean} Returns `true` if a symbol is found, else `false`.
  402. */
  403. function hasUnicode(string) {
  404. return reHasUnicode.test(string);
  405. }
  406.  
  407. /**
  408. * Checks if `string` contains a word composed of Unicode symbols.
  409. *
  410. * @private
  411. * @param {string} string The string to inspect.
  412. * @returns {boolean} Returns `true` if a word is found, else `false`.
  413. */
  414. function hasUnicodeWord(string) {
  415. return reHasUnicodeWord.test(string);
  416. }
  417.  
  418. /**
  419. * Converts `string` to an array.
  420. *
  421. * @private
  422. * @param {string} string The string to convert.
  423. * @returns {Array} Returns the converted array.
  424. */
  425. function stringToArray(string) {
  426. return hasUnicode(string)
  427. ? unicodeToArray(string)
  428. : asciiToArray(string);
  429. }
  430.  
  431. /**
  432. * Converts a Unicode `string` to an array.
  433. *
  434. * @private
  435. * @param {string} string The string to convert.
  436. * @returns {Array} Returns the converted array.
  437. */
  438. function unicodeToArray(string) {
  439. return string.match(reUnicode) || [];
  440. }
  441.  
  442. /**
  443. * Splits a Unicode `string` into an array of its words.
  444. *
  445. * @private
  446. * @param {string} The string to inspect.
  447. * @returns {Array} Returns the words of `string`.
  448. */
  449. function unicodeWords(string) {
  450. return string.match(reUnicodeWord) || [];
  451. }
  452.  
  453. /*--------------------------------------------------------------------------*/
  454.  
  455. /** Used for built-in method references. */
  456. var objectProto = Object.prototype;
  457.  
  458. /** Used to check objects for own properties. */
  459. var hasOwnProperty = objectProto.hasOwnProperty;
  460.  
  461. /**
  462. * Used to resolve the
  463. * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
  464. * of values.
  465. */
  466. var nativeObjectToString = objectProto.toString;
  467.  
  468. /** Built-in value references. */
  469. var Symbol = root.Symbol,
  470. symToStringTag = Symbol ? Symbol.toStringTag : undefined;
  471.  
  472. /** Used to lookup unminified function names. */
  473. var realNames = {};
  474.  
  475. /** Used to convert symbols to primitives and strings. */
  476. var symbolProto = Symbol ? Symbol.prototype : undefined,
  477. symbolToString = symbolProto ? symbolProto.toString : undefined;
  478.  
  479. /*------------------------------------------------------------------------*/
  480.  
  481. /**
  482. * Creates a `lodash` object which wraps `value` to enable implicit method
  483. * chain sequences. Methods that operate on and return arrays, collections,
  484. * and functions can be chained together. Methods that retrieve a single value
  485. * or may return a primitive value will automatically end the chain sequence
  486. * and return the unwrapped value. Otherwise, the value must be unwrapped
  487. * with `_#value`.
  488. *
  489. * Explicit chain sequences, which must be unwrapped with `_#value`, may be
  490. * enabled using `_.chain`.
  491. *
  492. * The execution of chained methods is lazy, that is, it's deferred until
  493. * `_#value` is implicitly or explicitly called.
  494. *
  495. * Lazy evaluation allows several methods to support shortcut fusion.
  496. * Shortcut fusion is an optimization to merge iteratee calls; this avoids
  497. * the creation of intermediate arrays and can greatly reduce the number of
  498. * iteratee executions. Sections of a chain sequence qualify for shortcut
  499. * fusion if the section is applied to an array and iteratees accept only
  500. * one argument. The heuristic for whether a section qualifies for shortcut
  501. * fusion is subject to change.
  502. *
  503. * Chaining is supported in custom builds as long as the `_#value` method is
  504. * directly or indirectly included in the build.
  505. *
  506. * In addition to lodash methods, wrappers have `Array` and `String` methods.
  507. *
  508. * The wrapper `Array` methods are:
  509. * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
  510. *
  511. * The wrapper `String` methods are:
  512. * `replace` and `split`
  513. *
  514. * The wrapper methods that support shortcut fusion are:
  515. * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
  516. * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
  517. * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
  518. *
  519. * The chainable wrapper methods are:
  520. * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
  521. * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
  522. * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
  523. * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
  524. * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
  525. * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
  526. * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
  527. * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
  528. * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
  529. * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
  530. * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
  531. * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
  532. * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
  533. * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
  534. * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
  535. * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
  536. * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
  537. * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
  538. * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
  539. * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
  540. * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
  541. * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
  542. * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
  543. * `zipObject`, `zipObjectDeep`, and `zipWith`
  544. *
  545. * The wrapper methods that are **not** chainable by default are:
  546. * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
  547. * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
  548. * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
  549. * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
  550. * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
  551. * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
  552. * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
  553. * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
  554. * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
  555. * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
  556. * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
  557. * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
  558. * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
  559. * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
  560. * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
  561. * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
  562. * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
  563. * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
  564. * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
  565. * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
  566. * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
  567. * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
  568. * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
  569. * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
  570. * `upperFirst`, `value`, and `words`
  571. *
  572. * @name _
  573. * @constructor
  574. * @category Seq
  575. * @param {*} value The value to wrap in a `lodash` instance.
  576. * @returns {Object} Returns the new `lodash` wrapper instance.
  577. * @example
  578. *
  579. * function square(n) {
  580. * return n * n;
  581. * }
  582. *
  583. * var wrapped = _([1, 2, 3]);
  584. *
  585. * // Returns an unwrapped value.
  586. * wrapped.reduce(_.add);
  587. * // => 6
  588. *
  589. * // Returns a wrapped value.
  590. * var squares = wrapped.map(square);
  591. *
  592. * _.isArray(squares);
  593. * // => false
  594. *
  595. * _.isArray(squares.value());
  596. * // => true
  597. */
  598. function lodash() {
  599. // No operation performed.
  600. }
  601.  
  602. /*------------------------------------------------------------------------*/
  603.  
  604. /**
  605. * The base implementation of `getTag` without fallbacks for buggy environments.
  606. *
  607. * @private
  608. * @param {*} value The value to query.
  609. * @returns {string} Returns the `toStringTag`.
  610. */
  611. function baseGetTag(value) {
  612. if (value == null) {
  613. return value === undefined ? undefinedTag : nullTag;
  614. }
  615. return (symToStringTag && symToStringTag in Object(value))
  616. ? getRawTag(value)
  617. : objectToString(value);
  618. }
  619.  
  620. /**
  621. * The base implementation of `_.slice` without an iteratee call guard.
  622. *
  623. * @private
  624. * @param {Array} array The array to slice.
  625. * @param {number} [start=0] The start position.
  626. * @param {number} [end=array.length] The end position.
  627. * @returns {Array} Returns the slice of `array`.
  628. */
  629. function baseSlice(array, start, end) {
  630. var index = -1,
  631. length = array.length;
  632.  
  633. if (start < 0) {
  634. start = -start > length ? 0 : (length + start);
  635. }
  636. end = end > length ? length : end;
  637. if (end < 0) {
  638. end += length;
  639. }
  640. length = start > end ? 0 : ((end - start) >>> 0);
  641. start >>>= 0;
  642.  
  643. var result = Array(length);
  644. while (++index < length) {
  645. result[index] = array[index + start];
  646. }
  647. return result;
  648. }
  649.  
  650. /**
  651. * The base implementation of `_.toString` which doesn't convert nullish
  652. * values to empty strings.
  653. *
  654. * @private
  655. * @param {*} value The value to process.
  656. * @returns {string} Returns the string.
  657. */
  658. function baseToString(value) {
  659. // Exit early for strings to avoid a performance hit in some environments.
  660. if (typeof value == 'string') {
  661. return value;
  662. }
  663. if (isArray(value)) {
  664. // Recursively convert values (susceptible to call stack limits).
  665. return arrayMap(value, baseToString) + '';
  666. }
  667. if (isSymbol(value)) {
  668. return symbolToString ? symbolToString.call(value) : '';
  669. }
  670. var result = (value + '');
  671. return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
  672. }
  673.  
  674. /**
  675. * Casts `array` to a slice if it's needed.
  676. *
  677. * @private
  678. * @param {Array} array The array to inspect.
  679. * @param {number} start The start position.
  680. * @param {number} [end=array.length] The end position.
  681. * @returns {Array} Returns the cast slice.
  682. */
  683. function castSlice(array, start, end) {
  684. var length = array.length;
  685. end = end === undefined ? length : end;
  686. return (!start && end >= length) ? array : baseSlice(array, start, end);
  687. }
  688.  
  689. /**
  690. * Creates a function like `_.lowerFirst`.
  691. *
  692. * @private
  693. * @param {string} methodName The name of the `String` case method to use.
  694. * @returns {Function} Returns the new case function.
  695. */
  696. function createCaseFirst(methodName) {
  697. return function (string) {
  698. string = toString(string);
  699.  
  700. var strSymbols = hasUnicode(string)
  701. ? stringToArray(string)
  702. : undefined;
  703.  
  704. var chr = strSymbols
  705. ? strSymbols[0]
  706. : string.charAt(0);
  707.  
  708. var trailing = strSymbols
  709. ? castSlice(strSymbols, 1).join('')
  710. : string.slice(1);
  711.  
  712. return chr[methodName]() + trailing;
  713. };
  714. }
  715.  
  716. /**
  717. * Creates a function like `_.camelCase`.
  718. *
  719. * @private
  720. * @param {Function} callback The function to combine each word.
  721. * @returns {Function} Returns the new compounder function.
  722. */
  723. function createCompounder(callback) {
  724. return function (string) {
  725. return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
  726. };
  727. }
  728.  
  729. /**
  730. * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
  731. *
  732. * @private
  733. * @param {*} value The value to query.
  734. * @returns {string} Returns the raw `toStringTag`.
  735. */
  736. function getRawTag(value) {
  737. var isOwn = hasOwnProperty.call(value, symToStringTag),
  738. tag = value[symToStringTag];
  739.  
  740. try {
  741. value[symToStringTag] = undefined;
  742. var unmasked = true;
  743. } catch (e) { }
  744.  
  745. var result = nativeObjectToString.call(value);
  746. if (unmasked) {
  747. if (isOwn) {
  748. value[symToStringTag] = tag;
  749. } else {
  750. delete value[symToStringTag];
  751. }
  752. }
  753. return result;
  754. }
  755.  
  756. /**
  757. * Converts `value` to a string using `Object.prototype.toString`.
  758. *
  759. * @private
  760. * @param {*} value The value to convert.
  761. * @returns {string} Returns the converted string.
  762. */
  763. function objectToString(value) {
  764. return nativeObjectToString.call(value);
  765. }
  766.  
  767. /*------------------------------------------------------------------------*/
  768.  
  769. /**
  770. * Checks if `value` is classified as an `Array` object.
  771. *
  772. * @static
  773. * @memberOf _
  774. * @since 0.1.0
  775. * @category Lang
  776. * @param {*} value The value to check.
  777. * @returns {boolean} Returns `true` if `value` is an array, else `false`.
  778. * @example
  779. *
  780. * _.isArray([1, 2, 3]);
  781. * // => true
  782. *
  783. * _.isArray(document.body.children);
  784. * // => false
  785. *
  786. * _.isArray('abc');
  787. * // => false
  788. *
  789. * _.isArray(_.noop);
  790. * // => false
  791. */
  792. var isArray = Array.isArray;
  793.  
  794. /**
  795. * Checks if `value` is object-like. A value is object-like if it's not `null`
  796. * and has a `typeof` result of "object".
  797. *
  798. * @static
  799. * @memberOf _
  800. * @since 4.0.0
  801. * @category Lang
  802. * @param {*} value The value to check.
  803. * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
  804. * @example
  805. *
  806. * _.isObjectLike({});
  807. * // => true
  808. *
  809. * _.isObjectLike([1, 2, 3]);
  810. * // => true
  811. *
  812. * _.isObjectLike(_.noop);
  813. * // => false
  814. *
  815. * _.isObjectLike(null);
  816. * // => false
  817. */
  818. function isObjectLike(value) {
  819. return value != null && typeof value == 'object';
  820. }
  821.  
  822. /**
  823. * Checks if `value` is classified as a `Symbol` primitive or object.
  824. *
  825. * @static
  826. * @memberOf _
  827. * @since 4.0.0
  828. * @category Lang
  829. * @param {*} value The value to check.
  830. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
  831. * @example
  832. *
  833. * _.isSymbol(Symbol.iterator);
  834. * // => true
  835. *
  836. * _.isSymbol('abc');
  837. * // => false
  838. */
  839. function isSymbol(value) {
  840. return typeof value == 'symbol' ||
  841. (isObjectLike(value) && baseGetTag(value) == symbolTag);
  842. }
  843.  
  844. /**
  845. * Converts `value` to a string. An empty string is returned for `null`
  846. * and `undefined` values. The sign of `-0` is preserved.
  847. *
  848. * @static
  849. * @memberOf _
  850. * @since 4.0.0
  851. * @category Lang
  852. * @param {*} value The value to convert.
  853. * @returns {string} Returns the converted string.
  854. * @example
  855. *
  856. * _.toString(null);
  857. * // => ''
  858. *
  859. * _.toString(-0);
  860. * // => '-0'
  861. *
  862. * _.toString([1, 2, 3]);
  863. * // => '1,2,3'
  864. */
  865. function toString(value) {
  866. return value == null ? '' : baseToString(value);
  867. }
  868.  
  869. /*------------------------------------------------------------------------*/
  870.  
  871. /**
  872. * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
  873. *
  874. * @static
  875. * @memberOf _
  876. * @since 3.0.0
  877. * @category String
  878. * @param {string} [string=''] The string to convert.
  879. * @returns {string} Returns the camel cased string.
  880. * @example
  881. *
  882. * _.camelCase('Foo Bar');
  883. * // => 'fooBar'
  884. *
  885. * _.camelCase('--foo-bar--');
  886. * // => 'fooBar'
  887. *
  888. * _.camelCase('__FOO_BAR__');
  889. * // => 'fooBar'
  890. */
  891. var camelCase = createCompounder(function (result, word, index) {
  892. word = word.toLowerCase();
  893. return result + (index ? capitalize(word) : word);
  894. });
  895.  
  896. /**
  897. * Converts the first character of `string` to upper case and the remaining
  898. * to lower case.
  899. *
  900. * @static
  901. * @memberOf _
  902. * @since 3.0.0
  903. * @category String
  904. * @param {string} [string=''] The string to capitalize.
  905. * @returns {string} Returns the capitalized string.
  906. * @example
  907. *
  908. * _.capitalize('FRED');
  909. * // => 'Fred'
  910. */
  911. function capitalize(string) {
  912. return upperFirst(toString(string).toLowerCase());
  913. }
  914.  
  915. /**
  916. * Deburrs `string` by converting
  917. * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
  918. * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
  919. * letters to basic Latin letters and removing
  920. * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
  921. *
  922. * @static
  923. * @memberOf _
  924. * @since 3.0.0
  925. * @category String
  926. * @param {string} [string=''] The string to deburr.
  927. * @returns {string} Returns the deburred string.
  928. * @example
  929. *
  930. * _.deburr('déjà vu');
  931. * // => 'deja vu'
  932. */
  933. function deburr(string) {
  934. string = toString(string);
  935. return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
  936. }
  937.  
  938. /**
  939. * Converts `string` to
  940. * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
  941. *
  942. * @static
  943. * @memberOf _
  944. * @since 3.0.0
  945. * @category String
  946. * @param {string} [string=''] The string to convert.
  947. * @returns {string} Returns the kebab cased string.
  948. * @example
  949. *
  950. * _.kebabCase('Foo Bar');
  951. * // => 'foo-bar'
  952. *
  953. * _.kebabCase('fooBar');
  954. * // => 'foo-bar'
  955. *
  956. * _.kebabCase('__FOO_BAR__');
  957. * // => 'foo-bar'
  958. */
  959. var kebabCase = createCompounder(function (result, word, index) {
  960. return result + (index ? '-' : '') + word.toLowerCase();
  961. });
  962.  
  963. /**
  964. * Converts `string` to
  965. * [snake case](https://en.wikipedia.org/wiki/Snake_case).
  966. *
  967. * @static
  968. * @memberOf _
  969. * @since 3.0.0
  970. * @category String
  971. * @param {string} [string=''] The string to convert.
  972. * @returns {string} Returns the snake cased string.
  973. * @example
  974. *
  975. * _.snakeCase('Foo Bar');
  976. * // => 'foo_bar'
  977. *
  978. * _.snakeCase('fooBar');
  979. * // => 'foo_bar'
  980. *
  981. * _.snakeCase('--FOO-BAR--');
  982. * // => 'foo_bar'
  983. */
  984. var snakeCase = createCompounder(function (result, word, index) {
  985. return result + (index ? '_' : '') + word.toLowerCase();
  986. });
  987.  
  988. /**
  989. * Converts the first character of `string` to upper case.
  990. *
  991. * @static
  992. * @memberOf _
  993. * @since 4.0.0
  994. * @category String
  995. * @param {string} [string=''] The string to convert.
  996. * @returns {string} Returns the converted string.
  997. * @example
  998. *
  999. * _.upperFirst('fred');
  1000. * // => 'Fred'
  1001. *
  1002. * _.upperFirst('FRED');
  1003. * // => 'FRED'
  1004. */
  1005. var upperFirst = createCaseFirst('toUpperCase');
  1006.  
  1007. /**
  1008. * Splits `string` into an array of its words.
  1009. *
  1010. * @static
  1011. * @memberOf _
  1012. * @since 3.0.0
  1013. * @category String
  1014. * @param {string} [string=''] The string to inspect.
  1015. * @param {RegExp|string} [pattern] The pattern to match words.
  1016. * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
  1017. * @returns {Array} Returns the words of `string`.
  1018. * @example
  1019. *
  1020. * _.words('fred, barney, & pebbles');
  1021. * // => ['fred', 'barney', 'pebbles']
  1022. *
  1023. * _.words('fred, barney, & pebbles', /[^, ]+/g);
  1024. * // => ['fred', 'barney', '&', 'pebbles']
  1025. */
  1026. function words(string, pattern, guard) {
  1027. string = toString(string);
  1028. pattern = guard ? undefined : pattern;
  1029.  
  1030. if (pattern === undefined) {
  1031. return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
  1032. }
  1033. return string.match(pattern) || [];
  1034. }
  1035.  
  1036. /*------------------------------------------------------------------------*/
  1037.  
  1038. // Add methods that return wrapped values in chain sequences.
  1039. lodash.words = words;
  1040.  
  1041. /*------------------------------------------------------------------------*/
  1042.  
  1043. // Add methods that return unwrapped values in chain sequences.
  1044. lodash.camelCase = camelCase;
  1045. lodash.capitalize = capitalize;
  1046. lodash.deburr = deburr;
  1047. lodash.isArray = isArray;
  1048. lodash.isObjectLike = isObjectLike;
  1049. lodash.isSymbol = isSymbol;
  1050. lodash.kebabCase = kebabCase;
  1051. lodash.snakeCase = snakeCase;
  1052. lodash.toString = toString;
  1053. lodash.upperFirst = upperFirst;
  1054.  
  1055. /*------------------------------------------------------------------------*/
  1056.  
  1057. /**
  1058. * The semantic version number.
  1059. *
  1060. * @static
  1061. * @memberOf _
  1062. * @type {string}
  1063. */
  1064. lodash.VERSION = VERSION;
  1065.  
  1066. /*--------------------------------------------------------------------------*/
  1067.  
  1068. // Some AMD build optimizers, like r.js, check for condition patterns like:
  1069. if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
  1070. // Expose Lodash on the global object to prevent errors when Lodash is
  1071. // loaded by a script tag in the presence of an AMD loader.
  1072. // See http://requirejs.org/docs/errors.html#mismatch for more details.
  1073. // Use `_.noConflict` to remove Lodash from the global object.
  1074. root._ = lodash;
  1075.  
  1076. // Define as an anonymous module so, through path mapping, it can be
  1077. // referenced as the "underscore" module.
  1078. define(function () {
  1079. return lodash;
  1080. });
  1081. }
  1082. // Check for `exports` after `define` in case a build optimizer adds it.
  1083. else if (freeModule) {
  1084. // Export for Node.js.
  1085. (freeModule.exports = lodash)._ = lodash;
  1086. // Export for CommonJS support.
  1087. freeExports._ = lodash;
  1088. }
  1089. else {
  1090. // Export to the global object.
  1091. root._ = lodash;
  1092. }
  1093. }.call(this));
  1094.  
  1095. (function () {
  1096. main();
  1097. })();