--- /dev/null
+import Sortable from 'sortablejs';
+
+function LinkeditorAccessibility(linkeditor) {
+ this.linkeditor = linkeditor;
+ this.interactiveThreshold = 5;
+ this.nonInteractiveTypes = [14, 15, 39];
+}
+
+LinkeditorAccessibility.prototype = {
+ init: function () {
+ var $this = this;
+
+ 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');
+ tippy.setContent(TRANSLATIONS.id_copied);
+ tippy.show();
+ return false;
+ });
+
+ this.update();
+ },
+
+ reorderSelection: function (way) {
+ 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();
+ let num = selection.length;
+ if (num <= 0) {
+ return;
+ }
+ let firstSelected = $(selection).get(0);
+ let firstSelectedOrder = parseFloat($(firstSelected).attr('fb-order'));
+ let max = this.getOrderableLinksOnPage().length + 1;
+
+ let step = 1 / (num + 1);
+
+ switch (way) {
+ case'start':
+ start = -num;
+ break;
+ case'end':
+ start = max;
+ break;
+ case'up':
+ start = firstSelectedOrder - 1 - step;
+ break;
+ case'down':
+ start = firstSelectedOrder + 1 + step;
+ break;
+ }
+
+ let selectedOrder = start;
+
+ $(selection).each(function () {
+ $(this).attr('fb-order', selectedOrder);
+ selectedOrder += step;
+ });
+
+ this.normalizeLinksOrder();
+ },
+
+ 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 $this = this;
+ let res = [];
+ $.each(links, function () {
+ if ($this.isInteractive(this)) {
+ res.push(this);
+ }
+ });
+
+ return this.orderLinks(res);
+ },
+
+ isInteractive: function (link) {
+ link = $(link);
+ if (link.attr('fb-calc-depth') < this.interactiveThreshold * 10) {
+ return false;
+ }
+ if (this.nonInteractiveTypes.indexOf(parseInt(link.attr('fb-type'))) > -1) {
+ return false;
+ }
+ let x = parseFloat(link.attr('fb-left'));
+ let y = parseFloat(link.attr('fb-top'));
+ let w = parseFloat(link.attr('fb-width'));
+ let h = parseFloat(link.attr('fb-height'));
+ if (x > this.linkeditor.fw || y > this.linkeditor.fh) {
+ return false;
+ }
+ if (x + w < 0 || y + h < 0) {
+ return false;
+ }
+ return true;
+
+ },
+
+ orderLinks: function (links) {
+ 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 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;
+ pa++;
+ }
+ if (xb >= pw) {
+ xb -= pw;
+ pb++;
+ }
+ if (pa !== pb) {
+ return pa - pb;
+ }
+ }
+
+
+ let wa = ca.width;
+ let wb = cb.width;
+
+ let xTolerance = Math.min(wa, wb) / 2;
+
+ let ha = ca.height;
+ let hb = cb.height;
+
+ let yTolerance = Math.min(ha, hb) / 2;
+
+ xa += wa / 2;
+ xb += wb / 2;
+
+ let ya = ca.y + ha / 2;
+ let yb = cb.y + hb / 2;
+
+ let xdiff = xa - xb;
+ let ydiff = ya - yb;
+
+ if (way === 'columns') {
+ return Math.abs(xdiff) > xTolerance ? xdiff : ydiff;
+ } else if (way === 'lines') {
+ return Math.abs(ydiff) > yTolerance ? ydiff : xdiff;
+ }
+ });
+ },
+
+ 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());
+ },
+
+ normalizeLinksOrder: function (refresh) {
+ if (refresh === undefined) {
+ refresh = true;
+ }
+ let $this = this;
+ let links = [];
+ $('#linkeditor-links .link:not(.pendingCreate)').each(function () {
+ links.push({
+ link: $(this),
+ interactive: $this.isInteractive($(this)),
+ order: parseFloat($(this).attr('fb-order'),)
+ });
+ });
+
+ links.sort(function (a, b) {
+ if (a.interactive === b.interactive) {
+ return a.order - b.order
+ }
+ return b.interactive - a.interactive;
+ });
+
+ let i = 0;
+ let wrapper = $("#linkeditor-links");
+ $(links).each(function (k, v) {
+ $(v.link).attr('fb-order', i++);
+ $(v.link).attr('fb-orderable', v.interactive ? '1' : '0');
+ $(wrapper).append($(v.link));
+ });
+
+ if (refresh) {
+ this.linkeditor.links.updateLinksData(links, ['order']);
+ this.linkeditor.hasChanged();
+ }
+ this.linkeditor.links.pageMaxOrderIndex = i;
+ },
+
+ getLinkLevel: function (link) {
+ let d = parseInt($(link).attr('fb-calc-depth'));
+ var m = 1;
+ if (d >= 30 && d < this.interactiveThreshold * 10) {
+ m = 10;
+ }
+ return Math.floor((m * d) / 10) / m;
+ },
+
+ update: function () {
+ if (this.container === undefined) {
+ return;
+ }
+ if (!this.container.hasClass('open')) {
+ return;
+ }
+ var $this = this;
+ this.container.addClass('toolbar-top').addClass('toolbar-bottom');
+ this.container.html(this.getTopToolbar() + '<div class="linkeditor-panel-wrapper"></div>');
+ let wrapper = this.container.find('.linkeditor-panel-wrapper');
+ var accessibility = [];
+ this.normalizeLinksOrder(false);
+ $(this.orderLinks(this.linkeditor.links.getLinksOfCurrentPage())).each(function () {
+ let type = $(this).attr('fb-type');
+ let dest = $(this).attr('fb-to');
+ let uid = $(this).attr('fb-uid');
+ let interactive = $this.isInteractive($(this));
+
+ if (dest === '') {
+ dest = '<em>' + TRANSLATIONS.empty + '</em>';
+ }
+ var l = '<div class="layer" fb-type="' + type + '">';
+ l += '<input name="' + uid + '" type="checkbox"> ';
+ l += '<label class="layer" data-uid="' + uid + '">';
+ l += dest;
+ if (interactive) {
+ l += '<span class="order">#' + $(this).attr('fb-order') + '</span>';
+ l += '<span class="drag">' + getSpriteIcon('linkeditor-drag-drop') + '</span>';
+ }
+ l += '</label>';
+ l += '</div>';
+
+ accessibility.push({
+ interactive: interactive,
+ zindex: parseInt($(this).attr('fb-calc-zindex')),
+ html: l,
+ order: parseInt($(this).attr('fb-order')),
+ });
+ });
+
+ accessibility.sort(function (a, b) {
+ if (a.interactive === b.interactive) {
+ return a.order - b.order
+ }
+ return b.interactive - a.interactive;
+ });
+
+ var seenLevels = {};
+ $.each(accessibility, function (k, v) {
+ let wrapperClass = 'order' + (v.interactive ? '-interactive' : '-noninteractive') + '-wrapper';
+ if (seenLevels[v.interactive] === undefined) {
+ seenLevels[v.interactive] = true;
+ wrapper.append('<h3>' + (v.interactive ? TRANSLATIONS.interactive_links : TRANSLATIONS.noninteractive_links) + '</h3><div class="' + wrapperClass + '"></div>');
+ }
+ $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 = '<div class="linkeditor-toolbar linkeditor-panel-toolbar linkeditor-panel-toolbar-top"><nav>';
+ res += '<a href="#" data-icon="order-horizontal" data-action="accessibility.reorderPageLinks" data-action-args="lines" data-tooltip="' + TRANSLATIONS.order_page_lines + '"></a>';
+ res += '<a href="#" data-icon="order-vertical" data-action="accessibility.reorderPageLinks" data-action-args="columns" data-tooltip="' + TRANSLATIONS.order_page_columns + '"></a>';
+ res += '<div class="separator"></div>';
+ res += '<a href="#" data-icon="order-horizontal-all" data-action="accessibility.reorderAllLinks" data-action-args="lines" data-tooltip="' + TRANSLATIONS.order_all_lines + '"></a>';
+ res += '<a href="#" data-icon="order-vertical-all" data-action="accessibility.reorderAllLinks" data-action-args="columns" data-tooltip="' + TRANSLATIONS.order_all_columns + '"></a>';
+ res += '</nav></div>';
+ return res;
+ },
+
+ getBottomToolbar: function () {
+ let res = '<div class="linkeditor-toolbar linkeditor-panel-toolbar linkeditor-panel-toolbar-bottom"><nav>';
+ res += '<a href="#" data-icon="order-horizontal" data-action="accessibility.reorderSelection" data-action-args="lines" data-tooltip="' + TRANSLATIONS.reorder_selection_lines + '"></a>';
+ res += '<a href="#" data-icon="order-vertical" data-action="accessibility.reorderSelection" data-action-args="columns" data-tooltip="' + TRANSLATIONS.reorder_selection_columns + '"></a>';
+ res += '<div class="separator"></div>';
+ res += '<a href="#" data-icon="move-start" data-action="accessibility.moveSelectionOrder" data-action-args="start" data-tooltip="' + TRANSLATIONS.move_order_start + '"></a>';
+ res += '<a href="#" data-icon="move-up" data-action="accessibility.moveSelectionOrder" data-action-args="up" data-tooltip="' + TRANSLATIONS.move_order_up + '"></a>';
+ res += '<a href="#" data-icon="move-down" data-action="accessibility.moveSelectionOrder" data-action-args="down" data-tooltip="' + TRANSLATIONS.move_order_down + '"></a>';
+ res += '<a href="#" data-icon="move-end" data-action="accessibility.moveSelectionOrder" data-action-args="end" data-tooltip="' + TRANSLATIONS.move_order_end + '"></a>';
+ res += '</nav></div>';
+ 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 () {
+
+ },
+}
+
+export default LinkeditorAccessibility;