From 61e201adb216d2a87bb6b470bc8019cbe84b4c87 Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Thu, 12 Jun 2025 18:00:45 +0200 Subject: [PATCH] wip #7467 @9 --- .../js/linkeditor.accessibility.js | 178 +++++++++++++++--- resources/linkeditor-stable/js/linkeditor.js | 1 + .../linkeditor-stable/js/linkeditor.links.js | 4 - .../linkeditor-stable/style/inc/_layers.sass | 11 ++ .../linkeditor-stable/style/inc/_panels.sass | 38 +++- .../linkeditor-stable/style/inc/_toolbar.sass | 24 ++- .../style/inc/_variables.sass | 3 + .../link_editor.blade.php | 14 +- .../link_editor_icons.blade.php | 8 + 9 files changed, 243 insertions(+), 38 deletions(-) diff --git a/resources/linkeditor-stable/js/linkeditor.accessibility.js b/resources/linkeditor-stable/js/linkeditor.accessibility.js index 1feab45f4..a5beef42c 100644 --- a/resources/linkeditor-stable/js/linkeditor.accessibility.js +++ b/resources/linkeditor-stable/js/linkeditor.accessibility.js @@ -1,3 +1,5 @@ +import Sortable from 'sortablejs'; + function LinkeditorAccessibility(linkeditor) { this.linkeditor = linkeditor; } @@ -9,6 +11,8 @@ LinkeditorAccessibility.prototype = { this.container = $("#linkeditor-panel-accessibility"); this.maskCheckEvents = false; + this.sortable = false; + $(document).on('click', '#linkeditor-panel-accessibility label span.uid', function () { navigator.clipboard.writeText($(this).attr('fb-uid')); let tippy = $(this).data('tippyinstance'); @@ -21,24 +25,51 @@ LinkeditorAccessibility.prototype = { }, reorderSelection: function (way) { - let selection = this.getCurrentOrderableSelection(); - let selectedOrder = parseInt($(selection).eq(0).attr('fb-order')); - selection = this.orderLinksByPosition(selection, way); - $(selection).each(function () { - $(this).attr('fb-order', selectedOrder++); + return this.reorderLinks(this.getCurrentOrderableSelection(), way); + }, + + reorderLinks: function (links, way) { + let selectedOrder = parseInt($(links).eq(0).attr('fb-order')); + links = this.orderLinksByPosition(links, way); + let step = 1 / (links.length + 1); + $(links).each(function () { + let s = selectedOrder += step; + $(this).attr('fb-order', s); }); this.normalizeLinksOrder(); }, + reorderPageLinks: function (way) { + return this.reorderLinks(this.getOrderableLinksOnPage(), way); + }, + + reorderAllLinks: function (way) { + let $this = this; + let step = this.linkeditor.single ? 1 : 2; + for (let i = 0; i < FLUIDBOOK_DATA.settings.pages; i += step) { + let o = 0; + let links = this.orderLinksByPosition(this.getOrderableLinksOnPage(i), way); + $.each(links, function (k, v) { + LINKS[v.uid].order = o++; + if (i === $this.linkeditor.getCurrentPage()) { + $('.link[fb-uid="' + v.uid + '"]').attr('fb-order', o); + } + }); + this.linkeditor.hasChanged(); + } + this.normalizeLinksOrder(true); + }, + moveSelectionOrder: function (way) { let start; let selection = this.getCurrentOrderableSelection(); + console.log(selection); let num = selection.length; if (num <= 0) { return; } let firstSelected = $(selection).get(0); - let firstSelectedOrder = parseInt($(firstSelected).attr('fb-order')); + let firstSelectedOrder = parseFloat($(firstSelected).attr('fb-order')); let max = this.getOrderableLinksOnPage().length + 1; let step = 1 / (num + 1); @@ -46,15 +77,12 @@ LinkeditorAccessibility.prototype = { switch (way) { case'start': start = -num; - step = -1; break; case'end': start = max; - step = 1; break; case'up': start = firstSelectedOrder - 1 - step; - step *= -1; break; case'down': start = firstSelectedOrder + 1 + step; @@ -71,10 +99,18 @@ LinkeditorAccessibility.prototype = { this.normalizeLinksOrder(); }, - getOrderableLinksOnPage: function () { - return this.filterOrderableLinks(this.linkeditor.links.getLinksOfCurrentPage()); + getOrderableLinksOnPage: function (page) { + let links; + if (page === undefined) { + links = this.linkeditor.links.getLinksOfCurrentPage(); + } else { + links = this.linkeditor.links.getLinksOfPage(page); + } + + return this.filterOrderableLinks(links); }, + filterOrderableLinks: function (links) { let res = []; $.each(links, function () { @@ -88,20 +124,28 @@ LinkeditorAccessibility.prototype = { }, orderLinks: function (links) { - return $(links).toArray().sort(function (a, b) { - return parseInt($(a).attr('fb-order')) - parseInt($(b).attr('fb-order')); + let arr = links; + if (links instanceof jQuery) { + arr = $(links).toArray(); + } + return arr.sort(function (a, b) { + return parseFloat($(a).attr('fb-order')) - parseFloat($(b).attr('fb-order')); }); }, orderLinksByPosition: function (links, way) { + let $this = this; let doublePage = !this.linkeditor.single && !this.linkeditor.utils.isSpecialPage(this.linkeditor.currentPage); let pw = this.linkeditor.pw; return $(links).toArray().sort(function (a, b) { - let pa = 0; - let pb = 0; - let xa = parseFloat($(a).attr('fb-left')); - let xb = parseFloat($(b).attr('fb-left')); + let ca = $this.getLinkDimensions(a); + let cb = $this.getLinkDimensions(b); + + let pa = ca.page; + let pb = cb.page; + let xa = ca.x; + let xb = cb.x; if (doublePage) { if (xa >= pw) { xa -= pw; @@ -117,21 +161,21 @@ LinkeditorAccessibility.prototype = { } - let wa = parseFloat($(a).attr('fb-width')); - let wb = parseFloat($(b).attr('fb-width')); + let wa = ca.width; + let wb = cb.width; let xTolerance = Math.min(wa, wb) / 2; - let ha = parseFloat($(a).attr('fb-height')); - let hb = parseFloat($(b).attr('fb-height')); + let ha = ca.height; + let hb = cb.height; let yTolerance = Math.min(ha, hb) / 2; xa += wa / 2; xb += wb / 2; - let ya = parseFloat($(a).attr('fb-top')) + ha / 2; - let yb = parseFloat($(b).attr('fb-top')) + hb / 2; + let ya = ca.y + ha / 2; + let yb = cb.y + hb / 2; let xdiff = xa - xb; let ydiff = ya - yb; @@ -144,6 +188,26 @@ LinkeditorAccessibility.prototype = { }); }, + getLinkDimensions: function (link) { + if (link.left !== undefined) { + return { + x: parseFloat(link.left), + y: parseFloat(link.top), + width: parseFloat(link.width), + height: parseFloat(link.height), + page: parseInt(link.page), + } + } else { + return { + x: parseFloat($(link).attr('fb-left')), + y: parseFloat($(link).attr('fb-top')), + width: parseFloat($(link).attr('fb-width')), + height: parseFloat($(link).attr('fb-height')), + page: $(link).attr('fb-page'), + }; + } + }, + getCurrentOrderableSelection: function () { return this.filterOrderableLinks(this.linkeditor.links.getCurrentSelection()); }, @@ -156,7 +220,7 @@ LinkeditorAccessibility.prototype = { let links = []; $('#linkeditor-links .link:not(.pendingCreate)').each(function () { let level = $this.getLinkLevel($(this)); - links.push({link: $(this), interactive: level >= 5, order: parseInt($(this).attr('fb-order'),)}); + links.push({link: $(this), interactive: level >= 5, order: parseFloat($(this).attr('fb-order'),)}); }); links.sort(function (a, b) { @@ -198,7 +262,9 @@ LinkeditorAccessibility.prototype = { return; } var $this = this; - this.container.html(''); + this.container.addClass('toolbar-top').addClass('toolbar-bottom'); + this.container.html(this.getTopToolbar() + '
'); + let wrapper = this.container.find('.linkeditor-panel-wrapper'); var accessibility = []; this.normalizeLinksOrder(false); $(this.orderLinks(this.linkeditor.links.getLinksOfCurrentPage())).each(function () { @@ -217,6 +283,7 @@ LinkeditorAccessibility.prototype = { l += dest; if (interactive) { l += '#' + $(this).attr('fb-order') + ''; + l += '' + getSpriteIcon('linkeditor-drag-drop') + ''; } l += ''; l += ''; @@ -238,20 +305,77 @@ LinkeditorAccessibility.prototype = { var seenLevels = {}; $.each(accessibility, function (k, v) { + let wrapperClass = 'order' + (v.interactive ? '-interactive' : '-noninteractive') + '-wrapper'; if (seenLevels[v.interactive] === undefined) { seenLevels[v.interactive] = true; - $this.container.append('

