MediaWiki:Jquery context popup.js
From Conceptual Reconstructionism Project
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
;(function($) { /* Popup Menu plugin ** author Chris Muster ** created 04/12/2017 ** updated 08/05/2020 ** description - A plugin that, when called on an element, returns and attaches a customisable popup menu ** */ class Popup { constructor(options,elem) { var self = this; var defaultPopupMenu = `<div> <a href="#"><i id="faInfo" class="fa fa-info"></i></a> <a href="#"><i id="faQuest" class="fa fa-question"></i></a> <a href="#" title="Link to example.com"><i id="faLink" class="fa fa-external-link"></i></a> </div>`; this.defaultOptions = { content : defaultPopupMenu, //this option MUST be set when new options passed through, or only the default menu will show position : "top", //where the popup will show by default- top. Other options: right, bottom, or left theme : "popupTheme", //Menu Element theme. Defaults to popupTheme, but custom class can be set instead style : "", //Popup Menu Style. Default no style, will revert to default colours. Other options: Blue, Red, Green, Custom animation : "standard", //Standard animation by default. Other options: flip, grow, bounce event : "click", //Default set to "click", can also be set to hover hideOnClick : true, //When true, clicking off the menu closes it. When false, only clicking on the menu closes it zIndex : 100, //Individual z-index can be set for each menu for layering if necessary //function to handle actions when clicking on popup menu icons. MUST be set when options are passed through or an error or default menu actions will occur popItemClick: function(globalthis) { //Default actions var twentyEightSpaces = ` `; var twentyFourSpaces = ` `; var eightSpaces = ` `; var sixteenSpaces = ` `; var content; var container = $(event.target).attr("id"); switch (container) { case "faInfo": content = { type : "info", heading : "Information", text : `<p>To set a new menu when calling .popup() on an element, you must set a variable that holds a string with the html for that menu, then pass that variable through as the "content" part of the options. For example: </p> <p>var myMenu = '<div>\ <br /> ${twentyEightSpaces}<a href="#''><i id="faInfo" class="fa fa-info"></i></a>\<br /> ${twentyFourSpaces}</div>'; </p> <p>would create a menu with one item, and just add more '<a>' tags with icons inside the '<div>' tags to add more menu items. </p> <p>Then add it to the content when calling the popup: </p> <p>$("#myPopUp").popup({ <br /> ${eightSpaces}content: myMenu, <br /> ${eightSpaces}popItemClick(globalthis) { <br /> ${sixteenSpaces}...new actions here... <br /> ${eightSpaces}} <br /> });</p> <p>You must set new actions in the "popItemClick" function for your menu in the options you pass or it will throw an error.</p>` } globalthis.alertBox(content); break; case "faQuest": content = { type : "info", heading : "Question", text : `<p>Why is this being shown?</p> <p>Because you need to set a popup menu of your own (and the popItemClick() function) or you get this default menu.</p> <p>If you set the popup menu but don't change the popItemClick() function, you will get an error.</p> <p>Click the "i" button for more info.</p>` } globalthis.alertBox(content); break; case "faLink": window.open("http://example.com/"); break; default: content = { type : "danger", heading : "Error", text : `<p>Error! You have set a new menu without changing the 'popItemClick' function. The 'popItemClick' function must be set to new menu actions.</p>` } globalthis.alertBox(content); } } } this.elem = elem; this.$elem = $(elem); this.options = $.extend({}, this.defaultOptions, options); if (!this.$elem.hasClass(this.options.theme)) { this.$elem.addClass(this.options.theme); } this.init(); } init() { this.popup = $('<div class="pop-cont" />') .addClass('pop-' + this.options.position) .addClass('popupTheme' + this.options.style) .append('<div class="pop-items" />') .appendTo('body').css("opacity", 0).hide(); this.setContent(); this.setTriggers(); } setContent() { var self = this; var location = this.popup.find(".pop-items"); var content; if ((this.options.position == 'top') || (this.options.position == 'bottom')) { content = $(this.options.content).find("a").addClass("pop-item"); location.html(content); this.popup.find("i").first().addClass("leftBorder"); this.popup.find("i").last().addClass("rightBorder"); } else if ((this.options.position == 'left') || (this.options.position == 'right')) { content = $(this.options.content).find("a").addClass("pop-item").addClass('item-side'); location.html(content); this.popup.find("i").first().addClass("topBorder"); this.popup.find("i").last().addClass("bottomBorder"); } //popItemClick callback**************************************** location.find('.pop-item').on('click', function(event) { event.preventDefault(); self.options.popItemClick.call(this, self); }); } setTriggers() { var self = this; if (this.options.event === 'click') { this.$elem.on('click', function(event) { event.preventDefault(); if (self.$elem.hasClass('pressed')) { self.pophide(); } else { self.popshow(); } }); } if (this.options.event === 'hover') { this.$elem.on('mouseenter', function(event) { setTimeout(function() { self.popshow(); self.popup = $(self.popup[0]); }, 250); }); $(this.popup).on('mouseleave', function(event) { setTimeout(function() { self.pophide(); }, 1000); }); } if (this.options.hideOnClick === true) { $('html').on('click.popup', function(event) { if (event.target != self.elem && self.$elem.has(event.target).length === 0 && self.popup.has(event.target).length === 0 && self.popup.is(":visible")) { self.pophide(); } }); } } pophide() { var self = this; var animation = {opacity: 0}; this.$elem.removeClass('pressed'); switch (this.options.position) { case 'top': animation.top = '+=20'; break; case 'left': animation.left = '+=20'; break; case 'right': animation.left = '-=20'; break; case 'bottom': animation.top = '-=20'; break; } this.popup.animate(animation, 200, function() { self.popup.hide(); }); } popshow() { this.$elem.addClass('pressed'); this.setPosition(); this.popup.show().css({opacity: 1}).addClass('animate-' + this.options.animation); } setPosition() { var self = this; this.coords = this.$elem.offset(); var x = this.coords.left; var y = this.coords.top; var popWidth = this.popup.width(); var popHeight = this.popup.height(); var adjLeft = popWidth / 2; var adjTop = popHeight / 2; this.testy = $('<div class="test" />') .css({display: 'inline-block', margin: '0px', padding: '0px'}) .appendTo('body'); var measure = this.$elem.clone().css({padding: "0px", margin: "0px"}); var loc = this.testy; loc.html(measure); var textWidth = this.testy.width(); var textHeight = this.testy.height(); this.testy.remove(); var adjMenuWidth = textWidth / 2; var adjMenuHeight = textHeight / 2; var up = y - (popHeight + 7); var down = y + textHeight; if (this.popup.hasClass('pop-top')){ this.popup.css({ top : up + "px", left : (x - adjLeft + adjMenuWidth + 5) + "px", right: "auto", 'z-index': this.options.zIndex }); } if (this.popup.hasClass('pop-bottom')) { this.popup.css({ top : (down + 7) + "px", left : (x - adjLeft + adjMenuWidth + 5) + "px", right: "auto", 'z-index': this.options.zIndex }); } if (this.popup.hasClass('pop-left')) { this.popup.css({ top : (y - adjTop + adjMenuHeight + 5) + "px", left : (x - popWidth - 2) + "px", right: "auto", 'z-index': this.options.zIndex}); } if (this.popup.hasClass('pop-right')) { this.popup.css({ top : (y - adjTop + adjMenuHeight + 5) + "px", left : (x + textWidth + 12) + "px", right: "auto", 'z-index': this.options.zIndex}); } } alertBox(content) { var self = this; var myAlert = `<div id="alertBox" class="alert"> <div class="alert-content"> <div class="alert-header"> <h2></h2> </div> <div class="alert-body"></div> <div class="alert-footer"> <button class="alert-close">OK</button> </div> </div> </div>`; $('body').append(myAlert); this.alert = $('#alertBox'); this.header = this.alert.find('div.alert-header'); this.heading = this.header.find('h2'); this.alertBody = this.alert.find('div.alert-body'); this.footer = this.alert.find('div.alert-footer'); this.close = this.footer.find('button.alert-close'); this.heading.append(content.heading); this.alertBody.append(content.text); switch (content.type) { case "info": this.header.addClass("info"); this.footer.addClass("info"); this.close.addClass("info"); break; case "success": this.header.addClass("success"); this.footer.addClass("success"); this.close.addClass("success"); break; case "danger": this.header.addClass("danger"); this.footer.addClass("danger"); this.close.addClass("danger"); break; case "warning": this.header.addClass("warning"); this.footer.addClass("warning"); this.close.addClass("warning"); break; default: break; } this.alert.show(); var closeBtn = $("button.alert-close"); closeBtn.on("click", function() { self.alert.remove(); }); $(document).on("click", function(event) { event.preventDefault(); if (event.target == self.alert[0]) { self.alert.remove(); } }); } }; //Set $.fn.popup so it returns an instance of the Popup class when called******************************* $.fn.popup = function(options) { return this.each(function() { var popobject = new Popup(options, this); }); }; }(jQuery));