Skip to content

Instantly share code, notes, and snippets.

@tleilax
Created January 29, 2019 08:37
Show Gist options
  • Save tleilax/69b6d2d4ada86974b64ceba8935fab54 to your computer and use it in GitHub Desktop.
Save tleilax/69b6d2d4ada86974b64ceba8935fab54 to your computer and use it in GitHub Desktop.
Index: resources/assets/javascripts/bootstrap/tooltip.js
===================================================================
--- resources/assets/javascripts/bootstrap/tooltip.js (revision 50796)
+++ resources/assets/javascripts/bootstrap/tooltip.js (working copy)
@@ -1,3 +1,5 @@
+/*jslint esversion: 6*/
+
// Attach global hover handler for tooltips.
// Applies to all elements having a "data-tooltip" attribute.
// Tooltip may be provided in the data-attribute itself or by
@@ -8,58 +10,50 @@
STUDIP.Tooltip.threshold = 6;
-jQuery(document)
- .on('mouseenter mouseleave', '[data-tooltip]', function(event) {
- var data = $(this).data(),
- visible = event.type === 'mouseenter',
- content,
- offset = $(this).offset(),
- x = offset.left + $(this).outerWidth(true) / 2,
- y = offset.top,
- tooltip;
+$(document).on('mouseenter mouseleave', '[data-tooltip]', function(event) {
+ let data = $(this).data();
- if (!data.tooltipObject) {
- // If tooltip has not yet been created (first hover), obtain it's
- // contents and create the actual tooltip object.
- content =
- $('<div/>')
- .text(data.tooltip || $(this).attr('title'))
- .html() ||
- $(this)
- .find('.tooltip-content')
- .remove()
- .html();
- $(this).attr('title', '');
+ const visible = event.type === 'mouseenter';
+ const offset = $(this).offset();
+ const x = offset.left + $(this).outerWidth(true) / 2;
+ const y = offset.top;
+ const delay = data.hasOwnProperty('tooltipDelay') ? data.tooltipDelay : 300;
- tooltip = new STUDIP.Tooltip(x, y, content);
+ let content;
+ let tooltip;
- data.tooltipObject = tooltip;
-
- $(this).on('remove', function() {
- tooltip.remove();
- });
- } else if (visible) {
- // If tooltip has already been created, update it's position.
- // This is neccessary if the surrounding content is scrollable AND has
- // been scrolled. Otherwise the tooltip would appear at it's previous
- // and now wrong location.
- data.tooltipObject.position(x, y);
+ if (!data.tooltipObject) {
+ // If tooltip has not yet been created (first hover), obtain it's
+ // contents and create the actual tooltip object.
+ content = $('<div/>').text(data.tooltip || $(this).attr('title')).html();
+ if (!content) {
+ content = $(this).find('.tooltip-content').remove().html();
}
+ $(this).attr('title', '');
- if (visible) {
- $('.studip-tooltip')
- .not(data.tooltipObject)
- .hide();
- data.tooltipObject.show();
- } else {
- timeout = setTimeout(function() {
- data.tooltipObject.hide();
- }, 300);
- }
- })
- .on('mouseenter', '.studip-tooltip', function() {
- clearTimeout(timeout);
- })
- .on('mouseleave', '.studip-tooltip', function() {
- $(this).hide();
- });
+ tooltip = new STUDIP.Tooltip(x, y, content);
+
+ data.tooltipObject = tooltip;
+
+ $(this).on('remove', function() {
+ tooltip.remove();
+ });
+ } else if (visible) {
+ // If tooltip has already been created, update it's position.
+ // This is neccessary if the surrounding content is scrollable AND has
+ // been scrolled. Otherwise the tooltip would appear at it's previous
+ // and now wrong location.
+ data.tooltipObject.position(x, y);
+ }
+
+ if (visible) {
+ $('.studip-tooltip').not(data.tooltipObject).hide();
+ data.tooltipObject.show();
+ } else {
+ timeout = setTimeout(() => data.tooltipObject.hide(), tooltipDelay);
+ }
+}).on('mouseenter', '.studip-tooltip', () => {
+ clearTimeout(timeout);
+}).on('mouseleave', '.studip-tooltip', function() {
+ $(this).hide();
+});
Index: resources/assets/javascripts/lib/tooltip.js
===================================================================
--- resources/assets/javascripts/lib/tooltip.js (revision 50796)
+++ resources/assets/javascripts/lib/tooltip.js (working copy)
@@ -1,3 +1,5 @@
+/*jslint esversion: 6*/
+
import CSS from './css.js';
/**
@@ -9,172 +11,188 @@
* @since Stud.IP 3.1
*/
-/**
- * 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'
- */
-function Tooltip(x, y, content, css_class) {
- // Obtain unique id of the tooltip
- this.id = Tooltip.getId();
+let count = 0;
+let threshold = 0;
- // 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.appendTo('body');
+class Tooltip {
+ static get count() {
+ return count;
+ }
- // Set position and content and paint the tooltip
- this.position(x, y);
- this.update(content);
- this.paint();
-}
+ static set count(value) {
+ count = value;
+ }
-// Provide unique ids for each tooltip (neccessary for css styles)
-Tooltip.count = 0;
+ // Threshold used for "edge detection" (imagine a padding along the edges)
+ static get threshold() {
+ return threshold;
+ }
-/**
- * Returns a new unique id of a tooltip.
- *
- * @return {string} Unique id
- * @static
- */
-Tooltip.getId = function() {
- var id = 'studip-tooltip-' + Tooltip.count;
- Tooltip.count += 1;
- return id;
-};
+ static set threshold(value) {
+ threshold = value;
+ }
-/**
- * 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
- */
-Tooltip.prototype.translateArrows = function(x, y) {
- CSS.removeRule('#' + this.id + ':before');
- CSS.removeRule('#' + this.id + ':after');
+ /**
+ * 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;
+ }
- if (x !== 0 || y !== 0) {
- var rule = 'translate(' + x + 'px, ' + y + 'px);';
- CSS.addRule('#' + this.id + ':before', { transform: rule }, ['-ms-', '-webkit-']);
- CSS.addRule('#' + this.id + ':after', { transform: rule }, ['-ms-', '-webkit-']);
+ /**
+ * 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.appendTo('body');
+
+ // Set position and content and paint the tooltip
+ this.position(x, y);
+ this.update(content);
+ this.paint();
}
-};
-/**
- * Updates the position of the tooltip.
- *
- * @param {int} x - Horizontal position of the tooltip
- * @param {int} y - Vertical position of the tooltip
- */
-Tooltip.prototype.position = function(x, y) {
- this.x = x;
- this.y = y;
-};
+ /**
+ * 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) {
+ CSS.removeRule(`#${this.id}::before`);
+ CSS.removeRule(`#${this.id}::after`);
-/**
- * Updates the contents of the tooltip.
- *
- * @param {string} content - Content of the tooltip (may be html)
- */
-Tooltip.prototype.update = function(content) {
- this.element.html(content);
-};
+ if (x !== 0 || y !== 0) {
+ const rule = `translate(${x}px, ${y}px);`;
+ CSS.addRule(`#${this.id}::before`, { transform: rule }, ['-ms-', '-webkit-']);
+ CSS.addRule(`#${this.id}::after`, { transform: rule }, ['-ms-', '-webkit-']);
+ }
+ }
-// Threshold used for "edge detection" (imagine a padding along the edges)
-Tooltip.threshold = 0;
+ /**
+ * 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;
+ }
-/**
- * "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.
- */
-Tooltip.prototype.paint = function() {
- var width = this.element.outerWidth(true),
- height = this.element.outerHeight(true),
- maxWidth = $(document).width(),
- x = this.x - width / 2,
- y = this.y - height,
- arrowOffset = 0;
+ /**
+ * Updates the contents of the tooltip.
+ *
+ * @param {string} content - Content of the tooltip (may be html)
+ */
+ update(content) {
+ this.element.html(content);
+ }
- if (x < Tooltip.threshold) {
- arrowOffset = x - Tooltip.threshold;
- x = Tooltip.threshold;
- } else if (x + width > maxWidth - Tooltip.threshold) {
- arrowOffset = x + width - maxWidth + Tooltip.threshold;
- x = maxWidth - width - Tooltip.threshold;
+ /**
+ * "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();
+ let x = this.x - width / 2;
+ let y = this.y - height;
+ let arrowOffset = 0;
+
+ if (x < Tooltip.threshold) {
+ arrowOffset = x - Tooltip.threshold;
+ x = Tooltip.threshold;
+ } else if (x + width > maxWidth - Tooltip.threshold) {
+ arrowOffset = x + width - maxWidth + Tooltip.threshold;
+ x = maxWidth - width - Tooltip.threshold;
+ }
+ this.translateArrows(arrowOffset, 0);
+
+ this.element.css({
+ left: x,
+ top: y
+ });
}
- this.translateArrows(arrowOffset, 0);
- 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);
+ }
-/**
- * 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
- */
-Tooltip.prototype.toggle = function(visible) {
- if (visible) {
- this.paint();
+ /**
+ * Reveals the tooltip.
+ *
+ * @see Tooltip.toggle
+ */
+ show() {
+ this.toggle(true);
}
- this.element.toggle(visible);
-};
-/**
- * Reveals the tooltip.
- *
- * @see Tooltip.toggle
- */
-Tooltip.prototype.show = function() {
- this.toggle(true);
-};
+ /**
+ * Hides the tooltip.
+ *
+ * @see Tooltip.toggle
+ */
+ hide() {
+ this.toggle(false);
+ }
-/**
- * Hides the tooltip.
- *
- * @see Tooltip.toggle
- */
-Tooltip.prototype.hide = function() {
- this.toggle(false);
-};
+ /**
+ * Removes the tooltip
+ */
+ remove() {
+ this.element.remove();
+ }
+}
-/**
- * Removes the tooltip
- */
-Tooltip.prototype.remove = function() {
- this.element.remove();
-};
-
export default Tooltip;
/*jslint esversion: 6*/
// Attach global hover handler for tooltips.
// Applies to all elements having a "data-tooltip" attribute.
// Tooltip may be provided in the data-attribute itself or by
// defining a title attribute. The latter is prefered due to
// the obvious accessibility issues.
var timeout = null;
STUDIP.Tooltip.threshold = 6;
$(document).on('mouseenter mouseleave', '[data-tooltip]', function(event) {
let data = $(this).data();
const visible = event.type === 'mouseenter';
const offset = $(this).offset();
const x = offset.left + $(this).outerWidth(true) / 2;
const y = offset.top;
const delay = data.hasOwnProperty('tooltipDelay') ? data.tooltipDelay : 300;
let content;
let tooltip;
if (!data.tooltipObject) {
// If tooltip has not yet been created (first hover), obtain it's
// contents and create the actual tooltip object.
content = $('<div/>').text(data.tooltip || $(this).attr('title')).html();
if (!content) {
content = $(this).find('.tooltip-content').remove().html();
}
$(this).attr('title', '');
tooltip = new STUDIP.Tooltip(x, y, content);
data.tooltipObject = tooltip;
$(this).on('remove', function() {
tooltip.remove();
});
} else if (visible) {
// If tooltip has already been created, update it's position.
// This is neccessary if the surrounding content is scrollable AND has
// been scrolled. Otherwise the tooltip would appear at it's previous
// and now wrong location.
data.tooltipObject.position(x, y);
}
if (visible) {
$('.studip-tooltip').not(data.tooltipObject).hide();
data.tooltipObject.show();
} else {
timeout = setTimeout(() => data.tooltipObject.hide(), tooltipDelay);
}
}).on('mouseenter', '.studip-tooltip', () => {
clearTimeout(timeout);
}).on('mouseleave', '.studip-tooltip', function() {
$(this).hide();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment