41674e8ab6e1a59b09e24efc6a1503139f9f6db424025e4c0e87b531bb50f5321ec1f5ab4d0d7182f817f458c49442c342d435417b2478fa3aaaa9f2ee5455 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import * as dom from '../../dom.js';
  6. import { CaseSensitiveToggle, RegexToggle, WholeWordsToggle } from './findInputToggles.js';
  7. import { HistoryInputBox } from '../inputbox/inputBox.js';
  8. import { Widget } from '../widget.js';
  9. import { Emitter } from '../../../common/event.js';
  10. import './findInput.css';
  11. import * as nls from '../../../../nls.js';
  12. const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input");
  13. export class FindInput extends Widget {
  14. constructor(parent, contextViewProvider, _showOptionButtons, options) {
  15. var _a;
  16. super();
  17. this._showOptionButtons = _showOptionButtons;
  18. this.fixFocusOnOptionClickEnabled = true;
  19. this.imeSessionInProgress = false;
  20. this.additionalToggles = [];
  21. this._onDidOptionChange = this._register(new Emitter());
  22. this.onDidOptionChange = this._onDidOptionChange.event;
  23. this._onKeyDown = this._register(new Emitter());
  24. this.onKeyDown = this._onKeyDown.event;
  25. this._onMouseDown = this._register(new Emitter());
  26. this.onMouseDown = this._onMouseDown.event;
  27. this._onInput = this._register(new Emitter());
  28. this._onKeyUp = this._register(new Emitter());
  29. this._onCaseSensitiveKeyDown = this._register(new Emitter());
  30. this.onCaseSensitiveKeyDown = this._onCaseSensitiveKeyDown.event;
  31. this._onRegexKeyDown = this._register(new Emitter());
  32. this.onRegexKeyDown = this._onRegexKeyDown.event;
  33. this._lastHighlightFindOptions = 0;
  34. this.contextViewProvider = contextViewProvider;
  35. this.placeholder = options.placeholder || '';
  36. this.validation = options.validation;
  37. this.label = options.label || NLS_DEFAULT_LABEL;
  38. this.inputActiveOptionBorder = options.inputActiveOptionBorder;
  39. this.inputActiveOptionForeground = options.inputActiveOptionForeground;
  40. this.inputActiveOptionBackground = options.inputActiveOptionBackground;
  41. this.inputBackground = options.inputBackground;
  42. this.inputForeground = options.inputForeground;
  43. this.inputBorder = options.inputBorder;
  44. this.inputValidationInfoBorder = options.inputValidationInfoBorder;
  45. this.inputValidationInfoBackground = options.inputValidationInfoBackground;
  46. this.inputValidationInfoForeground = options.inputValidationInfoForeground;
  47. this.inputValidationWarningBorder = options.inputValidationWarningBorder;
  48. this.inputValidationWarningBackground = options.inputValidationWarningBackground;
  49. this.inputValidationWarningForeground = options.inputValidationWarningForeground;
  50. this.inputValidationErrorBorder = options.inputValidationErrorBorder;
  51. this.inputValidationErrorBackground = options.inputValidationErrorBackground;
  52. this.inputValidationErrorForeground = options.inputValidationErrorForeground;
  53. const appendCaseSensitiveLabel = options.appendCaseSensitiveLabel || '';
  54. const appendWholeWordsLabel = options.appendWholeWordsLabel || '';
  55. const appendRegexLabel = options.appendRegexLabel || '';
  56. const history = options.history || [];
  57. const flexibleHeight = !!options.flexibleHeight;
  58. const flexibleWidth = !!options.flexibleWidth;
  59. const flexibleMaxHeight = options.flexibleMaxHeight;
  60. this.domNode = document.createElement('div');
  61. this.domNode.classList.add('monaco-findInput');
  62. this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
  63. placeholder: this.placeholder || '',
  64. ariaLabel: this.label || '',
  65. validationOptions: {
  66. validation: this.validation
  67. },
  68. inputBackground: this.inputBackground,
  69. inputForeground: this.inputForeground,
  70. inputBorder: this.inputBorder,
  71. inputValidationInfoBackground: this.inputValidationInfoBackground,
  72. inputValidationInfoForeground: this.inputValidationInfoForeground,
  73. inputValidationInfoBorder: this.inputValidationInfoBorder,
  74. inputValidationWarningBackground: this.inputValidationWarningBackground,
  75. inputValidationWarningForeground: this.inputValidationWarningForeground,
  76. inputValidationWarningBorder: this.inputValidationWarningBorder,
  77. inputValidationErrorBackground: this.inputValidationErrorBackground,
  78. inputValidationErrorForeground: this.inputValidationErrorForeground,
  79. inputValidationErrorBorder: this.inputValidationErrorBorder,
  80. history,
  81. showHistoryHint: options.showHistoryHint,
  82. flexibleHeight,
  83. flexibleWidth,
  84. flexibleMaxHeight
  85. }));
  86. this.regex = this._register(new RegexToggle({
  87. appendTitle: appendRegexLabel,
  88. isChecked: false,
  89. inputActiveOptionBorder: this.inputActiveOptionBorder,
  90. inputActiveOptionForeground: this.inputActiveOptionForeground,
  91. inputActiveOptionBackground: this.inputActiveOptionBackground
  92. }));
  93. this._register(this.regex.onChange(viaKeyboard => {
  94. this._onDidOptionChange.fire(viaKeyboard);
  95. if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
  96. this.inputBox.focus();
  97. }
  98. this.validate();
  99. }));
  100. this._register(this.regex.onKeyDown(e => {
  101. this._onRegexKeyDown.fire(e);
  102. }));
  103. this.wholeWords = this._register(new WholeWordsToggle({
  104. appendTitle: appendWholeWordsLabel,
  105. isChecked: false,
  106. inputActiveOptionBorder: this.inputActiveOptionBorder,
  107. inputActiveOptionForeground: this.inputActiveOptionForeground,
  108. inputActiveOptionBackground: this.inputActiveOptionBackground
  109. }));
  110. this._register(this.wholeWords.onChange(viaKeyboard => {
  111. this._onDidOptionChange.fire(viaKeyboard);
  112. if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
  113. this.inputBox.focus();
  114. }
  115. this.validate();
  116. }));
  117. this.caseSensitive = this._register(new CaseSensitiveToggle({
  118. appendTitle: appendCaseSensitiveLabel,
  119. isChecked: false,
  120. inputActiveOptionBorder: this.inputActiveOptionBorder,
  121. inputActiveOptionForeground: this.inputActiveOptionForeground,
  122. inputActiveOptionBackground: this.inputActiveOptionBackground
  123. }));
  124. this._register(this.caseSensitive.onChange(viaKeyboard => {
  125. this._onDidOptionChange.fire(viaKeyboard);
  126. if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
  127. this.inputBox.focus();
  128. }
  129. this.validate();
  130. }));
  131. this._register(this.caseSensitive.onKeyDown(e => {
  132. this._onCaseSensitiveKeyDown.fire(e);
  133. }));
  134. // Arrow-Key support to navigate between options
  135. const indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode];
  136. this.onkeydown(this.domNode, (event) => {
  137. if (event.equals(15 /* KeyCode.LeftArrow */) || event.equals(17 /* KeyCode.RightArrow */) || event.equals(9 /* KeyCode.Escape */)) {
  138. const index = indexes.indexOf(document.activeElement);
  139. if (index >= 0) {
  140. let newIndex = -1;
  141. if (event.equals(17 /* KeyCode.RightArrow */)) {
  142. newIndex = (index + 1) % indexes.length;
  143. }
  144. else if (event.equals(15 /* KeyCode.LeftArrow */)) {
  145. if (index === 0) {
  146. newIndex = indexes.length - 1;
  147. }
  148. else {
  149. newIndex = index - 1;
  150. }
  151. }
  152. if (event.equals(9 /* KeyCode.Escape */)) {
  153. indexes[index].blur();
  154. this.inputBox.focus();
  155. }
  156. else if (newIndex >= 0) {
  157. indexes[newIndex].focus();
  158. }
  159. dom.EventHelper.stop(event, true);
  160. }
  161. }
  162. });
  163. this.controls = document.createElement('div');
  164. this.controls.className = 'controls';
  165. this.controls.style.display = this._showOptionButtons ? 'block' : 'none';
  166. this.controls.appendChild(this.caseSensitive.domNode);
  167. this.controls.appendChild(this.wholeWords.domNode);
  168. this.controls.appendChild(this.regex.domNode);
  169. if (!this._showOptionButtons) {
  170. this.caseSensitive.domNode.style.display = 'none';
  171. this.wholeWords.domNode.style.display = 'none';
  172. this.regex.domNode.style.display = 'none';
  173. }
  174. for (const toggle of (_a = options === null || options === void 0 ? void 0 : options.additionalToggles) !== null && _a !== void 0 ? _a : []) {
  175. this._register(toggle);
  176. this.controls.appendChild(toggle.domNode);
  177. this._register(toggle.onChange(viaKeyboard => {
  178. this._onDidOptionChange.fire(viaKeyboard);
  179. if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
  180. this.inputBox.focus();
  181. }
  182. }));
  183. this.additionalToggles.push(toggle);
  184. }
  185. if (this.additionalToggles.length > 0) {
  186. this.controls.style.display = 'block';
  187. }
  188. this.inputBox.paddingRight =
  189. (this._showOptionButtons ? this.caseSensitive.width() + this.wholeWords.width() + this.regex.width() : 0)
  190. + this.additionalToggles.reduce((r, t) => r + t.width(), 0);
  191. this.domNode.appendChild(this.controls);
  192. parent === null || parent === void 0 ? void 0 : parent.appendChild(this.domNode);
  193. this._register(dom.addDisposableListener(this.inputBox.inputElement, 'compositionstart', (e) => {
  194. this.imeSessionInProgress = true;
  195. }));
  196. this._register(dom.addDisposableListener(this.inputBox.inputElement, 'compositionend', (e) => {
  197. this.imeSessionInProgress = false;
  198. this._onInput.fire();
  199. }));
  200. this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
  201. this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
  202. this.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());
  203. this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
  204. }
  205. get onDidChange() {
  206. return this.inputBox.onDidChange;
  207. }
  208. enable() {
  209. this.domNode.classList.remove('disabled');
  210. this.inputBox.enable();
  211. this.regex.enable();
  212. this.wholeWords.enable();
  213. this.caseSensitive.enable();
  214. for (const toggle of this.additionalToggles) {
  215. toggle.enable();
  216. }
  217. }
  218. disable() {
  219. this.domNode.classList.add('disabled');
  220. this.inputBox.disable();
  221. this.regex.disable();
  222. this.wholeWords.disable();
  223. this.caseSensitive.disable();
  224. for (const toggle of this.additionalToggles) {
  225. toggle.disable();
  226. }
  227. }
  228. setFocusInputOnOptionClick(value) {
  229. this.fixFocusOnOptionClickEnabled = value;
  230. }
  231. setEnabled(enabled) {
  232. if (enabled) {
  233. this.enable();
  234. }
  235. else {
  236. this.disable();
  237. }
  238. }
  239. getValue() {
  240. return this.inputBox.value;
  241. }
  242. setValue(value) {
  243. if (this.inputBox.value !== value) {
  244. this.inputBox.value = value;
  245. }
  246. }
  247. style(styles) {
  248. this.inputActiveOptionBorder = styles.inputActiveOptionBorder;
  249. this.inputActiveOptionForeground = styles.inputActiveOptionForeground;
  250. this.inputActiveOptionBackground = styles.inputActiveOptionBackground;
  251. this.inputBackground = styles.inputBackground;
  252. this.inputForeground = styles.inputForeground;
  253. this.inputBorder = styles.inputBorder;
  254. this.inputValidationInfoBackground = styles.inputValidationInfoBackground;
  255. this.inputValidationInfoForeground = styles.inputValidationInfoForeground;
  256. this.inputValidationInfoBorder = styles.inputValidationInfoBorder;
  257. this.inputValidationWarningBackground = styles.inputValidationWarningBackground;
  258. this.inputValidationWarningForeground = styles.inputValidationWarningForeground;
  259. this.inputValidationWarningBorder = styles.inputValidationWarningBorder;
  260. this.inputValidationErrorBackground = styles.inputValidationErrorBackground;
  261. this.inputValidationErrorForeground = styles.inputValidationErrorForeground;
  262. this.inputValidationErrorBorder = styles.inputValidationErrorBorder;
  263. this.applyStyles();
  264. }
  265. applyStyles() {
  266. if (this.domNode) {
  267. const toggleStyles = {
  268. inputActiveOptionBorder: this.inputActiveOptionBorder,
  269. inputActiveOptionForeground: this.inputActiveOptionForeground,
  270. inputActiveOptionBackground: this.inputActiveOptionBackground,
  271. };
  272. this.regex.style(toggleStyles);
  273. this.wholeWords.style(toggleStyles);
  274. this.caseSensitive.style(toggleStyles);
  275. for (const toggle of this.additionalToggles) {
  276. toggle.style(toggleStyles);
  277. }
  278. const inputBoxStyles = {
  279. inputBackground: this.inputBackground,
  280. inputForeground: this.inputForeground,
  281. inputBorder: this.inputBorder,
  282. inputValidationInfoBackground: this.inputValidationInfoBackground,
  283. inputValidationInfoForeground: this.inputValidationInfoForeground,
  284. inputValidationInfoBorder: this.inputValidationInfoBorder,
  285. inputValidationWarningBackground: this.inputValidationWarningBackground,
  286. inputValidationWarningForeground: this.inputValidationWarningForeground,
  287. inputValidationWarningBorder: this.inputValidationWarningBorder,
  288. inputValidationErrorBackground: this.inputValidationErrorBackground,
  289. inputValidationErrorForeground: this.inputValidationErrorForeground,
  290. inputValidationErrorBorder: this.inputValidationErrorBorder
  291. };
  292. this.inputBox.style(inputBoxStyles);
  293. }
  294. }
  295. select() {
  296. this.inputBox.select();
  297. }
  298. focus() {
  299. this.inputBox.focus();
  300. }
  301. getCaseSensitive() {
  302. return this.caseSensitive.checked;
  303. }
  304. setCaseSensitive(value) {
  305. this.caseSensitive.checked = value;
  306. }
  307. getWholeWords() {
  308. return this.wholeWords.checked;
  309. }
  310. setWholeWords(value) {
  311. this.wholeWords.checked = value;
  312. }
  313. getRegex() {
  314. return this.regex.checked;
  315. }
  316. setRegex(value) {
  317. this.regex.checked = value;
  318. this.validate();
  319. }
  320. focusOnCaseSensitive() {
  321. this.caseSensitive.focus();
  322. }
  323. highlightFindOptions() {
  324. this.domNode.classList.remove('highlight-' + (this._lastHighlightFindOptions));
  325. this._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;
  326. this.domNode.classList.add('highlight-' + (this._lastHighlightFindOptions));
  327. }
  328. validate() {
  329. this.inputBox.validate();
  330. }
  331. showMessage(message) {
  332. this.inputBox.showMessage(message);
  333. }
  334. clearMessage() {
  335. this.inputBox.hideMessage();
  336. }
  337. }