From 5a1a26b43859345c9773b647231b2f7fe47d1aea Mon Sep 17 00:00:00 2001 From: Pluto Date: Wed, 9 Jul 2025 23:03:05 +0530 Subject: [PATCH 01/43] fix: profile button text not centralized --- src/services/profile-menu.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/profile-menu.js b/src/services/profile-menu.js index 517fd9a356..7d8444ed49 100644 --- a/src/services/profile-menu.js +++ b/src/services/profile-menu.js @@ -13,9 +13,9 @@ define(function (require, exports, module) { function _createSVGIcon(initials, bgColor) { return ` - - - ${initials} + + + ${initials} `; } From 4252e7628620783ebc2d4d8aeefb8e9a78d84ab4 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 00:04:57 +0530 Subject: [PATCH 02/43] feat: add cancel button in add snippet panel --- .../CustomSnippets/htmlContent/snippets-panel.html | 5 +++-- src/extensionsIntegrated/CustomSnippets/main.js | 6 ++++++ src/styles/Extn-CustomSnippets.less | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html index 67d85ead76..8c7abf6b98 100644 --- a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html +++ b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html @@ -111,8 +111,9 @@ -
- +
+ +
diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index e27d9d39a5..8c2cdcc2e2 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -122,6 +122,7 @@ define(function (require, exports, module) { function _registerHandlers() { const $closePanelBtn = $("#close-custom-snippets-panel-btn"); const $saveCustomSnippetBtn = $("#save-custom-snippet-btn"); + const $cancelCustomSnippetBtn = $("#cancel-custom-snippet-btn"); const $abbrInput = $("#abbr-box"); const $descInput = $("#desc-box"); const $templateInput = $("#template-text-box"); @@ -159,6 +160,11 @@ define(function (require, exports, module) { Driver.handleSaveBtnClick(); }); + $cancelCustomSnippetBtn.on("click", function () { + UIHelper.showSnippetListMenu(); + SnippetsList.showSnippetsList(); + }); + $abbrInput.on("input", Helper.toggleSaveButtonDisability); $templateInput.on("input", Helper.toggleSaveButtonDisability); diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index ffff63c228..020e37fe6f 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -534,11 +534,14 @@ } } - #save-custom-snippet-btn { + #add-custom-snippet-panel-buttons { margin-top: 8px; padding-top: 8px; border-top: 1px solid @bc-panel-separator; text-align: right; + display: flex; + gap: 10px; + justify-content: flex-end; .dark & { border-top: 1px solid @dark-bc-panel-separator; From ae7dbc43cc79ab194b14cf7c2cdc6cb1fce031a2 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 00:08:33 +0530 Subject: [PATCH 03/43] fix: save button always remain disabled --- src/extensionsIntegrated/CustomSnippets/helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 3eebe8bdaa..21644aa614 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -128,7 +128,7 @@ define(function (require, exports, module) { const $abbrInput = $("#abbr-box"); const $templateInput = $("#template-text-box"); - const $saveBtn = $("#save-custom-snippet-btn button"); + const $saveBtn = $("#save-custom-snippet-btn"); // make sure that the required fields has some value const hasAbbr = $abbrInput.val().trim().length > 0; From 4004cfd9d2e192aa718171157f0b26befe9c90c5 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 11:35:17 +0530 Subject: [PATCH 04/43] feat: auto update API docs --- docs/API-Reference/editor/CodeHintManager.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/API-Reference/editor/CodeHintManager.md b/docs/API-Reference/editor/CodeHintManager.md index 986b86748c..653b60d6a4 100644 --- a/docs/API-Reference/editor/CodeHintManager.md +++ b/docs/API-Reference/editor/CodeHintManager.md @@ -227,6 +227,8 @@ insertHintOnTab Preference. * [.registerHintProvider(provider, languageIds, priority)](#module_CodeHintManager..registerHintProvider) * [.hasValidExclusion(exclusion, textAfterCursor)](#module_CodeHintManager..hasValidExclusion) ⇒ boolean * [.isOpen()](#module_CodeHintManager..isOpen) ⇒ boolean + * [.showHintsAtTop(handler)](#module_CodeHintManager..showHintsAtTop) + * [.clearHintsAtTop()](#module_CodeHintManager..clearHintsAtTop) @@ -263,3 +265,21 @@ Test if a hint popup is open. **Kind**: inner method of [CodeHintManager](#module_CodeHintManager) **Returns**: boolean - - true if the hints are open, false otherwise. + + +### CodeHintManager.showHintsAtTop(handler) +Register a handler to show hints at the top of the hint list. +This API allows extensions to add their own hints at the top of the standard hint list. + +**Kind**: inner method of [CodeHintManager](#module_CodeHintManager) + +| Param | Type | Description | +| --- | --- | --- | +| handler | Object | A hint provider object with standard methods: - hasHints: function(editor, implicitChar) - returns true if hints are available - getHints: function(editor, implicitChar) - returns hint response object with hints array - insertHint: function(hint) - handles hint insertion, returns true if handled | + + + +### CodeHintManager.clearHintsAtTop() +Unregister the hints at top handler. + +**Kind**: inner method of [CodeHintManager](#module_CodeHintManager) From e5d2653d345912d7f4163f720339f644575d6ccb Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 12:10:28 +0530 Subject: [PATCH 05/43] fix: increase panel min size so that the save, cancel buttons are always visible --- src/extensionsIntegrated/CustomSnippets/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index 8c2cdcc2e2..caa7fa9e8c 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -41,7 +41,7 @@ define(function (require, exports, module) { const MY_COMMAND_ID = "custom_snippets"; const PANEL_ID = "customSnippets.panel"; const MENU_ITEM_NAME = "Custom Snippets..."; // this name will appear as the menu item - const PANEL_MIN_SIZE = 100; // the minimum size more than which its height cannot be decreased + const PANEL_MIN_SIZE = 340; // the minimum size more than which its height cannot be decreased // this is to store the panel reference, // as we only need to create this once. rest of the time we can just toggle the visibility of the panel From 078502c5af0f54663408e5196e55003ea09b8646 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 12:24:56 +0530 Subject: [PATCH 06/43] fix: update text in the no snippets present panel --- .../CustomSnippets/snippetsList.js | 2 +- src/styles/Extn-CustomSnippets.less | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsList.js b/src/extensionsIntegrated/CustomSnippets/snippetsList.js index b69bd99147..a8b6b94b2e 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsList.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsList.js @@ -104,7 +104,7 @@ define(function (require, exports, module) { if (filterText) { $emptyMessage.text(`No snippets match "${filterText}"`); } else { - $emptyMessage.text("No custom snippets added yet!"); + $emptyMessage.html('Add your own code hints to speed up coding - Learn More'); } } diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 020e37fe6f..17c8c39bcd 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -331,6 +331,19 @@ .dark & { color: @dark-bc-text-thin; } + + a { + color: @bc-btn-border-focused; + text-decoration: none; + + &:hover { + text-decoration: underline; + } + + .dark & { + color: @dark-bc-btn-border-focused; + } + } } #add-snippet-btn button { From f4db68f679c32b277743698cce3743577aad56d2 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 13:38:11 +0530 Subject: [PATCH 07/43] fix: back button text not properly centralized --- .../htmlContent/snippets-panel.html | 3 ++- src/styles/Extn-CustomSnippets.less | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html index 8c7abf6b98..df81357650 100644 --- a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html +++ b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html @@ -9,7 +9,8 @@ diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 17c8c39bcd..30ee0df886 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -72,6 +72,22 @@ } } +.custom-snippet-btn button { + display: flex; + align-items: center; +} + +.custom-snippet-btn .back-btn-left-icon { + position: relative; + top: 1px; + margin-right: 4px; +} + +.custom-snippet-btn .back-btn-text { + position: relative; + top: 0.6px; +} + .filter-snippets-panel { display: inline-block; } From 4236acd9608f6b7499e0e38ec23edf077e391fe1 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 13:58:15 +0530 Subject: [PATCH 08/43] feat: add check state on menu item when panel is open --- src/extensionsIntegrated/CustomSnippets/main.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index caa7fa9e8c..2b37b7ca46 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -72,8 +72,10 @@ define(function (require, exports, module) { function _togglePanelVisibility() { if (customSnippetsPanel.isVisible()) { customSnippetsPanel.hide(); + CommandManager.get(MY_COMMAND_ID).setChecked(false); } else { customSnippetsPanel.show(); + CommandManager.get(MY_COMMAND_ID).setChecked(true); $("#filter-snippets-input").val(""); UIHelper.initializeListViewToolbarTitle(); @@ -89,6 +91,7 @@ define(function (require, exports, module) { */ function _hidePanel() { customSnippetsPanel.hide(); + CommandManager.get(MY_COMMAND_ID).setChecked(false); } /** @@ -101,6 +104,7 @@ define(function (require, exports, module) { // if it is then we can just toggle its visibility if (!customSnippetsPanel) { _createPanel(); + CommandManager.get(MY_COMMAND_ID).setChecked(true); } else { _togglePanelVisibility(); } From f985b8b42d07cf316d68395615f78106bec3ab06 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 16:00:53 +0530 Subject: [PATCH 09/43] fix: alignment of plus icon in the add snippet button --- src/styles/Extn-CustomSnippets.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 30ee0df886..f5be4b5417 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -88,6 +88,11 @@ top: 0.6px; } +.custom-snippet-btn .fa-plus { + position: relative; + top: 0.6px; +} + .filter-snippets-panel { display: inline-block; } From c619e32273173804572a078102b4c43029a5cee2 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 16:04:13 +0530 Subject: [PATCH 10/43] fix: back button alignment --- src/styles/Extn-CustomSnippets.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index f5be4b5417..f042c8d50c 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -79,7 +79,7 @@ .custom-snippet-btn .back-btn-left-icon { position: relative; - top: 1px; + top: 0.6px; margin-right: 4px; } From 1ff336d98b17ab3955535b319339df5e74e4db3a Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 16:27:57 +0530 Subject: [PATCH 11/43] fix: move the content a bit right to maintain hierarchy structure --- src/styles/Extn-CustomSnippets.less | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index f042c8d50c..b1cd6581fc 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -403,7 +403,7 @@ color: @bc-text-thin-quiet; font-size: 12px; font-style: italic; - margin-left: 132px; + margin-left: 144px; padding: 0; background: none; border: none; @@ -460,6 +460,8 @@ display: flex; align-items: flex-start; margin-bottom: 8px; + margin-left: 12px; + margin-right: 8px; gap: 4px; flex-direction: column; @@ -570,6 +572,8 @@ #add-custom-snippet-panel-buttons { margin-top: 8px; + margin-left: 12px; + margin-right: 8px; padding-top: 8px; border-top: 1px solid @bc-panel-separator; text-align: right; @@ -612,6 +616,8 @@ display: flex; align-items: flex-start; margin-bottom: 8px; + margin-left: 12px; + margin-right: 8px; gap: 4px; flex-direction: column; @@ -722,6 +728,8 @@ #edit-snippet-buttons { margin-top: 8px; + margin-left: 12px; + margin-right: 8px; padding-top: 8px; border-top: 1px solid @bc-panel-separator; text-align: right; @@ -789,6 +797,9 @@ #custom-snippets-add-new, #custom-snippets-edit { .field-wrapper { + margin-left: 8px; + margin-right: 4px; + .field-row { flex-direction: column; align-items: stretch; @@ -799,10 +810,16 @@ } } } + + #add-custom-snippet-panel-buttons, + #edit-snippet-buttons { + margin-left: 8px; + margin-right: 4px; + } } .error-message { - margin-left: 0; + margin-left: 8px; } } @@ -819,6 +836,14 @@ .field-wrapper { margin-bottom: 6px; + margin-left: 6px; + margin-right: 3px; + } + + #add-custom-snippet-panel-buttons, + #edit-snippet-buttons { + margin-left: 6px; + margin-right: 3px; } } } From e7d59a36491b5a5692476e7df1f568972aa49040 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 17:00:20 +0530 Subject: [PATCH 12/43] fix: made close button styling consistent to other panels close button --- .../htmlContent/snippets-panel.html | 4 +--- src/styles/Extn-CustomSnippets.less | 22 +++++-------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html index df81357650..fd4c253f59 100644 --- a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html +++ b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html @@ -18,9 +18,7 @@
-
- -
+ × diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index b1cd6581fc..340c703de4 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -93,6 +93,10 @@ top: 0.6px; } +#custom-snippets-panel .close { + padding-top: 2.5px; +} + .filter-snippets-panel { display: inline-block; } @@ -107,23 +111,7 @@ min-width: 120px; margin-bottom: 0; margin-top: -4px; -} - -#close-custom-snippets-panel-btn button { - background: transparent; - border: none; - outline: none; - font-size: 13px; - opacity: 0.7; - color: @bc-text; - - .dark & { - color: @dark-bc-text; - } - - &:hover { - opacity: 0.9; - } + margin-right: 30px; } #custom-snippets-list.hidden { From a5932f5ad0bc99f4fd18f6081d78be6a1807e150 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 17:04:39 +0530 Subject: [PATCH 13/43] fix: make filter input consistent to other panels filter input --- src/styles/Extn-CustomSnippets.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 340c703de4..93241fc009 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -107,7 +107,6 @@ .filter-snippets-panel #filter-snippets-input { height: 14px; - width: 180px; min-width: 120px; margin-bottom: 0; margin-top: -4px; From 5ad4a125b19e1325f208a6b1cad7e249726269f7 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 17:19:35 +0530 Subject: [PATCH 14/43] fix: set min width to the template textare to keep it consistent to other input fields --- src/styles/Extn-CustomSnippets.less | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 93241fc009..99da153d4a 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -545,6 +545,7 @@ textarea { min-height: 80px; max-height: 120px; + min-width: 156px; resize: none; line-height: 1.4; white-space: pre-wrap; @@ -701,6 +702,7 @@ textarea { min-height: 80px; max-height: 120px; + min-width: 156px; resize: none; line-height: 1.4; white-space: pre-wrap; @@ -779,6 +781,15 @@ min-width: auto; } } + + #custom-snippets-add-new, + #custom-snippets-edit { + .field-wrapper { + textarea { + min-width: auto; + } + } + } } #custom-snippets-add-new, From 41bc07d9ccfa6ed56eb1959dae3b0ad5dcf649d9 Mon Sep 17 00:00:00 2001 From: Pluto Date: Thu, 10 Jul 2025 18:14:41 +0530 Subject: [PATCH 15/43] feat: disable reset button in edit panel when nothing to reset --- .../CustomSnippets/helper.js | 33 +++++++++++++++++++ .../CustomSnippets/main.js | 2 ++ 2 files changed, 35 insertions(+) diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 21644aa614..8a08a9dfe8 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -396,6 +396,38 @@ define(function (require, exports, module) { const hasAbbr = $abbrInput.val().trim().length > 0; const hasTemplate = $templateInput.val().trim().length > 0; $saveBtn.prop("disabled", !(hasAbbr && hasTemplate)); + + // Also toggle the reset button state + toggleResetButtonDisability(); + } + + /** + * This function checks if the snippet is in its default state and + * disables the reset button if it is + */ + function toggleResetButtonDisability() { + const $editView = $("#custom-snippets-edit"); + const originalSnippet = $editView.data("originalSnippet"); + const $resetBtn = $("#reset-snippet-btn"); + + if (!originalSnippet) { + // If there's no original snippet data, disable the reset button + $resetBtn.prop("disabled", true); + return; + } + + // Get current values from the form + const currentData = getEditSnippetData(); + + // Check if current values match original values + const isDefault = + currentData.abbreviation === originalSnippet.abbreviation && + currentData.description === (originalSnippet.description || "") && + currentData.templateText === originalSnippet.templateText && + currentData.fileExtension === originalSnippet.fileExtension; + + // Disable reset button if in default state + $resetBtn.prop("disabled", isDefault); } /** @@ -769,6 +801,7 @@ define(function (require, exports, module) { exports.populateEditForm = populateEditForm; exports.getEditSnippetData = getEditSnippetData; exports.toggleEditSaveButtonDisability = toggleEditSaveButtonDisability; + exports.toggleResetButtonDisability = toggleResetButtonDisability; exports.clearEditInputFields = clearEditInputFields; exports.handleTextareaTabKey = handleTextareaTabKey; exports.validateAbbrInput = validateAbbrInput; diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index 2b37b7ca46..5c4ff7f432 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -201,7 +201,9 @@ define(function (require, exports, module) { }); $editAbbrInput.on("input", Helper.toggleEditSaveButtonDisability); + $editDescInput.on("input", Helper.toggleEditSaveButtonDisability); $editTemplateInput.on("input", Helper.toggleEditSaveButtonDisability); + $editFileExtnInput.on("input", Helper.toggleEditSaveButtonDisability); $editAbbrInput.on("keydown", function (e) { Helper.validateAbbrInput(e, this); From 11552b6cb65f278186133a43ef0ae31ce8eb296a Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 12:03:41 +0530 Subject: [PATCH 16/43] fix: ui layout issues in snippets list header --- src/styles/Extn-CustomSnippets.less | 149 +++++++++++++++++++++------- 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 99da153d4a..368398a0a8 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -151,13 +151,14 @@ } #snippets-list-header { - display: flex; - align-items: center; - padding: 6px 13px; + display: block; + padding: 4px 12px 4px 16px; margin: 0; border: none; - font-weight: 700; background-color: #c2c7c7; + font-size: 0; + white-space: nowrap; + line-height: 20px; .dark & { background-color: #202020; @@ -166,41 +167,91 @@ #snippet-abbr-header, #snippet-abbr { - flex: 1; + width: 15%; min-width: 80px; + display: inline-block; + vertical-align: middle; + box-sizing: border-box; + font-size: 14px; + font-weight: 500; + line-height: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } #snippet-template-header, #snippet-template { - flex: 2.4; - min-width: 100px; + width: 35%; + min-width: 120px; + display: inline-block; + vertical-align: middle; + padding: 0 12px; + box-sizing: border-box; + font-size: 14px; + font-weight: 500; + line-height: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } #snippet-description-header, #snippet-description { - flex: 1.5; - min-width: 80px; + width: 25%; + min-width: 100px; + display: inline-block; + vertical-align: middle; + padding: 0 12px; + box-sizing: border-box; + font-size: 14px; + font-weight: 500; + line-height: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } #snippet-file-extension-header, #snippet-files { - flex: 0.8; + width: 15%; min-width: 60px; + display: inline-block; + vertical-align: middle; text-align: center; + box-sizing: border-box; + font-size: 14px; + font-weight: 500; + line-height: 20px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +#snippet-actions-header { + width: 10%; + min-width: 40px; + display: inline-block; + vertical-align: middle; + box-sizing: border-box; + font-size: 14px; + font-weight: 500; + line-height: 20px; } .snippet-item { - display: flex; - align-items: center; - padding: 4px 12px 4px 16px; + display: block; + padding: 2px 12px 2px 16px; margin: 0; border-bottom: 1px solid transparent; background-color: @bc-panel-bg; color: @bc-text; - line-height: 16px; position: relative; cursor: pointer; transition: background-color 0.1s ease; + font-size: 0; + white-space: nowrap; + line-height: 20px; .dark & { background-color: @dark-bc-panel-bg; @@ -238,11 +289,24 @@ } } +#snippet-abbr-header { + color: @bc-text; + + .dark & { + color: @dark-bc-text; + } +} + #snippet-abbr { color: @bc-text; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + .dark & { + color: @dark-bc-text; + } +} + +#snippet-template-header { + color: @bc-text; .dark & { color: @dark-bc-text; @@ -250,34 +314,39 @@ } #snippet-template { - margin: 0 12px; color: @bc-text-thin; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; .dark & { color: @dark-bc-text-thin; } } +#snippet-description-header { + color: @bc-text; + + .dark & { + color: @dark-bc-text; + } +} + #snippet-description { - margin: 0 12px; color: @bc-text-thin-quiet; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; .dark & { color: @dark-bc-text-thin-quiet; } } +#snippet-file-extension-header { + color: @bc-text; + + .dark & { + color: @dark-bc-text; + } +} + #snippet-files { color: @bc-text-thin-quiet; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; .dark & { color: @dark-bc-text-thin-quiet; @@ -285,15 +354,19 @@ } .delete-snippet-btn { + width: 10%; + min-width: 40px; + display: inline-block; + vertical-align: middle; + box-sizing: border-box; color: @bc-text-thin-quiet; cursor: pointer; opacity: 0.3; transition: opacity 0.1s ease; - display: flex; - align-items: center; - justify-content: center; - font-size: 0.9rem; - padding: 3px 6px; + text-align: center; + font-size: 14px; + line-height: 20px; + padding: 0; .dark & { color: @dark-bc-text-thin-quiet; @@ -309,11 +382,11 @@ } i { - width: 12px; - height: 12px; - display: flex; - align-items: center; - justify-content: center; + display: inline-block; + text-align: center; + font-size: 12px; + line-height: 20px; + vertical-align: middle; } } From 90a8a51f10d096d71c87fbf75020cf32f0dd60c4 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 15:02:51 +0530 Subject: [PATCH 17/43] fix: font weight issue for snippet list --- src/styles/Extn-CustomSnippets.less | 67 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/src/styles/Extn-CustomSnippets.less b/src/styles/Extn-CustomSnippets.less index 368398a0a8..a90af44b61 100644 --- a/src/styles/Extn-CustomSnippets.less +++ b/src/styles/Extn-CustomSnippets.less @@ -166,9 +166,9 @@ } #snippet-abbr-header, -#snippet-abbr { - width: 15%; - min-width: 80px; +#snippet-template-header, +#snippet-description-header, +#snippet-file-extension-header { display: inline-block; vertical-align: middle; box-sizing: border-box; @@ -180,52 +180,65 @@ text-overflow: ellipsis; } -#snippet-template-header, -#snippet-template { +#snippet-abbr-header { + width: 15%; + min-width: 80px; +} + +#snippet-template-header { width: 35%; min-width: 120px; + padding: 0 12px; +} + +#snippet-description-header { + width: 25%; + min-width: 100px; + padding: 0 12px; +} + +#snippet-file-extension-header { + width: 15%; + min-width: 60px; + text-align: center; +} + +#snippet-abbr, +#snippet-template, +#snippet-description, +#snippet-files { display: inline-block; vertical-align: middle; - padding: 0 12px; box-sizing: border-box; font-size: 14px; - font-weight: 500; + font-weight: normal; line-height: 20px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -#snippet-description-header, +#snippet-abbr { + width: 15%; + min-width: 80px; +} + +#snippet-template { + width: 35%; + min-width: 120px; + padding: 0 12px; +} + #snippet-description { width: 25%; min-width: 100px; - display: inline-block; - vertical-align: middle; padding: 0 12px; - box-sizing: border-box; - font-size: 14px; - font-weight: 500; - line-height: 20px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } -#snippet-file-extension-header, #snippet-files { width: 15%; min-width: 60px; - display: inline-block; - vertical-align: middle; text-align: center; - box-sizing: border-box; - font-size: 14px; - font-weight: 500; - line-height: 20px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; } #snippet-actions-header { From 99c819ae98218d9429916adf198b503174881852 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 16:09:12 +0530 Subject: [PATCH 18/43] feat: allow users to write file extension in any format --- .../CustomSnippets/helper.js | 76 ++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 8a08a9dfe8..fdeeb494d7 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -95,6 +95,72 @@ define(function (require, exports, module) { return languageMap[languageId] || languageId; } + /** + * This function is to make sure file extensions are properly formatted with leading dots + * because user may provide values in not very consistent manner, we need to handle all those cases + * For ex: what we expect: `.js, .html, .css` + * what user may provide: `js, html, css` or: `js html css` or `.js.html.css` etc + * + * This function processes file extensions in various formats and ensures they: + * - Have a leading dot (if not empty or "all") + * - Are properly separated with commas and spaces + * - Don't contain empty or standalone dots + * + * @param {string} extension - The file extension(s) to process + * @returns {string} - The properly formatted file extension(s) + */ + function processFileExtensionInput(extension) { + if (!extension || extension === "all") { + return extension; + } + + // Step 1: normalize the input by converting spaces to commas if no commas exist + if (extension.includes(" ")) { + extension = extension.replace(/\s+/g, ","); + } + + // Step 2: handle multiple extensions joined by dots (e.g., ".less.css.js") + // Only process if multiple dots exist and not already comma-separated + const dotCount = (extension.match(/\./g) || []).length; + if (dotCount > 1) { + // remove the leading dot if present for consistent processing + const extensionWithoutLeadingDot = extension.startsWith(".") ? extension.substring(1) : extension; + + // split by dot, filter empty parts, add leading dot to each part + const parts = extensionWithoutLeadingDot + .split(".") + .filter((part) => part !== "") + .map((part) => "." + part); + + return parts.join(", "); + } + + // Step 3: process comma-separated extensions + if (extension.includes(",")) { + return extension + .split(",") + .map((ext) => { + ext = ext.trim(); + // skip all the standalone dots or empty entries + if (ext === "." || ext === "") { + return ""; + } + // Add leading dot if missing + return ext.startsWith(".") ? ext : "." + ext; + }) + .filter((ext) => ext !== "") // Remove empty entries + .join(", "); + } + + // Step 4: Handle single extension + if (extension === ".") { + return ""; // remove standalone dot + } + + // Add leading dot if missing + return extension.startsWith(".") ? extension : "." + extension; + } + /** * This function is responsible to get the snippet data from all the required input fields * it is called when the save button is clicked @@ -108,11 +174,14 @@ define(function (require, exports, module) { const templateText = $("#template-text-box").val().trim(); const fileExtension = $("#file-extn-box").val().trim(); + // process the file extension so that we can get the value in the required format + const processedFileExtension = processFileExtensionInput(fileExtension); + return { abbreviation: abbreviation, description: description || "", // allow empty description templateText: templateText, - fileExtension: fileExtension || "all" // default to "all" if empty + fileExtension: processedFileExtension || "all" // default to "all" if empty }; } @@ -374,11 +443,14 @@ define(function (require, exports, module) { const templateText = $("#edit-template-text-box").val().trim(); const fileExtension = $("#edit-file-extn-box").val().trim(); + // process the file extension so that we can get the value in the required format + const processedFileExtension = processFileExtensionInput(fileExtension); + return { abbreviation: abbreviation, description: description || "", // allow empty description templateText: templateText, - fileExtension: fileExtension || "all" // default to "all" if empty + fileExtension: processedFileExtension || "all" // default to "all" if empty }; } From f941f0153e8e0249d14e3acbdf8def3bc0dafa97 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 17:13:35 +0530 Subject: [PATCH 19/43] fix: mutliple commas appearing when parsing failed --- .../CustomSnippets/helper.js | 55 +++++++++++-------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index fdeeb494d7..0b85a9fb5f 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -105,6 +105,7 @@ define(function (require, exports, module) { * - Have a leading dot (if not empty or "all") * - Are properly separated with commas and spaces * - Don't contain empty or standalone dots + * - No consecutive commas * * @param {string} extension - The file extension(s) to process * @returns {string} - The properly formatted file extension(s) @@ -119,25 +120,12 @@ define(function (require, exports, module) { extension = extension.replace(/\s+/g, ","); } - // Step 2: handle multiple extensions joined by dots (e.g., ".less.css.js") - // Only process if multiple dots exist and not already comma-separated - const dotCount = (extension.match(/\./g) || []).length; - if (dotCount > 1) { - // remove the leading dot if present for consistent processing - const extensionWithoutLeadingDot = extension.startsWith(".") ? extension.substring(1) : extension; + let result = ""; - // split by dot, filter empty parts, add leading dot to each part - const parts = extensionWithoutLeadingDot - .split(".") - .filter((part) => part !== "") - .map((part) => "." + part); - - return parts.join(", "); - } - - // Step 3: process comma-separated extensions + // Step 2: process comma-separated extensions FIRST (before dot-separated) + // this prevents issues with inputs like ".js,.html,." or ".js,,.html" if (extension.includes(",")) { - return extension + result = extension .split(",") .map((ext) => { ext = ext.trim(); @@ -150,15 +138,36 @@ define(function (require, exports, module) { }) .filter((ext) => ext !== "") // Remove empty entries .join(", "); + } else { + // Step 3: handle multiple extensions joined by dots (e.g., ".less.css.js") + // Only process if multiple dots exist and no commas + const dotCount = (extension.match(/\./g) || []).length; + if (dotCount > 1) { + // remove the leading dot if present for consistent processing + const extensionWithoutLeadingDot = extension.startsWith(".") ? extension.substring(1) : extension; + + // split by dot, filter empty parts, add leading dot to each part + const parts = extensionWithoutLeadingDot + .split(".") + .filter((part) => part !== "") + .map((part) => "." + part); + + result = parts.join(", "); + } else { + // Step 4: Handle single extension + if (extension === ".") { + result = ""; // remove standalone dot + } else { + // Add leading dot if missing + result = extension.startsWith(".") ? extension : "." + extension; + } + } } - // Step 4: Handle single extension - if (extension === ".") { - return ""; // remove standalone dot - } + // this is just the final safeguard to remove any consecutive commas and clean up spacing + result = result.replace(/,\s*,+/g, ",").replace(/,\s*$/, "").replace(/^\s*,/, "").trim(); - // Add leading dot if missing - return extension.startsWith(".") ? extension : "." + extension; + return result; } /** From 4148d561e01e12e9b7be2abdd8224fe20694d030 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 17:20:04 +0530 Subject: [PATCH 20/43] fix: remove trailing dot from result --- src/extensionsIntegrated/CustomSnippets/helper.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 0b85a9fb5f..379f48f318 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -166,6 +166,8 @@ define(function (require, exports, module) { // this is just the final safeguard to remove any consecutive commas and clean up spacing result = result.replace(/,\s*,+/g, ",").replace(/,\s*$/, "").replace(/^\s*,/, "").trim(); + // remove trailing dots (like .css. -> .css) + result = result.endsWith('.') ? result.slice(0, -1) : result; return result; } From 3191f02ef06e6f3034e6942433d8e0d9f0212da3 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 18:17:28 +0530 Subject: [PATCH 21/43] feat: save snippets to file storage instead of prefs manager --- .../CustomSnippets/driver.js | 22 ++++-- .../CustomSnippets/main.js | 11 ++- .../CustomSnippets/snippetsList.js | 16 ++++- .../CustomSnippets/snippetsState.js | 68 ++++++++++++------- 4 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/driver.js b/src/extensionsIntegrated/CustomSnippets/driver.js index bd3871558f..2b8ce27adf 100644 --- a/src/extensionsIntegrated/CustomSnippets/driver.js +++ b/src/extensionsIntegrated/CustomSnippets/driver.js @@ -45,7 +45,15 @@ define(function (require, exports, module) { Global.SnippetHintsList.push(snippetData); Helper.clearAllInputFields(); Helper.toggleSaveButtonDisability(); - SnippetsState.saveSnippetsToState(); + + // save to file storage + SnippetsState.saveSnippetsToState() + .then(function () { + // + }) + .catch(function (error) { + console.error("failed to save custom snippet correctly:", error); + }); // we need to move back to snippets list view after a snippet is saved UIHelper.showSnippetListMenu(); @@ -87,7 +95,15 @@ define(function (require, exports, module) { // update the snippet in the list if (snippetIndex !== -1) { Global.SnippetHintsList[snippetIndex] = editedData; - SnippetsState.saveSnippetsToState(); + + // save to file storage + SnippetsState.saveSnippetsToState() + .then(function () { + // + }) + .catch(function (error) { + console.error("failed to save custom snippet correctly:", error); + }); // clear the stored data $editView.removeData("originalSnippet"); @@ -164,8 +180,6 @@ define(function (require, exports, module) { }; } - - exports.getWordBeforeCursor = getWordBeforeCursor; exports.handleSaveBtnClick = handleSaveBtnClick; exports.handleEditSaveBtnClick = handleEditSaveBtnClick; diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index 5c4ff7f432..35dec54975 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -258,7 +258,16 @@ define(function (require, exports, module) { $snippetsPanel = $(snippetsPanelTpl); _addToMenu(); CodeHintIntegration.init(); - SnippetsState.loadSnippetsFromState(); + + // load snippets from file storage + SnippetsState.loadSnippetsFromState() + .then(function () { + // + }) + .catch(function (error) { + console.error("failed to load custom snippets:", error); + }); + SnippetCursorManager.registerHandlers(); }); }); diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsList.js b/src/extensionsIntegrated/CustomSnippets/snippetsList.js index a8b6b94b2e..0d4f13d8ed 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsList.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsList.js @@ -104,7 +104,9 @@ define(function (require, exports, module) { if (filterText) { $emptyMessage.text(`No snippets match "${filterText}"`); } else { - $emptyMessage.html('Add your own code hints to speed up coding - Learn More'); + $emptyMessage.html( + 'Add your own code hints to speed up coding - Learn More' + ); } } @@ -163,8 +165,16 @@ define(function (require, exports, module) { if (index !== -1) { Global.SnippetHintsList.splice(index, 1); // removes it from the actual array - // save to preferences after deleting snippet - SnippetsState.saveSnippetsToState(); + + // save to file storage + SnippetsState.saveSnippetsToState() + .then(function () { + // + }) + .catch(function (error) { + console.error("failed to delete custom snippet correctly:", error); + }); + // update the snippets count in toolbar Helper.updateSnippetsCount(); // Refresh the entire list to properly handle filtering diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsState.js b/src/extensionsIntegrated/CustomSnippets/snippetsState.js index 412a27f4b0..34d351e5d6 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsState.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsState.js @@ -19,45 +19,61 @@ */ define(function (require, exports, module) { - const PreferencesManager = require("preferences/PreferencesManager"); - const Global = require("./global"); + const PreferencesBase = require("preferences/PreferencesBase"); - // create extension preferences - const prefs = PreferencesManager.getExtensionPrefs("CustomSnippets"); + const SNIPPETS_FILE_PATH = brackets.app.getApplicationSupportDirectory() + "/customSnippets.json"; - // define preference for storing snippets - prefs.definePreference("snippetsList", "array", [], { - description: "List of custom code snippets" + // the file storage for storing the snippets + const fileStorage = new PreferencesBase.FileStorage(SNIPPETS_FILE_PATH, { + snippets: [] }); /** - * Load snippets from preferences - * This is called on startup to restore previously saved snippets + * This function is responsible to load snippets from file storage + * @returns {Promise} a promise that resolves when snippets are loaded */ function loadSnippetsFromState() { - try { - const savedSnippets = prefs.get("snippetsList"); - if (Array.isArray(savedSnippets)) { - // clear existing snippets and load from saved state - Global.SnippetHintsList.length = 0; - Global.SnippetHintsList.push(...savedSnippets); - } - } catch (e) { - console.error("something went wrong when trying to load custom snippets from preferences:", e); - } + return new Promise((resolve, reject) => { + fileStorage + .load() + .done(function (data) { + if (data && data.snippets && Array.isArray(data.snippets)) { + Global.SnippetHintsList = data.snippets; + } else { + // no snippets are present + Global.SnippetHintsList = []; + } + resolve(); + }) + .fail(function (error) { + console.error("unable to load snippets from file storage:", error); + Global.SnippetHintsList = []; // since it failed we init a empty array + reject(error); + }); + }); } /** - * Save snippets to preferences - * This is called whenever snippets are modified + * this function is responsible to save snippets to file storage + * @returns {Promise} a promise that resolves when snippets are saved */ function saveSnippetsToState() { - try { - prefs.set("snippetsList", [...Global.SnippetHintsList]); - } catch (e) { - console.error("something went wrong when saving custom snippets to preferences:", e); - } + return new Promise((resolve, reject) => { + const dataToSave = { + snippets: Global.SnippetHintsList + }; + + fileStorage + .save(dataToSave) + .done(() => { + resolve(); + }) + .fail((error) => { + console.error("unable to save snippets to file storage:", error); + reject(error); + }); + }); } exports.loadSnippetsFromState = loadSnippetsFromState; From 2a12fd3601983da313cca653cbb69e9cca750e50 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 23:03:08 +0530 Subject: [PATCH 22/43] feat: replace reset button with cancel button in the edit snippets panel --- .../CustomSnippets/driver.js | 19 +++++++---- .../CustomSnippets/helper.js | 33 ------------------- .../htmlContent/snippets-panel.html | 2 +- .../CustomSnippets/main.js | 6 ++-- 4 files changed, 16 insertions(+), 44 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/driver.js b/src/extensionsIntegrated/CustomSnippets/driver.js index 2b8ce27adf..93a3f6be9e 100644 --- a/src/extensionsIntegrated/CustomSnippets/driver.js +++ b/src/extensionsIntegrated/CustomSnippets/driver.js @@ -116,19 +116,24 @@ define(function (require, exports, module) { } /** - * This function handles the reset button click for editing a snippet - * It restores the original snippet data in the edit form + * This function is responsible to handle the cancel button click in the edit-snippet panel + * this resets the format to the last saved values and then moves back to the snippets-list panel */ - function handleResetBtnClick() { + function handleCancelEditBtnClick() { const $editView = $("#custom-snippets-edit"); const originalSnippet = $editView.data("originalSnippet"); if (originalSnippet) { - // restore original data in the form + // restore original data in the form to reset any changes Helper.populateEditForm(originalSnippet); - // update save button state - Helper.toggleEditSaveButtonDisability(); } + + $editView.removeData("originalSnippet"); + $editView.removeData("snippetIndex"); + + // navigate back to snippets list + UIHelper.showSnippetListMenu(); + SnippetsList.showSnippetsList(); } /** @@ -183,5 +188,5 @@ define(function (require, exports, module) { exports.getWordBeforeCursor = getWordBeforeCursor; exports.handleSaveBtnClick = handleSaveBtnClick; exports.handleEditSaveBtnClick = handleEditSaveBtnClick; - exports.handleResetBtnClick = handleResetBtnClick; + exports.handleCancelEditBtnClick = handleCancelEditBtnClick; }); diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 379f48f318..5f0c015fe1 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -479,38 +479,6 @@ define(function (require, exports, module) { const hasAbbr = $abbrInput.val().trim().length > 0; const hasTemplate = $templateInput.val().trim().length > 0; $saveBtn.prop("disabled", !(hasAbbr && hasTemplate)); - - // Also toggle the reset button state - toggleResetButtonDisability(); - } - - /** - * This function checks if the snippet is in its default state and - * disables the reset button if it is - */ - function toggleResetButtonDisability() { - const $editView = $("#custom-snippets-edit"); - const originalSnippet = $editView.data("originalSnippet"); - const $resetBtn = $("#reset-snippet-btn"); - - if (!originalSnippet) { - // If there's no original snippet data, disable the reset button - $resetBtn.prop("disabled", true); - return; - } - - // Get current values from the form - const currentData = getEditSnippetData(); - - // Check if current values match original values - const isDefault = - currentData.abbreviation === originalSnippet.abbreviation && - currentData.description === (originalSnippet.description || "") && - currentData.templateText === originalSnippet.templateText && - currentData.fileExtension === originalSnippet.fileExtension; - - // Disable reset button if in default state - $resetBtn.prop("disabled", isDefault); } /** @@ -884,7 +852,6 @@ define(function (require, exports, module) { exports.populateEditForm = populateEditForm; exports.getEditSnippetData = getEditSnippetData; exports.toggleEditSaveButtonDisability = toggleEditSaveButtonDisability; - exports.toggleResetButtonDisability = toggleResetButtonDisability; exports.clearEditInputFields = clearEditInputFields; exports.handleTextareaTabKey = handleTextareaTabKey; exports.validateAbbrInput = validateAbbrInput; diff --git a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html index fd4c253f59..669da372cd 100644 --- a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html +++ b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html @@ -163,7 +163,7 @@
- +
diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index 35dec54975..7c95d84732 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -141,7 +141,7 @@ define(function (require, exports, module) { const $editTemplateInput = $("#edit-template-text-box"); const $editFileExtnInput = $("#edit-file-extn-box"); const $saveEditSnippetBtn = $("#save-edit-snippet-btn"); - const $resetSnippetBtn = $("#reset-snippet-btn"); + const $cancelEditSnippetBtn = $("#cancel-edit-snippet-btn"); $addSnippetBtn.on("click", function () { UIHelper.showAddSnippetMenu(); @@ -237,8 +237,8 @@ define(function (require, exports, module) { Driver.handleEditSaveBtnClick(); }); - $resetSnippetBtn.on("click", function () { - Driver.handleResetBtnClick(); + $cancelEditSnippetBtn.on("click", function () { + Driver.handleCancelEditBtnClick(); }); // filter input event handler From ae5852660d7d6f3db4e134cec5430ae92680f128 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sat, 12 Jul 2025 23:31:47 +0530 Subject: [PATCH 23/43] fix: prevent processing file extension where two dots are there to support compound extensions --- .../CustomSnippets/helper.js | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 5f0c015fe1..1b78adaf5f 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -99,7 +99,7 @@ define(function (require, exports, module) { * This function is to make sure file extensions are properly formatted with leading dots * because user may provide values in not very consistent manner, we need to handle all those cases * For ex: what we expect: `.js, .html, .css` - * what user may provide: `js, html, css` or: `js html css` or `.js.html.css` etc + * what user may provide: `js, html, css` or: `js html css` etc * * This function processes file extensions in various formats and ensures they: * - Have a leading dot (if not empty or "all") @@ -139,28 +139,12 @@ define(function (require, exports, module) { .filter((ext) => ext !== "") // Remove empty entries .join(", "); } else { - // Step 3: handle multiple extensions joined by dots (e.g., ".less.css.js") - // Only process if multiple dots exist and no commas - const dotCount = (extension.match(/\./g) || []).length; - if (dotCount > 1) { - // remove the leading dot if present for consistent processing - const extensionWithoutLeadingDot = extension.startsWith(".") ? extension.substring(1) : extension; - - // split by dot, filter empty parts, add leading dot to each part - const parts = extensionWithoutLeadingDot - .split(".") - .filter((part) => part !== "") - .map((part) => "." + part); - - result = parts.join(", "); + // Step 3: Handle single extension + if (extension === ".") { + result = ""; // remove standalone dot } else { - // Step 4: Handle single extension - if (extension === ".") { - result = ""; // remove standalone dot - } else { - // Add leading dot if missing - result = extension.startsWith(".") ? extension : "." + extension; - } + // Add leading dot if missing + result = extension.startsWith(".") ? extension : "." + extension; } } From 589b6d16e5a87dccab2e654ba3ab2a2acb9d7f33 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sun, 13 Jul 2025 00:02:47 +0530 Subject: [PATCH 24/43] refactor: replace template with Click to edit template and so on --- .../CustomSnippets/snippetsList.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsList.js b/src/extensionsIntegrated/CustomSnippets/snippetsList.js index 0d4f13d8ed..4d801151ed 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsList.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsList.js @@ -45,12 +45,16 @@ define(function (require, exports, module) { const $snippetAbbr = $("
") .text(snippetItem.abbreviation) .attr("id", "snippet-abbr") - .attr("title", `Abbreviation: ${snippetItem.abbreviation}`); + .attr("title", `Click to edit abbreviation - ${snippetItem.abbreviation}`); const $snippetTemplate = $("
") .text(snippetItem.templateText) .attr("id", "snippet-template") - .attr("title", `Template: ${snippetItem.templateText}`); + .attr( + "title", + `Click to edit template text - +${snippetItem.templateText}` + ); const $snippetDescription = $("
") .text( @@ -62,14 +66,14 @@ define(function (require, exports, module) { .attr( "title", snippetItem.description && snippetItem.description.trim() !== "" - ? `Description: ${snippetItem.description}` - : "No description provided" + ? `Click to edit description - ${snippetItem.description}` + : "Click to add description" ); const $snippetFiles = $("
") .text(snippetItem.fileExtension || "all") .attr("id", "snippet-files") - .attr("title", `File extensions: ${snippetItem.fileExtension}`); + .attr("title", `Click to edit file extensions - ${snippetItem.fileExtension || "all"}`); const $deleteSnippet = $("
") .html(``) From 8068629e14a0fffd2c5a1b087f04e080c4a7271e Mon Sep 17 00:00:00 2001 From: Pluto Date: Sun, 13 Jul 2025 14:31:21 +0530 Subject: [PATCH 25/43] refactor: store snippets directly in file instead of preferencesBase --- .../CustomSnippets/snippetsState.js | 66 ++++++++++++------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsState.js b/src/extensionsIntegrated/CustomSnippets/snippetsState.js index 34d351e5d6..050fd4a782 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsState.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsState.js @@ -20,36 +20,50 @@ define(function (require, exports, module) { const Global = require("./global"); - const PreferencesBase = require("preferences/PreferencesBase"); + const FileSystem = require("filesystem/FileSystem"); + const FileUtils = require("file/FileUtils"); + const FileSystemError = require("filesystem/FileSystemError"); const SNIPPETS_FILE_PATH = brackets.app.getApplicationSupportDirectory() + "/customSnippets.json"; - // the file storage for storing the snippets - const fileStorage = new PreferencesBase.FileStorage(SNIPPETS_FILE_PATH, { - snippets: [] - }); - /** * This function is responsible to load snippets from file storage * @returns {Promise} a promise that resolves when snippets are loaded */ function loadSnippetsFromState() { return new Promise((resolve, reject) => { - fileStorage - .load() - .done(function (data) { - if (data && data.snippets && Array.isArray(data.snippets)) { - Global.SnippetHintsList = data.snippets; - } else { - // no snippets are present - Global.SnippetHintsList = []; + const file = FileSystem.getFileForPath(SNIPPETS_FILE_PATH); + + // true is for bypassCache, to get the latest content always + const readPromise = FileUtils.readAsText(file, true); + + readPromise + .done(function (text) { + try { + const data = JSON.parse(text); + if (data && data.snippets && Array.isArray(data.snippets)) { + Global.SnippetHintsList = data.snippets; + } else { + // no snippets are present + Global.SnippetHintsList = []; + } + resolve(); + } catch (error) { + console.error("Error parsing snippets JSON:", error); + Global.SnippetHintsList = []; // fallback + resolve(); } - resolve(); }) .fail(function (error) { - console.error("unable to load snippets from file storage:", error); - Global.SnippetHintsList = []; // since it failed we init a empty array - reject(error); + if (error === FileSystemError.NOT_FOUND) { + // file is not present, empty array + Global.SnippetHintsList = []; + resolve(); + } else { + console.error("Unable to load snippets from file storage:", error); + Global.SnippetHintsList = []; + reject(error); + } }); }); } @@ -64,13 +78,19 @@ define(function (require, exports, module) { snippets: Global.SnippetHintsList }; - fileStorage - .save(dataToSave) - .done(() => { + const file = FileSystem.getFileForPath(SNIPPETS_FILE_PATH); + // 2 is for pretty print + const jsonText = JSON.stringify(dataToSave, null, 2); + + // true is allowBlindWrite to overwrite without checking file contents + const writePromise = FileUtils.writeText(file, jsonText, true); + + writePromise + .done(function () { resolve(); }) - .fail((error) => { - console.error("unable to save snippets to file storage:", error); + .fail(function (error) { + console.error("Unable to save snippets to file storage:", error); reject(error); }); }); From 206daed2b3ee9961fb44cf9c38dd6eb8049306d8 Mon Sep 17 00:00:00 2001 From: Pluto Date: Sun, 13 Jul 2025 14:50:07 +0530 Subject: [PATCH 26/43] fix: snippets 3 dots in the menu item was not consistent with the 3 dots in other menu items --- src/extensionsIntegrated/CustomSnippets/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index 7c95d84732..720ce9aaca 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -40,7 +40,7 @@ define(function (require, exports, module) { const MY_COMMAND_ID = "custom_snippets"; const PANEL_ID = "customSnippets.panel"; - const MENU_ITEM_NAME = "Custom Snippets..."; // this name will appear as the menu item + const MENU_ITEM_NAME = "Custom Snippets\u2026"; // this name will appear as the menu item const PANEL_MIN_SIZE = 340; // the minimum size more than which its height cannot be decreased // this is to store the panel reference, From 77a239100d28e505bf0631a34e64048c62d1cdf5 Mon Sep 17 00:00:00 2001 From: Pluto Date: Mon, 14 Jul 2025 11:04:57 +0530 Subject: [PATCH 27/43] fix: remove redundant then blocks --- src/extensionsIntegrated/CustomSnippets/driver.js | 6 ------ src/extensionsIntegrated/CustomSnippets/main.js | 3 --- src/extensionsIntegrated/CustomSnippets/snippetsList.js | 3 --- 3 files changed, 12 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/driver.js b/src/extensionsIntegrated/CustomSnippets/driver.js index 93a3f6be9e..4f8589454b 100644 --- a/src/extensionsIntegrated/CustomSnippets/driver.js +++ b/src/extensionsIntegrated/CustomSnippets/driver.js @@ -48,9 +48,6 @@ define(function (require, exports, module) { // save to file storage SnippetsState.saveSnippetsToState() - .then(function () { - // - }) .catch(function (error) { console.error("failed to save custom snippet correctly:", error); }); @@ -98,9 +95,6 @@ define(function (require, exports, module) { // save to file storage SnippetsState.saveSnippetsToState() - .then(function () { - // - }) .catch(function (error) { console.error("failed to save custom snippet correctly:", error); }); diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index 720ce9aaca..b77f47b156 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -261,9 +261,6 @@ define(function (require, exports, module) { // load snippets from file storage SnippetsState.loadSnippetsFromState() - .then(function () { - // - }) .catch(function (error) { console.error("failed to load custom snippets:", error); }); diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsList.js b/src/extensionsIntegrated/CustomSnippets/snippetsList.js index 4d801151ed..e559ad90fa 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsList.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsList.js @@ -172,9 +172,6 @@ ${snippetItem.templateText}` // save to file storage SnippetsState.saveSnippetsToState() - .then(function () { - // - }) .catch(function (error) { console.error("failed to delete custom snippet correctly:", error); }); From 8c502ab86a3caff25941630ef9f11447b103e249 Mon Sep 17 00:00:00 2001 From: Pluto Date: Mon, 14 Jul 2025 11:18:01 +0530 Subject: [PATCH 28/43] fix: remove unnecessary pretty printing when saving file --- src/extensionsIntegrated/CustomSnippets/snippetsState.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsState.js b/src/extensionsIntegrated/CustomSnippets/snippetsState.js index 050fd4a782..795cdfb6f0 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsState.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsState.js @@ -79,8 +79,7 @@ define(function (require, exports, module) { }; const file = FileSystem.getFileForPath(SNIPPETS_FILE_PATH); - // 2 is for pretty print - const jsonText = JSON.stringify(dataToSave, null, 2); + const jsonText = JSON.stringify(dataToSave); // true is allowBlindWrite to overwrite without checking file contents const writePromise = FileUtils.writeText(file, jsonText, true); From 2947c2daf4ab414f083b657c778de46f28abcad6 Mon Sep 17 00:00:00 2001 From: Pluto Date: Mon, 14 Jul 2025 12:06:56 +0530 Subject: [PATCH 29/43] fix: directly return jsPromise for writeText instead of creating a new promise --- .../CustomSnippets/snippetsState.js | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsState.js b/src/extensionsIntegrated/CustomSnippets/snippetsState.js index 795cdfb6f0..496b15d17c 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsState.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsState.js @@ -18,6 +18,7 @@ * */ +/* global jsPromise */ define(function (require, exports, module) { const Global = require("./global"); const FileSystem = require("filesystem/FileSystem"); @@ -73,26 +74,15 @@ define(function (require, exports, module) { * @returns {Promise} a promise that resolves when snippets are saved */ function saveSnippetsToState() { - return new Promise((resolve, reject) => { - const dataToSave = { - snippets: Global.SnippetHintsList - }; - - const file = FileSystem.getFileForPath(SNIPPETS_FILE_PATH); - const jsonText = JSON.stringify(dataToSave); + const dataToSave = { + snippets: Global.SnippetHintsList + }; - // true is allowBlindWrite to overwrite without checking file contents - const writePromise = FileUtils.writeText(file, jsonText, true); + const file = FileSystem.getFileForPath(SNIPPETS_FILE_PATH); + const jsonText = JSON.stringify(dataToSave); - writePromise - .done(function () { - resolve(); - }) - .fail(function (error) { - console.error("Unable to save snippets to file storage:", error); - reject(error); - }); - }); + // true is allowBlindWrite to overwrite without checking file contents + return jsPromise(FileUtils.writeText(file, jsonText, true)); } exports.loadSnippetsFromState = loadSnippetsFromState; From d4491e1f78049cb500c39aa5a665b564ad23c694 Mon Sep 17 00:00:00 2001 From: Pluto Date: Mon, 14 Jul 2025 12:22:55 +0530 Subject: [PATCH 30/43] feat: report unexpected errors to bugsnag --- src/extensionsIntegrated/CustomSnippets/driver.js | 3 +++ src/extensionsIntegrated/CustomSnippets/main.js | 2 ++ src/extensionsIntegrated/CustomSnippets/snippetsState.js | 7 ++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/extensionsIntegrated/CustomSnippets/driver.js b/src/extensionsIntegrated/CustomSnippets/driver.js index 4f8589454b..242f226906 100644 --- a/src/extensionsIntegrated/CustomSnippets/driver.js +++ b/src/extensionsIntegrated/CustomSnippets/driver.js @@ -18,6 +18,7 @@ * */ +/* global logger */ define(function (require, exports, module) { const EditorManager = require("editor/EditorManager"); @@ -50,6 +51,7 @@ define(function (require, exports, module) { SnippetsState.saveSnippetsToState() .catch(function (error) { console.error("failed to save custom snippet correctly:", error); + logger.reportError(error, "Custom Snippets: failed to save new snippet to file storage"); }); // we need to move back to snippets list view after a snippet is saved @@ -97,6 +99,7 @@ define(function (require, exports, module) { SnippetsState.saveSnippetsToState() .catch(function (error) { console.error("failed to save custom snippet correctly:", error); + logger.reportError(error, "Custom Snippets: failed to save edited snippet to file storage"); }); // clear the stored data diff --git a/src/extensionsIntegrated/CustomSnippets/main.js b/src/extensionsIntegrated/CustomSnippets/main.js index b77f47b156..53668dee32 100644 --- a/src/extensionsIntegrated/CustomSnippets/main.js +++ b/src/extensionsIntegrated/CustomSnippets/main.js @@ -19,6 +19,7 @@ */ /* eslint-disable no-invalid-this */ +/* global logger */ define(function (require, exports, module) { const AppInit = require("utils/AppInit"); const CommandManager = require("command/CommandManager"); @@ -263,6 +264,7 @@ define(function (require, exports, module) { SnippetsState.loadSnippetsFromState() .catch(function (error) { console.error("failed to load custom snippets:", error); + logger.reportError(error, "Custom Snippets: didn't load on app init"); }); SnippetCursorManager.registerHandlers(); diff --git a/src/extensionsIntegrated/CustomSnippets/snippetsState.js b/src/extensionsIntegrated/CustomSnippets/snippetsState.js index 496b15d17c..2ba22da750 100644 --- a/src/extensionsIntegrated/CustomSnippets/snippetsState.js +++ b/src/extensionsIntegrated/CustomSnippets/snippetsState.js @@ -18,7 +18,7 @@ * */ -/* global jsPromise */ +/* global jsPromise, logger */ define(function (require, exports, module) { const Global = require("./global"); const FileSystem = require("filesystem/FileSystem"); @@ -51,6 +51,10 @@ define(function (require, exports, module) { resolve(); } catch (error) { console.error("Error parsing snippets JSON:", error); + logger.reportError( + error, + "Custom Snippets: Failed to parse snippets JSON file. File might be corrupted." + ); Global.SnippetHintsList = []; // fallback resolve(); } @@ -62,6 +66,7 @@ define(function (require, exports, module) { resolve(); } else { console.error("Unable to load snippets from file storage:", error); + logger.reportError(error, "Custom Snippets: unexpected file system error loading snippets"); Global.SnippetHintsList = []; reject(error); } From 63d1a7bcd8264d961f95895ea0dc1667d5e78cc1 Mon Sep 17 00:00:00 2001 From: Pluto Date: Mon, 14 Jul 2025 13:04:48 +0530 Subject: [PATCH 31/43] feat: move all strings to strings.js file --- .../CustomSnippets/UIHelper.js | 3 +- .../CustomSnippets/helper.js | 20 ++--- .../htmlContent/snippets-panel.html | 74 +++++++++---------- .../CustomSnippets/main.js | 8 +- .../CustomSnippets/snippetsList.js | 23 +++--- src/nls/root/strings.js | 42 ++++++++++- 6 files changed, 103 insertions(+), 67 deletions(-) diff --git a/src/extensionsIntegrated/CustomSnippets/UIHelper.js b/src/extensionsIntegrated/CustomSnippets/UIHelper.js index 51a14308d4..ffbf24f94d 100644 --- a/src/extensionsIntegrated/CustomSnippets/UIHelper.js +++ b/src/extensionsIntegrated/CustomSnippets/UIHelper.js @@ -21,6 +21,7 @@ /* eslint-disable no-invalid-this */ define(function (require, exports, module) { const Global = require("./global"); + const Strings = require("strings"); /** * this is a generic function to show error messages for input fields @@ -187,7 +188,7 @@ define(function (require, exports, module) { const wrapperId = isEditForm ? "edit-abbr-box-wrapper" : "abbr-box-wrapper"; const errorId = isEditForm ? "edit-abbreviation-duplicate-error" : "abbreviation-duplicate-error"; - showError(inputId, wrapperId, `A snippet with abbreviation "${abbreviation}" already exists.`, errorId); + showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_DUPLICATE_ERROR.replace("{0}", abbreviation), errorId); } /** diff --git a/src/extensionsIntegrated/CustomSnippets/helper.js b/src/extensionsIntegrated/CustomSnippets/helper.js index 1b78adaf5f..d6276d9014 100644 --- a/src/extensionsIntegrated/CustomSnippets/helper.js +++ b/src/extensionsIntegrated/CustomSnippets/helper.js @@ -22,6 +22,7 @@ define(function (require, exports, module) { const StringMatch = require("utils/StringMatch"); const Global = require("./global"); const UIHelper = require("./UIHelper"); + const Strings = require("strings"); // list of all the navigation and function keys that are allowed inside the input fields const ALLOWED_NAVIGATION_KEYS = [ @@ -389,7 +390,7 @@ define(function (require, exports, module) { } // the codehints related style is written in brackets_patterns_override.less file - let $icon = $(`Snippet`); + let $icon = $(`${Strings.CUSTOM_SNIPPETS_HINT_LABEL}`); $hint.append($icon); if (description && description.trim() !== "") { @@ -620,7 +621,7 @@ define(function (require, exports, module) { const wrapperId = isEditForm ? "edit-abbr-box-wrapper" : "abbr-box-wrapper"; const errorId = isEditForm ? "edit-abbreviation-space-error" : "abbreviation-space-error"; - UIHelper.showError(inputId, wrapperId, "Space is not accepted as a valid abbreviation character.", errorId); + UIHelper.showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_SPACE_ERROR, errorId); return; } @@ -638,7 +639,7 @@ define(function (require, exports, module) { const wrapperId = isEditForm ? "edit-abbr-box-wrapper" : "abbr-box-wrapper"; const errorId = isEditForm ? "edit-abbreviation-length-error" : "abbreviation-length-error"; - UIHelper.showError(inputId, wrapperId, "Abbreviation cannot be more than 30 characters.", errorId); + UIHelper.showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_ABBR_LENGTH_ERROR, errorId); } } @@ -667,7 +668,7 @@ define(function (require, exports, module) { const wrapperId = isEditForm ? "edit-desc-box-wrapper" : "desc-box-wrapper"; const errorId = isEditForm ? "edit-description-length-error" : "description-length-error"; - UIHelper.showError(inputId, wrapperId, "Description cannot be more than 80 characters.", errorId); + UIHelper.showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_DESC_LENGTH_ERROR, errorId); } } @@ -730,15 +731,10 @@ define(function (require, exports, module) { // Prioritize length error over space error if both occurred if (wasTruncated) { const errorId = isEditForm ? "edit-abbreviation-paste-length-error" : "abbreviation-paste-length-error"; - UIHelper.showError(inputId, wrapperId, "Abbreviation cannot be more than 30 characters.", errorId); + UIHelper.showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_ABBR_LENGTH_ERROR, errorId); } else if (hadSpaces) { const errorId = isEditForm ? "edit-abbreviation-paste-space-error" : "abbreviation-paste-space-error"; - UIHelper.showError( - inputId, - wrapperId, - "Space is not accepted as a valid abbreviation character.", - errorId - ); + UIHelper.showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_SPACE_ERROR, errorId); } } @@ -806,7 +802,7 @@ define(function (require, exports, module) { const wrapperId = isEditForm ? "edit-desc-box-wrapper" : "desc-box-wrapper"; const errorId = isEditForm ? "edit-description-paste-length-error" : "description-paste-length-error"; - UIHelper.showError(inputId, wrapperId, "Description cannot be more than 80 characters.", errorId); + UIHelper.showError(inputId, wrapperId, Strings.CUSTOM_SNIPPETS_DESC_LENGTH_ERROR, errorId); } // Determine which save button to toggle based on input field diff --git a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html index 669da372cd..f1b5e3c0e2 100644 --- a/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html +++ b/src/extensionsIntegrated/CustomSnippets/htmlContent/snippets-panel.html @@ -1,22 +1,22 @@
- Custom Snippets + {{Strings.CUSTOM_SNIPPETS_PANEL_TITLE}}
-
- +
×
@@ -26,17 +26,17 @@
-
No custom snippets added yet!
+
{{Strings.CUSTOM_SNIPPETS_NO_SNIPPETS_MESSAGE}}
- +
-
Abbreviation
-
Template Text
-
Description
-
File Extension
+
{{Strings.CUSTOM_SNIPPETS_HEADER_ABBREVIATION}}
+
{{Strings.CUSTOM_SNIPPETS_HEADER_TEMPLATE}}
+
{{Strings.CUSTOM_SNIPPETS_HEADER_DESCRIPTION}}
+
{{Strings.CUSTOM_SNIPPETS_HEADER_FILE_EXTENSION}}
@@ -69,9 +69,9 @@
@@ -80,39 +80,39 @@
- +
- +
- +
- - + +
@@ -121,9 +121,9 @@
@@ -132,39 +132,39 @@
- +
- +
- +