' + (v.interactive ? TRANSLATIONS.interactive_links : TRANSLATIONS.noninteractive_links) + '

'); + wrapper.append('

' + (v.interactive ? TRANSLATIONS.interactive_links : TRANSLATIONS.noninteractive_links) + '

'); } - $this.container.append(v.html); + $this.container.find('.' + wrapperClass).append(v.html); }); + this.container.append(this.getBottomToolbar()); + + let sortableWrapper = $('.order-interactive-wrapper').get(0); + try { + this.sortable.destroy(); + } catch (e) { + + } + if ($('.order-interactive-wrapper').length > 0) { + this.sortable = Sortable.create(sortableWrapper, { + handle: '.drag', onSort: function (e) { + let i = 0; + $(sortableWrapper).find('div.layer').each(function () { + let uid = $(this).find('label.layer').data('uid'); + let link = $('#linkeditor-links .link[fb-uid="' + uid + '"]'); + $(link).attr('fb-order', i++); + }); + $this.normalizeLinksOrder(); + }, + }); + } this.updateSelection(); this.linkeditor.initTooltips(); this.linkeditor.initIcons(); }, + getTopToolbar: function () { + let res = '
'; + return res; + }, + + getBottomToolbar: function () { + let res = '
'; + return res; + }, + updateSelection() { this.linkeditor.panels.updatePanelSelection(this); + let l=this.getCurrentOrderableSelection().length; + if(l<1){ + $('[data-action="accessibility.moveSelectionOrder"]').addClass('disabled'); + } else { + $('[data-action="accessibility.moveSelectionOrder"]').removeClass('disabled'); + } + if (l < 2) { + $('[data-action="accessibility.reorderSelection"]').addClass('disabled'); + } else { + $('[data-action="accessibility.reorderSelection"]').removeClass('disabled'); + } }, resize: function () { diff --git a/resources/linkeditor-stable/js/linkeditor.js b/resources/linkeditor-stable/js/linkeditor.js index 5d01caf46..b8aed2e40 100644 --- a/resources/linkeditor-stable/js/linkeditor.js +++ b/resources/linkeditor-stable/js/linkeditor.js @@ -3,6 +3,7 @@ import '../../../vendor/cubist/cms-back/src/public/bunchmultiple/bunchmultiplemo import Noty from "noty"; import GrahamScan from "@lucio/graham-scan"; + import LinkeditorLinks from './linkeditor.links'; import LinkeditorLoader from './linkeditor.loader'; import LinkeditorResize from './linkeditor.resize'; diff --git a/resources/linkeditor-stable/js/linkeditor.links.js b/resources/linkeditor-stable/js/linkeditor.links.js index f222a5dbb..98e6b05c5 100644 --- a/resources/linkeditor-stable/js/linkeditor.links.js +++ b/resources/linkeditor-stable/js/linkeditor.links.js @@ -976,12 +976,10 @@ LinkeditorLinks.prototype = { } let change = false; if (link.order === undefined) { - console.log('link.order is undefined', link); link.order = ++this.pageMaxOrderIndex; } else { this.pageMaxOrderIndex = Math.max(this.pageMaxOrderIndex, link.order); } - console.log(link.order); if (link.uid === undefined) { link.uid = this.linkeditor.utils.generateUID(); change = true; @@ -991,7 +989,6 @@ LinkeditorLinks.prototype = { if (change) { LINKS[link.uid] = link; } - link.origuid = link.uid; let $this = this; @@ -1255,7 +1252,6 @@ LinkeditorLinks.prototype = { uid = $(this).attr('fb-uid'); l = this; } - console.log(uid, props); for (let i = 0; i < props.length; i++) { let prop = props[i]; LINKS[uid][prop] = $(l).attr('fb-' + prop); diff --git a/resources/linkeditor-stable/style/inc/_layers.sass b/resources/linkeditor-stable/style/inc/_layers.sass index 92495968b..a7b1b3cd3 100644 --- a/resources/linkeditor-stable/style/inc/_layers.sass +++ b/resources/linkeditor-stable/style/inc/_layers.sass @@ -20,6 +20,12 @@ .layer position: relative + &.sortable-ghost + opacity: 0.4 + + &.sortable-drag + visibility: hidden + input color: #fff position: absolute @@ -58,6 +64,11 @@ padding: 2px font-family: "Courier New", Courier, monospace + &.drag + right: 5px + width: 16px + cursor: grab + &[data-locked="1"] label pointer-events: none diff --git a/resources/linkeditor-stable/style/inc/_panels.sass b/resources/linkeditor-stable/style/inc/_panels.sass index 5509acafd..02552f13d 100644 --- a/resources/linkeditor-stable/style/inc/_panels.sass +++ b/resources/linkeditor-stable/style/inc/_panels.sass @@ -6,7 +6,7 @@ @include dark-theme background-color: #444 - nav + > nav position: absolute left: 0 width: $sidebar-icons-width @@ -69,6 +69,7 @@ .linkeditor-panel display: none + &.open display: block @@ -89,3 +90,38 @@ .linkeditor-panel-side margin-left: $sidebar-handle-width margin-right: $sidebar-icons-width + +.linkeditor-panel-wrapper + position: relative + max-height: 100% + overflow: scroll + +.linkeditor-panel + position: relative + height: 100% + + &.toolbar-top + .linkeditor-panel-wrapper + top: 40px + max-height: calc(100% - 40px) + + &.toolbar-bottom + .linkeditor-panel-wrapper + bottom: 40px + max-height: calc(100% - 40px) + + &.toolbar-bottom.toolbar-top + .linkeditor-panel-wrapper + max-height: calc(100% - 80px) + +.linkeditor-panel-toolbar + position: fixed + left: 0 + width: 100% + height: 40px + + .linkeditor-panel-toolbar-top + top: 0 + + .linkeditor-panel-toolbar-bottom + bottom: 0 diff --git a/resources/linkeditor-stable/style/inc/_toolbar.sass b/resources/linkeditor-stable/style/inc/_toolbar.sass index e017ce1ec..edf175810 100644 --- a/resources/linkeditor-stable/style/inc/_toolbar.sass +++ b/resources/linkeditor-stable/style/inc/_toolbar.sass @@ -1,8 +1,8 @@ -#linkeditor-toolbar - background-color: #dbdddf +.linkeditor-toolbar + background-color: $toolbar-background-color @include dark-theme - background-color: #444 + background-color: $toolbar-background-color-dark color: $toolbar-color @include dark-theme @@ -11,7 +11,6 @@ height: $toolbar-height padding: 5px - nav padding: 2px display: inline-block @@ -123,3 +122,20 @@ top: 1px height: 18px width: auto + + &.linkeditor-panel-toolbar + position: absolute + left: 0 + background-color: darken($toolbar-background-color, 5%) + + nav + width: 100% + + @include dark-theme + background-color: lighten($toolbar-background-color-dark, 5%) + + &.linkeditor-panel-toolbar-top + top: 0 + + &.linkeditor-panel-toolbar-bottom + bottom: 0 diff --git a/resources/linkeditor-stable/style/inc/_variables.sass b/resources/linkeditor-stable/style/inc/_variables.sass index 2246963c8..d5be2e69d 100644 --- a/resources/linkeditor-stable/style/inc/_variables.sass +++ b/resources/linkeditor-stable/style/inc/_variables.sass @@ -9,6 +9,9 @@ $toolbar-height: 40px $toolbar-color: #5d5d5d $toolbar-color-dark: #bbb +$toolbar-background-color: #dbdddf +$toolbar-background-color-dark: #444 + $toolbar-color-disabled: #bbb $toolbar-color-disabled-dark: #666 diff --git a/resources/views/fluidbook_publication/link_editor.blade.php b/resources/views/fluidbook_publication/link_editor.blade.php index f19b666fb..f60480906 100644 --- a/resources/views/fluidbook_publication/link_editor.blade.php +++ b/resources/views/fluidbook_publication/link_editor.blade.php @@ -88,10 +88,20 @@ 'reorder_selection'=>__('Réordonner la sélection'), 'reorder_lines'=>__('Par lignes'), 'reorder_columns'=>__('Par colonnes'), + 'reorder_selection_lines'=>__('Réordonner la sélection par lignes'), + 'reorder_selection_columns'=>__('Réordonner la sélection par colonnes'), + 'move_order_start'=>__('Déplacer la sélection au début'), + 'move_order_up'=>__('Remonter la sélection'), + 'move_order_down'=>__('Descendre la sélection'), + 'move_order_end'=>__('Déplacer la sélection à la fin'), 'move_up'=>__('Avant'), 'move_down'=>__('Après'), 'move_beginning'=>__('Au début'), 'move_end'=>__('À la fin'), + 'order_all_lines'=>__('Réordonner les liens de toute la publication par lignes'), + 'order_all_columns'=>__('Réordonner les liens de toute la publication par colonnes'), + 'order_page_lines'=>__('Réordonner les liens de la page par lignes'), + 'order_page_columns'=>__('Réordonner les liens de la page par colonnes'), 'select_all'=>__('Tout sélectionner'), 'error_open_image_link'=>__('Impossible d\'ajouter des liens au contenu de ce lien'), 'empty'=>__('Vide'), @@ -242,7 +252,7 @@
-
+