diff --git a/CHANGELOG-WIP.md b/CHANGELOG-WIP.md index 30b606e8b03..ff128d63a96 100644 --- a/CHANGELOG-WIP.md +++ b/CHANGELOG-WIP.md @@ -415,6 +415,11 @@ Craft 6 now uses [Laravel's authorization system](https://laravel.com/docs/12.x/ - Deprecated `craft\events\RegisterConditionRulesEvent`. `CraftCms\Cms\Condition\Events\ConditionRulesResolving` should be used instead. +### Control Panel + +- Removed the `Craft.Accordion` and `Craft.EnvVarGenerator` control panel JavaScript classes. ([#XXXXX](https://github.com/craftcms/cms/pull/XXXXX)) +- Deprecated the `Craft.LightSwitch`, `Craft.InfoIcon`, `Craft.ColorInput`, `Craft.PasswordInput`, `Craft.IconPicker`, `Craft.SlidePicker`, `Craft.SlideRuleInput`, and `Craft.Tooltip` control panel JavaScript classes, along with the `.infoicon` jQuery plugin. The corresponding `@craftcms/ui` web components should be used instead. + ### Drafts - Deprecated `craft\services\Drafts`. `CraftCms\Cms\Element\Drafts` should be used instead. diff --git a/packages/craftcms-legacy/cp/src/Craft.js b/packages/craftcms-legacy/cp/src/Craft.js index 622c9f7b839..cdf0dd66739 100644 --- a/packages/craftcms-legacy/cp/src/Craft.js +++ b/packages/craftcms-legacy/cp/src/Craft.js @@ -18,7 +18,6 @@ import './js/BaseElementIndex.js'; import './js/BaseElementIndexView.js'; import './js/BaseElementSelectInput.js'; import './js/BaseElementSelectorModal.js'; -import './js/BaseInputGenerator.js'; import './js/BaseUploader.js'; // Modals @@ -31,7 +30,6 @@ import './js/Tabs.js'; import './js/ElementThumbLoader.js'; // Finally load the remaining files -import './js/Accordion'; import './js/AdminTable.js'; import './js/AssetImageEditor.js'; import './js/AssetIndex.js'; @@ -44,13 +42,11 @@ import './js/CP.js'; import './js/CardsElementIndexView.js'; import './js/CategoryIndex.js'; import './js/Chart.js'; -import './js/ColorInput.js'; import './js/ComponentSelectInput.js'; import './js/ContentBlockEditor.js'; import './js/CustomizeSourcesModal.js'; import './js/DataTableSorter.js'; import './js/DeleteUserModal.js'; -import './js/DynamicGenerator.js'; import './js/ElementActionTrigger.js'; import './js/ElementDeletionManager.js'; import './js/ElementEditor.js'; @@ -58,38 +54,26 @@ import './js/ElementFieldSettings.js'; import './js/ElementTableSorter.js'; import './js/EntryIndex.js'; import './js/EntrySelectInput.js'; -import './js/EnvVarGenerator.js'; import './js/EntryMover.js'; import './js/FormObserver.js'; import './js/VolumeFolderSelectorModal.js'; -import './js/FieldToggle.js'; import './js/Grid.js'; -import './js/HandleGenerator.js'; -import './js/IconPicker.js'; import './js/ImageUpload.js'; -import './js/InfoIcon.js'; import './js/IntervalManager.js'; -import './js/LightSwitch.js'; import './js/LinkField.js'; import './js/LinkInput.js'; import './js/LivePreview.js'; import './js/NestedElementManager.js'; -import './js/PasswordInput.js'; import './js/Preview.js'; import './js/PreviewFileModal.js'; import './js/ProgressBar.js'; import './js/PromptHandler.js'; -import './js/SlidePicker.js'; -import './js/SlideRuleInput.js'; -import './js/SlugGenerator.js'; import './js/Structure.js'; import './js/StructureDrag.js'; import './js/TableElementIndexView.js'; import './js/TagSelectInput.js'; import './js/ThumbsElementIndexView.js'; -import './js/Tooltip.js'; import './js/Uploader.js'; -import './js/UriFormatGenerator.js'; import './js/UserIndex.js'; // Custom elements diff --git a/packages/craftcms-legacy/cp/src/css/_image_editor.scss b/packages/craftcms-legacy/cp/src/css/_image_editor.scss index abfe680c1d0..72988c3625f 100755 --- a/packages/craftcms-legacy/cp/src/css/_image_editor.scss +++ b/packages/craftcms-legacy/cp/src/css/_image_editor.scss @@ -344,143 +344,6 @@ html.noscroll body { margin-block-end: 0; } -/* Slide Rule */ - -.slide-rule { - position: relative; - padding-block: 10px; - padding-inline: 0; - - &:focus-visible { - .cursor::after { - box-shadow: var(--focus-ring); - } - } - - .cursor { - &::after { - content: ''; - width: calc(20 / 16 * 1rem); - height: calc(50 / 16 * 1rem); - position: absolute; - inset-block-start: -15px; - inset-inline-start: 50%; - transform: translateX(-50%); - } - } -} - -.slide-rule .cursor { - position: absolute; - margin-inline-start: calc(-4 / 16 * 1rem); - margin-block-start: 4px; - inset-inline-start: 50%; - z-index: 1; - width: 0; - height: 0; - border-inline-start: calc(5 / 16 * 1rem) solid transparent; - border-inline-end: calc(5 / 16 * 1rem) solid transparent; - border-block-start: calc(5 / 16 * 1rem) solid #63a6e1; -} - -.slide-rule .graduations { - white-space: nowrap; - height: 40px; - position: relative; -} - -.slide-rule .graduations ul { - position: relative; - float: inline-start; - height: 40px; - - /* We need to use "left" vs. a logical property here because that's wha the JS sets */ - transition: 200ms left linear; /* stylelint-disable-line */ -} - -.slide-rule.dragging .graduations ul { - transition: none; -} - -.slide-rule .graduations ul li { - display: inline-block; - font-size: 8px; - position: relative; - width: 10px; - - &:hover { - cursor: pointer; - - &::before { - border-inline-start-color: #63a6e1; - } - } -} - -.slide-rule .graduations ul li:not(.main-graduation) { - inset-inline-start: 1px; -} - -.slide-rule .graduations ul li.main-graduation::before { - border-inline-start-width: 4px; - height: 10px; -} - -.slide-rule .graduations ul li.main-graduation .label { - display: block; - cursor: default; -} - -.slide-rule .graduations ul li.selected::before { - border-inline-start-color: #63a6e1; -} - -.slide-rule .graduations ul li::before { - content: ''; - position: absolute; - border-inline-start: 2px solid var(--white); - height: 6px; - inset-block-start: 0; - inset-inline-start: 0; -} - -.slide-rule .graduations ul li .label { - width: 20px; - position: absolute; - inset-block-start: 10px; - inset-inline-start: -9px; - display: none; - text-align: center; -} - -.slide-rule .value { - display: none; - position: absolute; - inset-block-end: 0; - inset-inline-start: 50%; - z-index: 1; - box-sizing: border-box; - padding: 5px; - width: 50px; - margin-inline-start: -25px; - background: var(--gray-600); -} - -.slide-rule .overlay { - z-index: 2; - position: absolute; - inset-block: 0 1px; - inset-inline: 0; - pointer-events: none; - background-image: linear-gradient( - to right, - var(--gray-900) 0%, - color.adjust(mixins.$grey900, $alpha: -1) 15%, - color.adjust(mixins.$grey900, $alpha: -1) 85%, - var(--gray-900) 100% - ); -} - /* Misc */ .menu.dark { diff --git a/packages/craftcms-legacy/cp/src/css/_main.scss b/packages/craftcms-legacy/cp/src/css/_main.scss index 0e23ec74f40..e62d8b2fcc0 100644 --- a/packages/craftcms-legacy/cp/src/css/_main.scss +++ b/packages/craftcms-legacy/cp/src/css/_main.scss @@ -8126,67 +8126,6 @@ body { cursor: default; } -/* slide picker */ -.slide-picker { - display: flex; - height: 1rem; - white-space: nowrap; - - a { - position: relative; - border: 1px solid var(--border-hairline); - border-inline-start: none; - background-image: none; - width: calc(8rem / 16 - 1px); - height: calc(1rem - 2px); - margin-inline-start: 0; - margin-block: 1px; - box-sizing: border-box; - cursor: pointer; - - &:first-child { - width: calc(8rem / 16); - border-inline-start: 1px solid var(--gray-400) !important; - } - - &::before { - content: ''; - position: absolute; - inset-block-start: calc(-4rem / 16 - 1px); - inset-inline-start: -1px; - width: calc(100% + 2px); - height: var(--touch-target-size); - } - } - - &:not(:hover) a.active, - &:hover a.active-hover { - border-block-start-color: var(--gray-400); - border-block-end-color: var(--gray-400); - height: 1rem; - margin-block: 0; - - &:first-child { - border-inline-start: 1px solid var(--gray-400); - border-start-start-radius: var(--radius-sm); - border-end-start-radius: var(--radius-sm); - } - } - - &:not(:hover) a.last-active, - &:hover a.last-active-hover { - border-inline-end: 1px solid var(--gray-400); - border-start-end-radius: var(--radius-sm); - border-end-end-radius: var(--radius-sm); - } - - &:focus { - a.active { - background-color: var(--bg-selection-light); - } - } -} - /* errors */ ul.errors { margin-block-start: 5px; diff --git a/packages/craftcms-legacy/cp/src/js/Accordion.js b/packages/craftcms-legacy/cp/src/js/Accordion.js deleted file mode 100644 index b8aa8f76e12..00000000000 --- a/packages/craftcms-legacy/cp/src/js/Accordion.js +++ /dev/null @@ -1,130 +0,0 @@ -/** global: Craft */ -/** global: Garnish */ -/** - * Accordion - */ -Craft.Accordion = Garnish.Base.extend({ - $trigger: null, - targetSelector: null, - - _$target: null, - - init: function (trigger) { - this.$trigger = $(trigger); - - // Is this already an accordion trigger? - if (this.$trigger.data('accordion')) { - console.warn('Double-instantiating an accordion trigger on an element'); - this.$trigger.data('accordion').destroy(); - } - - this.$trigger.data('accordion', this); - this.targetSelector = this.$trigger.attr('aria-controls') - ? `#${this.$trigger.attr('aria-controls')}` - : null; - - if (this.targetSelector) { - this._$target = $(this.targetSelector); - } - - this.addListener(this.$trigger, 'click', 'onTriggerClick'); - this.addListener(this.$trigger, 'keypress', (event) => { - const key = event.keyCode; - - if (key === Garnish.SPACE_KEY || key === Garnish.RETURN_KEY) { - event.preventDefault(); - this.onTriggerClick(); - } - }); - }, - - onTriggerClick: function () { - const isOpen = this.$trigger.attr('aria-expanded') === 'true'; - - if (isOpen) { - this.hideTarget(this._$target); - } else { - this.showTarget(this._$target); - } - }, - - showTarget: function ($target) { - if ($target && $target.length) { - this.showTarget._currentHeight = $target.height(); - - $target.removeClass('hidden'); - - this.$trigger - .removeClass('collapsed') - .addClass('expanded') - .attr('aria-expanded', 'true'); - - for (let i = 0; i < $target.length; i++) { - (($t) => { - if ($t.prop('nodeName') !== 'SPAN') { - $t.height('auto'); - this.showTarget._targetHeight = $t.height(); - $t.css({ - height: this.showTarget._currentHeight, - overflow: 'hidden', - }); - - $t.velocity('stop'); - - $t.velocity( - {height: this.showTarget._targetHeight}, - Garnish.getUserPreferredAnimationDuration('fast'), - function () { - $t.css({ - height: '', - overflow: '', - }); - } - ); - } - })($target.eq(i)); - } - - delete this.showTarget._targetHeight; - delete this.showTarget._currentHeight; - - // Trigger a resize event in case there are any grids in the target that need to initialize - Garnish.$win.trigger('resize'); - } - }, - - hideTarget: function ($target) { - if ($target && $target.length) { - this.$trigger - .removeClass('expanded') - .addClass('collapsed') - .attr('aria-expanded', 'false'); - - for (let i = 0; i < $target.length; i++) { - (($t) => { - if ($t.hasClass('hidden')) { - return; - } - if ($t.prop('nodeName') === 'SPAN') { - $t.addClass('hidden'); - } else { - $t.css('overflow', 'hidden'); - $t.velocity('stop'); - $t.velocity( - {height: 0}, - Garnish.getUserPreferredAnimationDuration('fast'), - function () { - $t.addClass('hidden'); - } - ); - } - })($target.eq(i)); - } - } - }, - - destroy: function () { - this.$trigger.removeData('accordion'); - this.base(); - }, -}); diff --git a/packages/craftcms-legacy/cp/src/js/AssetImageEditor.js b/packages/craftcms-legacy/cp/src/js/AssetImageEditor.js index f26eadfa355..e2f505e5d48 100644 --- a/packages/craftcms-legacy/cp/src/js/AssetImageEditor.js +++ b/packages/craftcms-legacy/cp/src/js/AssetImageEditor.js @@ -929,18 +929,18 @@ Craft.AssetImageEditor = Garnish.Modal.extend( } }); - // Straighten slider - this.straighteningInput = new Craft.SlideRuleInput('slide-rule', { - onStart: () => { - this._showGrid(); - }, - onChange: (slider) => { - this.straighten(slider); - }, - onEnd: () => { - this._hideGrid(); - this._cleanupFocalPointAfterStraighten(); - }, + // Straighten slider — the web component (replaces the + // legacy Craft.SlideRuleInput), driven via its start/change/end events. + this.straighteningInput = document.getElementById('slide-rule'); + this.straighteningInput.addEventListener('start', () => { + this._showGrid(); + }); + this.straighteningInput.addEventListener('change', () => { + this.straighten(this.straighteningInput); + }); + this.straighteningInput.addEventListener('end', () => { + this._hideGrid(); + this._cleanupFocalPointAfterStraighten(); }); // Cropper scale modifier key @@ -1406,7 +1406,7 @@ Craft.AssetImageEditor = Garnish.Modal.extend( } var editorCenter = {x: this.editorWidth / 2, y: this.editorHeight / 2}; - this.straighteningInput.setValue(-this.imageStraightenAngle); + this.straighteningInput.value = -this.imageStraightenAngle; this.imageStraightenAngle = -this.imageStraightenAngle; var properties = { angle: this.viewportRotation + this.imageStraightenAngle, @@ -1482,7 +1482,7 @@ Craft.AssetImageEditor = Garnish.Modal.extend( /** * Perform the straightening with input slider. * - * @param {Craft.SlideRuleInput} slider + * @param {HTMLElement} slider The element (reads `.value`). */ straighten: function (slider) { if (!this.animationInProgress) { @@ -1966,7 +1966,8 @@ Craft.AssetImageEditor = Garnish.Modal.extend( */ hide: function () { this.removeAllListeners(); - this.straighteningInput.removeAllListeners(); + // The component manages its own listeners; the editor's + // start/change/end handlers persist with the element. Garnish.$bod.removeClass('no-scroll'); this.base(); }, diff --git a/packages/craftcms-legacy/cp/src/js/BaseInputGenerator.js b/packages/craftcms-legacy/cp/src/js/BaseInputGenerator.js deleted file mode 100644 index 7ac68a76899..00000000000 --- a/packages/craftcms-legacy/cp/src/js/BaseInputGenerator.js +++ /dev/null @@ -1,125 +0,0 @@ -/** global: Craft */ -/** global: Garnish */ -/** - * Input Generator - */ -Craft.BaseInputGenerator = Garnish.Base.extend( - { - $source: null, - $target: null, - $form: null, - settings: null, - - listening: null, - sourceVal: null, - - init: function (source, target, settings) { - this.$source = $(source); - this.$target = $(target); - this.$form = this.$source.closest('form'); - - this.setSettings(settings, Craft.BaseInputGenerator.defaults); - this.setSettings(settings); - - this.startListening(); - }, - - setNewSource: function (source) { - var listening = this.listening; - this.stopListening(); - - this.$source = $(source); - - if (listening) { - this.startListening(); - } - }, - - startListening: function () { - if (this.listening) { - return; - } - - this.listening = true; - this.sourceVal = this.$source.val(); - - this.addListener(this.$source, 'input', 'onSourceTextChange'); - this.addListener(this.$target, 'input', 'onTargetTextChange'); - this.addListener(this.$form, 'submit', 'updateTarget'); - }, - - stopListening: function () { - if (!this.listening) { - return; - } - - this.listening = false; - - this.removeAllListeners(this.$source); - this.removeAllListeners(this.$target); - this.removeAllListeners(this.$form); - }, - - onSourceTextChange: function () { - const val = this.$source.val(); - if (this.sourceVal !== (this.sourceVal = val)) { - this.updateTarget(); - } - }, - - onTargetTextChange: function () { - if (this.$target.get(0) === document.activeElement) { - this.stopListening(); - } - }, - - updateTarget: function () { - if ( - !this.$target.is(':visible') && - this.settings.updateWhenHidden == false - ) { - return; - } - - var sourceVal = this.$source.val(); - - if (typeof sourceVal === 'undefined') { - // The source input may not exist anymore - return; - } - - let targetVal = this.generateTargetValue(sourceVal); - if (targetVal) { - targetVal = `${this.settings.prefix}${targetVal}${this.settings.suffix}`; - } - - this.$target.val(targetVal); - - for (let i = 0; i < this.$target.length; i++) { - this.$target[i].dispatchEvent( - new InputEvent('input', { - inputType: 'insertText', - }) - ); - this.$target[i].dispatchEvent(new Event('input')); - } - - // If the target already has focus, select its whole value to mimic - // the behavior if the value had already been generated and they just tabbed in - if (this.$target.is(':focus')) { - Craft.selectFullValue(this.$target); - } - }, - - generateTargetValue: function (sourceVal) { - return sourceVal; - }, - }, - { - defaults: { - updateWhenHidden: false, - prefix: '', - suffix: '', - }, - } -); diff --git a/packages/craftcms-legacy/cp/src/js/ColorInput.js b/packages/craftcms-legacy/cp/src/js/ColorInput.js deleted file mode 100644 index 06084818bab..00000000000 --- a/packages/craftcms-legacy/cp/src/js/ColorInput.js +++ /dev/null @@ -1,130 +0,0 @@ -/** global: Craft */ -/** global: Garnish */ -/** - * Color input - */ -Craft.ColorInput = Garnish.Base.extend( - { - $container: null, - $input: null, - $colorContainer: null, - $colorPreview: null, - $colorInput: null, - - init: function (container, settings) { - this.setSettings(settings, Craft.ColorInput.defaults); - - this.$container = $(container); - this.$input = this.$container.find('.color-input'); - this.$colorContainer = this.$container.children('.color'); - this.$colorPreview = this.$colorContainer.children('.color-preview'); - - this.createColorInput(); - this.handleTextChange(); - - this.addListener(this.$input, 'input', 'handleTextChange'); - }, - - createColorInput: function () { - var input = document.createElement('input'); - input.setAttribute('type', 'color'); - - if (input.type !== 'color') { - // The browser doesn't support input[type=color] - return; - } - - let isDisabled = false; - if (this.$container.parents('.input').hasClass('disabled')) { - isDisabled = true; - } - this.$colorContainer.removeClass('static'); - this.$colorInput = $(input) - .addClass('color-preview-input') - .attr({ - 'aria-controls': this.$input.attr('id'), - 'aria-label': Craft.t('app', 'Color picker'), - 'aria-labelledby': this.$input.attr('aria-labelledby'), - }) - .appendTo(this.$colorPreview); - - if (isDisabled) { - this.$colorInput.attr('disabled', ''); - } - - if (this.settings.presets?.length) { - const listId = `listbox-${Math.floor(Math.random() * 1000000)}`; - this.$colorInput.attr('list', listId); - const $list = $('', { - id: listId, - }).insertAfter(this.$colorInput); - for (const color of this.settings.presets) { - $('