diff options
| author | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2024-06-24 13:32:09 +0000 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2024-06-24 13:32:09 +0000 |
| commit | 50371cbb71065fe95dbcef52d79e13d3db1ccb41 (patch) | |
| tree | 5843bb3ff74f347c08a05a0e6c73ed464ccbdc84 /resources/assets/javascripts/lib | |
| parent | 64e35ff574d272d9bf22e2dcd45d37498159db4a (diff) | |
add aria-label to all tooltips and align usage in vue as well, fixes #4330
Closes #4330
Merge request studip/studip!3132
Diffstat (limited to 'resources/assets/javascripts/lib')
| -rw-r--r-- | resources/assets/javascripts/lib/tooltip.js | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/resources/assets/javascripts/lib/tooltip.js b/resources/assets/javascripts/lib/tooltip.js new file mode 100644 index 0000000..2cdac27 --- /dev/null +++ b/resources/assets/javascripts/lib/tooltip.js @@ -0,0 +1,227 @@ +import CSS from './css.js'; + +/** + * Tooltip library for Stud.IP + * + * @author Jan-Hendrik Willms <tleilax+studip@gmail.com> + * @copyright Stud.IP Core Group 2014 + * @license GPL2 or any later version + * @since Stud.IP 3.1 + */ + +let count = 0; +let threshold = 0; + +class Tooltip { + static get count() { + return count; + } + + static set count(value) { + count = value; + } + + // Threshold used for "edge detection" (imagine a padding along the edges) + static get threshold() { + return threshold; + } + + static set threshold(value) { + threshold = value; + } + + /** + * Returns a new unique id of a tooltip. + * + * @return {string} Unique id + * @static + */ + static getId() { + const id = `studip-tooltip-${Tooltip.count}`; + Tooltip.count += 1; + return id; + } + + /** + * Constructs a new tooltip at given location with given content. + * The applied css class may be changed by the fourth parameter. + * + * @class + * @classdesc Stud.IP tooltips provide an improved layout and handling + * of contents (including html) than the browser's default + * tooltip through title attribute would + * + * @param {int} x - Horizontal position of the tooltip + * @param {int} y - Vertical position of the tooltip + * @param {string} content - Content of the tooltip (may be html) + * @param {string} css_class - Optional name of the applied css class / + * defaults to 'studip-tooltip' + */ + constructor(x, y, content, css_class) { + // Obtain unique id of the tooltip + this.id = Tooltip.getId(); + + // Create dom element of the tooltip, apply id and class and attach + // to dom + this.element = $('<div>'); + this.element.addClass(css_class || 'studip-tooltip'); + this.element.attr('id', this.id); + this.element.attr('role', 'tooltip'); + this.element.appendTo('body'); + + // Set position and content and paint the tooltip + this.position(x, y); + this.update(content); + this.paint(); + } + + /** + * Translates the arrow(s) under a tooltip using css3 translate + * transforms. This is needed at the edges of the screen. + * This implies that a current browser is used. The translation could + * also be achieved by adjusting margins but that way we would need + * to hardcode values into this function since it's a struggle to + * obtain the neccessary values from the CSS pseudo selectors in JS. + * + * Internal, css rules are dynamically created and applied to the current + * document by using the methods provided in the file studip-css.js. + * + * @param {int} x - Horizontal offset + * @param {int} y - Vertical offset + */ + translateArrows(x, y, left_arrow = false) { + CSS.removeRule(`#${this.id}::before`); + CSS.removeRule(`#${this.id}::after`); + + if (x !== 0 || y !== 0) { + let before_rule = { + transform: `translate(${x}px, ${y}px);` + }; + if (left_arrow) { + before_rule.transform = `translate(${x}px, ${y}px) rotate(90deg);`; + } + let after_rule = before_rule; + if (left_arrow) { + after_rule['border-width'] = '9px'; + } + CSS.addRule(`#${this.id}::before`, before_rule, ['-ms-', '-webkit-']); + CSS.addRule(`#${this.id}::after`, after_rule, ['-ms-', '-webkit-']); + } + } + + /** + * Updates the position of the tooltip. + * + * @param {int} x - Horizontal position of the tooltip + * @param {int} y - Vertical position of the tooltip + */ + position(x, y) { + this.x = x; + this.y = y; + } + + /** + * Updates the contents of the tooltip. + * + * @param {string} content - Content of the tooltip (may be html) + */ + update(content) { + this.element.html(content); + } + + /** + * "Paints" the tooltip. This method actually computes the dimensions of + * the tooltips, checks for screen edges and calculates the actual offset + * in the current document. + * This method is neccessary due to the fact that position and content + * can be changed apart from each other. + * Thus: Don't forget to repaint after adjusting any of the two. + */ + paint() { + const width = this.element.outerWidth(true); + const height = this.element.outerHeight(true); + const maxWidth = $(document).width(); + const maxHeight = $(document).height(); + let x = this.x - width / 2; + let y = this.y - height; + //The arrow offset is the offset from the bottom right corner of + //the tooltip "frame". + let arrow_offset_x = 0; + let arrow_offset_y = 0; + let left_arrow = false; + + if (y < 0) { + y = 0; + x = this.x + 20; + //Put the arrow on the left side and move the tooltip, + //if there is still enough place left on the right. + left_arrow = true; + arrow_offset_y = -height + this.y + 10; + if (arrow_offset_y > -20) { + y+= arrow_offset_y + 20; + arrow_offset_y = -20; + } + arrow_offset_x = -width / 2 - 8; + } else if (y + height > maxHeight) { + y = maxHeight - height; + } + + if (x < 0) { + arrow_offset_x = 0; + x = 0; + } else if (x + width > maxWidth) { + arrow_offset_x = x + width - maxWidth; + x = maxWidth - width; + } + this.translateArrows(arrow_offset_x, arrow_offset_y, left_arrow); + + this.element.css({ + left: x, + top: y + }); + } + + /** + * Toggles the visibility of the tooltip. If no state is provided, + * the tooltip will be hidden if visible and vice versa. Pretty straight + * forward and no surprises here. + * This method implicitely calls paint before a tooltip is shown (in case + * it was forgotten). + * + * @param {bool} visible - Optional visibility parameter to set the + * tooltip to a certain state + */ + toggle(visible) { + if (visible) { + this.paint(); + } + this.element.toggle(visible); + } + + /** + * Reveals the tooltip. + * + * @see Tooltip.toggle + */ + show() { + this.toggle(true); + } + + /** + * Hides the tooltip. + * + * @see Tooltip.toggle + */ + hide() { + this.toggle(false); + } + + /** + * Removes the tooltip + */ + remove() { + this.element.remove(); + } +} + +export default Tooltip; |
