diff --git a/backend/app/assets/javascripts/spree/backend.js b/backend/app/assets/javascripts/spree/backend.js index 66edd0b1b52..877d79459b6 100644 --- a/backend/app/assets/javascripts/spree/backend.js +++ b/backend/app/assets/javascripts/spree/backend.js @@ -1,3 +1,4 @@ +//= require solidus_admin/bind-polyfill //= require handlebars //= require jquery //= require jquery_ujs @@ -5,7 +6,6 @@ //= require jquery-ui/sortable //= require jquery-ui/autocomplete //= require jquery.cookie -//= require jquery.powertip //= require jquery.sticky-kit.min //= require underscore-min //= require backbone diff --git a/backend/app/assets/javascripts/spree/backend/admin.js b/backend/app/assets/javascripts/spree/backend/admin.js index 420e9757a9b..622b33ec820 100644 --- a/backend/app/assets/javascripts/spree/backend/admin.js +++ b/backend/app/assets/javascripts/spree/backend/admin.js @@ -15,36 +15,27 @@ Hopefully, this will evolve into a propper class. **/ jQuery(function($) { + $('body').tooltip({selector: '.with-tip'}) - // Add some tips - $('.with-tip').powerTip({ - smartPlacement: true, - fadeInTime: 50, - fadeOutTime: 50, + $('body').on('inserted.bs.tooltip', function(e){ + var $target = $(e.target); + var $tooltip = $("#" + $target.attr("aria-describedby")); + $tooltip.addClass("action-" + $target.data("action")); }); - $('body') - .on('powerTipPreRender', '.with-tip', function() { - $('#powerTip').addClass($(this).data('action')); - $('#powerTip').addClass($(this).data('tip-color')); - }) - .on('powerTipClose', '.with-tip', function() { - $('#powerTip').removeClass($(this).data('action')); - }) - // Highlight hovered table column - $('table tbody tr td.actions').find('a, button').hover(function(){ + $('table').on("mouseenter", 'td.actions a, td.actions button', function(){ var tr = $(this).closest('tr'); var klass = 'highlight action-' + $(this).data('action') tr.addClass(klass) tr.prev().addClass('before-' + klass); - }, function(){ + }); + $('table').on("mouseleave", 'td.actions a, td.actions button', function(){ var tr = $(this).closest('tr'); var klass = 'highlight action-' + $(this).data('action') tr.removeClass(klass) tr.prev().removeClass('before-' + klass); }); - }); diff --git a/backend/app/assets/javascripts/spree/backend/line_items_on_order_edit.js b/backend/app/assets/javascripts/spree/backend/line_items_on_order_edit.js index a2899f9dba5..f93365e4bee 100644 --- a/backend/app/assets/javascripts/spree/backend/line_items_on_order_edit.js +++ b/backend/app/assets/javascripts/spree/backend/line_items_on_order_edit.js @@ -13,15 +13,6 @@ $(document).ready(function () { $('#stock_details').show(); $('button.add_variant').click(addVariant); - - // Add some tips - $('.with-tip').powerTip({ - smartPlacement: true, - fadeInTime: 50, - fadeOutTime: 50, - intentPollInterval: 300 - }); - }); }); diff --git a/backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee b/backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee index f6afa991e3f..e6c5f50d1e7 100644 --- a/backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee +++ b/backend/app/assets/javascripts/spree/backend/payments/edit.js.coffee @@ -61,10 +61,6 @@ jQuery ($) -> $(@).data('clicked', true) mouseup: => @[action]() - .powerTip - smartPlacement: true - fadeInTime: 50 - fadeOutTime: 50 $buttons: -> @$actions().find(".fa-#{@action}, .fa-cancel") diff --git a/backend/app/assets/javascripts/spree/backend/shipments.js b/backend/app/assets/javascripts/spree/backend/shipments.js index 6a904a12590..f27cc587260 100644 --- a/backend/app/assets/javascripts/spree/backend/shipments.js +++ b/backend/app/assets/javascripts/spree/backend/shipments.js @@ -13,15 +13,6 @@ $(document).ready(function () { $('#stock_details').show(); $('button.add_variant').click(addVariantFromStockLocation); - - // Add some tips - $('.with-tip').powerTip({ - smartPlacement: true, - fadeInTime: 50, - fadeOutTime: 50, - intentPollInterval: 300 - }); - }); //handle edit click @@ -237,13 +228,6 @@ startItemSplit = function(event){ $('a.cancel-split').click(cancelItemSplit); $('a.save-split').click(completeItemSplit); - // Add some tips - $('.with-tip').powerTip({ - smartPlacement: true, - fadeInTime: 50, - fadeOutTime: 50, - intentPollInterval: 300 - }); $('#item_stock_location').select2({ width: 'resolve', placeholder: Spree.translations.item_stock_placeholder }); } diff --git a/backend/app/assets/javascripts/spree/backend/spree-select2.js b/backend/app/assets/javascripts/spree/backend/spree-select2.js index 7e6cd3b5214..23f45319983 100644 --- a/backend/app/assets/javascripts/spree/backend/spree-select2.js +++ b/backend/app/assets/javascripts/spree/backend/spree-select2.js @@ -11,14 +11,4 @@ jQuery(function($) { new_taxon = taxon.text.replace('->', '') return new_taxon; } - - $("#product_taxon_ids").on({ - change: function(e){ - $('.select2-search-choice .with-tip').powerTip({ - smartPlacement: true, - fadeInTime: 50, - fadeOutTime: 50 - }) - } - }) }) diff --git a/backend/app/assets/stylesheets/spree/backend.css b/backend/app/assets/stylesheets/spree/backend.css index 83c4b02839f..39df4e55601 100644 --- a/backend/app/assets/stylesheets/spree/backend.css +++ b/backend/app/assets/stylesheets/spree/backend.css @@ -6,7 +6,6 @@ *= require normalize *= require jquery-ui/datepicker *= require jquery-ui/autocomplete - *= require jquery.powertip *= require select2 *= require prism diff --git a/backend/app/assets/stylesheets/spree/backend/_bootstrap_custom.scss b/backend/app/assets/stylesheets/spree/backend/_bootstrap_custom.scss index 3e872fa3484..d41696d9aa4 100644 --- a/backend/app/assets/stylesheets/spree/backend/_bootstrap_custom.scss +++ b/backend/app/assets/stylesheets/spree/backend/_bootstrap_custom.scss @@ -142,7 +142,7 @@ $grid-gutter-width: 1.875rem !default; // 30px // // Font, line-height, and color for body text, headings, and more. -$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif !default; +$font-family-sans-serif: $base-font-family !default; $font-family-serif: Georgia, "Times New Roman", Times, serif !default; $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace !default; $font-family-base: $font-family-sans-serif !default; diff --git a/backend/app/assets/stylesheets/spree/backend/plugins/_bootstrap_tooltip.scss b/backend/app/assets/stylesheets/spree/backend/plugins/_bootstrap_tooltip.scss new file mode 100644 index 00000000000..3916a852d07 --- /dev/null +++ b/backend/app/assets/stylesheets/spree/backend/plugins/_bootstrap_tooltip.scss @@ -0,0 +1,47 @@ +@mixin bootstrap-tooltip-color($color) { + .tooltip-inner{ + background-color: $color; + } + + &.tooltip-top, + &.bs-tether-element-attached-bottom { + .tooltip-arrow { + border-top-color: $color; + } + } + + &.tooltip-right, + &.bs-tether-element-attached-left { + .tooltip-arrow { + border-right-color: $color; + } + } + + &.tooltip-bottom, + &.bs-tether-element-attached-top { + .tooltip-arrow { + border-bottom-color: $color; + } + } + + &.tooltip-left, + &.bs-tether-element-attached-right { + .tooltip-arrow { + border-left-color: $color; + } + } +} + +.tooltip { + pointer-events: none; + + &.action-edit, &.action-save, &.action-capture, &.action-add { + @include bootstrap-tooltip-color($brand-success); + } + &.action-clone { + @include bootstrap-tooltip-color($brand-warning); + } + &.action-void, &.action-failure, &.action-cancel, &.action-remove { + @include bootstrap-tooltip-color($brand-danger); + } +} diff --git a/backend/app/assets/stylesheets/spree/backend/plugins/_powertip.scss b/backend/app/assets/stylesheets/spree/backend/plugins/_powertip.scss deleted file mode 100644 index 57ed5308610..00000000000 --- a/backend/app/assets/stylesheets/spree/backend/plugins/_powertip.scss +++ /dev/null @@ -1,87 +0,0 @@ -#powerTip { - background-color: $color-3; - padding: 5px 15px; - border-radius: $border-radius; - pointer-events: none; - - &.n:before, &.ne:before, &.nw:before { - border-top-width: 5px; - border-top-color: $color-3; - bottom: -5px; - } - - &.e:before { - border-right-width: 5px; - border-right-color: $color-3; - left: -5px; - } - &.s:before, &.se:before, &.sw:before { - border-bottom-width: 5px; - border-bottom-color: $color-3; - top: -5px; - } - &.w:before { - border-left-width: 5px; - border-left-color: $color-3; - right: -5px; - } - &.ne:before, &.se:before { - border-right-width: 5px; - border-right-color: $color-3; - left: -5px; - } - &.nw:before, &.sw:before { - border-left-width: 5px; - border-right-color: $color-3; - right: -5px; - } - - &.clone, &.yellow, &.cancel { - background-color: $color-notice; - - &.n:before, &.ne:before, &.nw:before { - border-top-color: $color-notice; - } - &.e:before, &.nw:before, &.sw:before { - border-right-color: $color-notice; - } - &.s:before, &.se:before, &.sw:before { - border-bottom-color: $color-notice; - } - &.w:before { - border-left-color: $color-notice; - } - } - &.edit, &.green, &.capture, &.save, &.add { - background-color: $color-success; - - &.n:before, &.ne:before, &.nw:before { - border-top-color: $color-success; - } - &.e:before, &.nw:before, &.sw:before { - border-right-color: $color-success; - } - &.s:before, &.se:before, &.sw:before { - border-bottom-color: $color-success; - } - &.w:before { - border-left-color: $color-success; - } - } - &.remove, &.red, &.void { - background-color: $color-error; - - &.n:before, &.ne:before, &.nw:before { - border-top-color: $color-error; - } - &.e:before, &.nw:before, &.sw:before { - border-right-color: $color-error; - } - &.s:before, &.se:before, &.sw:before { - border-bottom-color: $color-error; - } - &.w:before { - border-left-color: $color-error; - } - } -} diff --git a/backend/app/assets/stylesheets/spree/backend/spree_admin.scss b/backend/app/assets/stylesheets/spree/backend/spree_admin.scss index d29f190853e..813e1026dc4 100644 --- a/backend/app/assets/stylesheets/spree/backend/spree_admin.scss +++ b/backend/app/assets/stylesheets/spree/backend/spree_admin.scss @@ -30,8 +30,8 @@ @import 'spree/backend/components/tabs'; @import 'font-awesome'; -@import 'spree/backend/plugins/powertip'; @import 'spree/backend/plugins/select2'; +@import 'spree/backend/plugins/bootstrap_tooltip'; @import 'spree/backend/sections/adjustments_table'; @import 'spree/backend/sections/orders'; diff --git a/backend/app/views/spree/admin/style_guide/topics/messaging/_tooltips.html.erb b/backend/app/views/spree/admin/style_guide/topics/messaging/_tooltips.html.erb index cbdb5579bad..f68a8ceb07c 100644 --- a/backend/app/views/spree/admin/style_guide/topics/messaging/_tooltips.html.erb +++ b/backend/app/views/spree/admin/style_guide/topics/messaging/_tooltips.html.erb @@ -3,7 +3,7 @@ <%- end %>

- We are using jQuery PowerTip + We are using bootstrap's tooltip library with the class .with-tip as a trigger.

diff --git a/backend/vendor/assets/javascripts/jquery.powertip.js b/backend/vendor/assets/javascripts/jquery.powertip.js deleted file mode 100644 index 2fd74bcedd0..00000000000 --- a/backend/vendor/assets/javascripts/jquery.powertip.js +++ /dev/null @@ -1,1165 +0,0 @@ -/*! - PowerTip - v1.2.0 - 2013-04-03 - http://stevenbenner.github.com/jquery-powertip/ - Copyright (c) 2013 Steven Benner (http://stevenbenner.com/). - Released under MIT license. - https://raw.github.com/stevenbenner/jquery-powertip/master/LICENSE.txt -*/ -(function(factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['jquery'], factory); - } else { - // Browser globals - factory(jQuery); - } -}(function($) { - // useful private variables - var $document = $(document), - $window = $(window), - $body = $('body'); - - // constants - var DATA_DISPLAYCONTROLLER = 'displayController', - DATA_HASACTIVEHOVER = 'hasActiveHover', - DATA_FORCEDOPEN = 'forcedOpen', - DATA_HASMOUSEMOVE = 'hasMouseMove', - DATA_MOUSEONTOTIP = 'mouseOnToPopup', - DATA_ORIGINALTITLE = 'originalTitle', - DATA_POWERTIP = 'powertip', - DATA_POWERTIPJQ = 'powertipjq', - DATA_POWERTIPTARGET = 'powertiptarget', - RAD2DEG = 180 / Math.PI; - - /** - * Session data - * Private properties global to all powerTip instances - */ - var session = { - isTipOpen: false, - isFixedTipOpen: false, - isClosing: false, - tipOpenImminent: false, - activeHover: null, - currentX: 0, - currentY: 0, - previousX: 0, - previousY: 0, - desyncTimeout: null, - mouseTrackingActive: false, - delayInProgress: false, - windowWidth: 0, - windowHeight: 0, - scrollTop: 0, - scrollLeft: 0 - }; - - /** - * Collision enumeration - * @enum {number} - */ - var Collision = { - none: 0, - top: 1, - bottom: 2, - left: 4, - right: 8 - }; - - /** - * Display hover tooltips on the matched elements. - * @param {(Object|string)} opts The options object to use for the plugin, or - * the name of a method to invoke on the first matched element. - * @param {*=} [arg] Argument for an invoked method (optional). - * @return {jQuery} jQuery object for the matched selectors. - */ - $.fn.powerTip = function(opts, arg) { - // don't do any work if there were no matched elements - if (!this.length) { - return this; - } - - // handle api method calls on the plugin, e.g. powerTip('hide') - if ($.type(opts) === 'string' && $.powerTip[opts]) { - return $.powerTip[opts].call(this, this, arg); - } - - // extend options and instantiate TooltipController - var options = $.extend({}, $.fn.powerTip.defaults, opts), - tipController = new TooltipController(options); - - // hook mouse and viewport dimension tracking - initTracking(); - - // setup the elements - this.each(function elementSetup() { - var $this = $(this), - dataPowertip = $this.data(DATA_POWERTIP), - dataElem = $this.data(DATA_POWERTIPJQ), - dataTarget = $this.data(DATA_POWERTIPTARGET), - title; - - // handle repeated powerTip calls on the same element by destroying the - // original instance hooked to it and replacing it with this call - if ($this.data(DATA_DISPLAYCONTROLLER)) { - $.powerTip.destroy($this); - } - - // attempt to use title attribute text if there is no data-powertip, - // data-powertipjq or data-powertiptarget. If we do use the title - // attribute, delete the attribute so the browser will not show it - title = $this.attr('title'); - if (!dataPowertip && !dataTarget && !dataElem && title) { - $this.data(DATA_POWERTIP, title); - $this.data(DATA_ORIGINALTITLE, title); - $this.removeAttr('title'); - } - - // create hover controllers for each element - $this.data( - DATA_DISPLAYCONTROLLER, - new DisplayController($this, options, tipController) - ); - }); - - // attach events to matched elements if the manual options is not enabled - if (!options.manual) { - this.on({ - // mouse events - 'mouseenter.powertip': function elementMouseEnter(event) { - $.powerTip.show(this, event); - }, - 'mouseleave.powertip': function elementMouseLeave() { - $.powerTip.hide(this); - }, - // keyboard events - 'focus.powertip': function elementFocus() { - $.powerTip.show(this); - }, - 'blur.powertip': function elementBlur() { - $.powerTip.hide(this, true); - }, - 'keydown.powertip': function elementKeyDown(event) { - // close tooltip when the escape key is pressed - if (event.keyCode === 27) { - $.powerTip.hide(this, true); - } - } - }); - } - - return this; - }; - - /** - * Default options for the powerTip plugin. - */ - $.fn.powerTip.defaults = { - fadeInTime: 200, - fadeOutTime: 100, - followMouse: false, - popupId: 'powerTip', - intentSensitivity: 7, - intentPollInterval: 100, - closeDelay: 100, - placement: 'n', - smartPlacement: false, - offset: 10, - mouseOnToPopup: false, - manual: false - }; - - /** - * Default smart placement priority lists. - * The first item in the array is the highest priority, the last is the lowest. - * The last item is also the default, which will be used if all previous options - * do not fit. - */ - $.fn.powerTip.smartPlacementLists = { - n: ['n', 'ne', 'nw', 's'], - e: ['e', 'ne', 'se', 'w', 'nw', 'sw', 'n', 's', 'e'], - s: ['s', 'se', 'sw', 'n'], - w: ['w', 'nw', 'sw', 'e', 'ne', 'se', 'n', 's', 'w'], - nw: ['nw', 'w', 'sw', 'n', 's', 'se', 'nw'], - ne: ['ne', 'e', 'se', 'n', 's', 'sw', 'ne'], - sw: ['sw', 'w', 'nw', 's', 'n', 'ne', 'sw'], - se: ['se', 'e', 'ne', 's', 'n', 'nw', 'se'], - 'nw-alt': ['nw-alt', 'n', 'ne-alt', 'sw-alt', 's', 'se-alt', 'w', 'e'], - 'ne-alt': ['ne-alt', 'n', 'nw-alt', 'se-alt', 's', 'sw-alt', 'e', 'w'], - 'sw-alt': ['sw-alt', 's', 'se-alt', 'nw-alt', 'n', 'ne-alt', 'w', 'e'], - 'se-alt': ['se-alt', 's', 'sw-alt', 'ne-alt', 'n', 'nw-alt', 'e', 'w'] - }; - - /** - * Public API - */ - $.powerTip = { - /** - * Attempts to show the tooltip for the specified element. - * @param {jQuery|Element} element The element to open the tooltip for. - * @param {jQuery.Event=} event jQuery event for hover intent and mouse - * tracking (optional). - */ - show: function apiShowTip(element, event) { - if (event) { - trackMouse(event); - session.previousX = event.pageX; - session.previousY = event.pageY; - $(element).data(DATA_DISPLAYCONTROLLER).show(); - } else { - $(element).first().data(DATA_DISPLAYCONTROLLER).show(true, true); - } - return element; - }, - - /** - * Repositions the tooltip on the element. - * @param {jQuery|Element} element The element the tooltip is shown for. - */ - reposition: function apiResetPosition(element) { - $(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition(); - return element; - }, - - /** - * Attempts to close any open tooltips. - * @param {(jQuery|Element)=} element The element with the tooltip that - * should be closed (optional). - * @param {boolean=} immediate Disable close delay (optional). - */ - hide: function apiCloseTip(element, immediate) { - if (element) { - $(element).first().data(DATA_DISPLAYCONTROLLER).hide(immediate); - } else { - if (session.activeHover) { - session.activeHover.data(DATA_DISPLAYCONTROLLER).hide(true); - } - } - return element; - }, - - /** - * Destroy and roll back any powerTip() instance on the specified element. - * @param {jQuery|Element} element The element with the powerTip instance. - */ - destroy: function apiDestroy(element) { - $(element).off('.powertip').each(function destroy() { - var $this = $(this), - dataAttributes = [ - DATA_ORIGINALTITLE, - DATA_DISPLAYCONTROLLER, - DATA_HASACTIVEHOVER, - DATA_FORCEDOPEN - ]; - - if ($this.data(DATA_ORIGINALTITLE)) { - $this.attr('title', $this.data(DATA_ORIGINALTITLE)); - dataAttributes.push(DATA_POWERTIP); - } - - $this.removeData(dataAttributes); - }); - return element; - } - }; - - // API aliasing - $.powerTip.showTip = $.powerTip.show; - $.powerTip.closeTip = $.powerTip.hide; - - /** - * Creates a new CSSCoordinates object. - * @private - * @constructor - */ - function CSSCoordinates() { - var me = this; - - // initialize object properties - me.top = 'auto'; - me.left = 'auto'; - me.right = 'auto'; - me.bottom = 'auto'; - - /** - * Set a property to a value. - * @private - * @param {string} property The name of the property. - * @param {number} value The value of the property. - */ - me.set = function(property, value) { - if ($.isNumeric(value)) { - me[property] = Math.round(value); - } - }; - } - - /** - * Creates a new tooltip display controller. - * @private - * @constructor - * @param {jQuery} element The element that this controller will handle. - * @param {Object} options Options object containing settings. - * @param {TooltipController} tipController The TooltipController object for - * this instance. - */ - function DisplayController(element, options, tipController) { - var hoverTimer = null; - - /** - * Begins the process of showing a tooltip. - * @private - * @param {boolean=} immediate Skip intent testing (optional). - * @param {boolean=} forceOpen Ignore cursor position and force tooltip to - * open (optional). - */ - function openTooltip(immediate, forceOpen) { - cancelTimer(); - if (!element.data(DATA_HASACTIVEHOVER)) { - if (!immediate) { - session.tipOpenImminent = true; - hoverTimer = setTimeout( - function intentDelay() { - hoverTimer = null; - checkForIntent(); - }, - options.intentPollInterval - ); - } else { - if (forceOpen) { - element.data(DATA_FORCEDOPEN, true); - } - tipController.showTip(element); - } - } - } - - /** - * Begins the process of closing a tooltip. - * @private - * @param {boolean=} disableDelay Disable close delay (optional). - */ - function closeTooltip(disableDelay) { - cancelTimer(); - session.tipOpenImminent = false; - if (element.data(DATA_HASACTIVEHOVER)) { - element.data(DATA_FORCEDOPEN, false); - if (!disableDelay) { - session.delayInProgress = true; - hoverTimer = setTimeout( - function closeDelay() { - hoverTimer = null; - tipController.hideTip(element); - session.delayInProgress = false; - }, - options.closeDelay - ); - } else { - tipController.hideTip(element); - } - } - } - - /** - * Checks mouse position to make sure that the user intended to hover on the - * specified element before showing the tooltip. - * @private - */ - function checkForIntent() { - // calculate mouse position difference - var xDifference = Math.abs(session.previousX - session.currentX), - yDifference = Math.abs(session.previousY - session.currentY), - totalDifference = xDifference + yDifference; - - // check if difference has passed the sensitivity threshold - if (totalDifference < options.intentSensitivity) { - tipController.showTip(element); - } else { - // try again - session.previousX = session.currentX; - session.previousY = session.currentY; - openTooltip(); - } - } - - /** - * Cancels active hover timer. - * @private - */ - function cancelTimer() { - hoverTimer = clearTimeout(hoverTimer); - session.delayInProgress = false; - } - - /** - * Repositions the tooltip on this element. - * @private - */ - function repositionTooltip() { - tipController.resetPosition(element); - } - - // expose the methods - this.show = openTooltip; - this.hide = closeTooltip; - this.cancel = cancelTimer; - this.resetPosition = repositionTooltip; - } - - /** - * Creates a new Placement Calculator. - * @private - * @constructor - */ - function PlacementCalculator() { - /** - * Compute the CSS position to display a tooltip at the specified placement - * relative to the specified element. - * @private - * @param {jQuery} element The element that the tooltip should target. - * @param {string} placement The placement for the tooltip. - * @param {number} tipWidth Width of the tooltip element in pixels. - * @param {number} tipHeight Height of the tooltip element in pixels. - * @param {number} offset Distance to offset tooltips in pixels. - * @return {CSSCoordinates} A CSSCoordinates object with the position. - */ - function computePlacementCoords(element, placement, tipWidth, tipHeight, offset) { - var placementBase = placement.split('-')[0], // ignore 'alt' for corners - coords = new CSSCoordinates(), - position; - - if (isSvgElement(element)) { - position = getSvgPlacement(element, placementBase); - } else { - position = getHtmlPlacement(element, placementBase); - } - - // calculate the appropriate x and y position in the document - switch (placement) { - case 'n': - coords.set('left', position.left - (tipWidth / 2)); - coords.set('bottom', session.windowHeight - position.top + offset); - break; - case 'e': - coords.set('left', position.left + offset); - coords.set('top', position.top - (tipHeight / 2)); - break; - case 's': - coords.set('left', position.left - (tipWidth / 2)); - coords.set('top', position.top + offset); - break; - case 'w': - coords.set('top', position.top - (tipHeight / 2)); - coords.set('right', session.windowWidth - position.left + offset); - break; - case 'nw': - coords.set('bottom', session.windowHeight - position.top + offset); - coords.set('right', session.windowWidth - position.left - 20); - break; - case 'nw-alt': - coords.set('left', position.left); - coords.set('bottom', session.windowHeight - position.top + offset); - break; - case 'ne': - coords.set('left', position.left - 20); - coords.set('bottom', session.windowHeight - position.top + offset); - break; - case 'ne-alt': - coords.set('bottom', session.windowHeight - position.top + offset); - coords.set('right', session.windowWidth - position.left); - break; - case 'sw': - coords.set('top', position.top + offset); - coords.set('right', session.windowWidth - position.left - 20); - break; - case 'sw-alt': - coords.set('left', position.left); - coords.set('top', position.top + offset); - break; - case 'se': - coords.set('left', position.left - 20); - coords.set('top', position.top + offset); - break; - case 'se-alt': - coords.set('top', position.top + offset); - coords.set('right', session.windowWidth - position.left); - break; - } - - return coords; - } - - /** - * Finds the tooltip attachment point in the document for a HTML DOM element - * for the specified placement. - * @private - * @param {jQuery} element The element that the tooltip should target. - * @param {string} placement The placement for the tooltip. - * @return {Object} An object with the top,left position values. - */ - function getHtmlPlacement(element, placement) { - var objectOffset = element.offset(), - objectWidth = element.outerWidth(), - objectHeight = element.outerHeight(), - left, - top; - - // calculate the appropriate x and y position in the document - switch (placement) { - case 'n': - left = objectOffset.left + objectWidth / 2; - top = objectOffset.top; - break; - case 'e': - left = objectOffset.left + objectWidth; - top = objectOffset.top + objectHeight / 2; - break; - case 's': - left = objectOffset.left + objectWidth / 2; - top = objectOffset.top + objectHeight; - break; - case 'w': - left = objectOffset.left; - top = objectOffset.top + objectHeight / 2; - break; - case 'nw': - left = objectOffset.left; - top = objectOffset.top; - break; - case 'ne': - left = objectOffset.left + objectWidth; - top = objectOffset.top; - break; - case 'sw': - left = objectOffset.left; - top = objectOffset.top + objectHeight; - break; - case 'se': - left = objectOffset.left + objectWidth; - top = objectOffset.top + objectHeight; - break; - } - - return { - top: top, - left: left - }; - } - - /** - * Finds the tooltip attachment point in the document for a SVG element for - * the specified placement. - * @private - * @param {jQuery} element The element that the tooltip should target. - * @param {string} placement The placement for the tooltip. - * @return {Object} An object with the top,left position values. - */ - function getSvgPlacement(element, placement) { - var svgElement = element.closest('svg')[0], - domElement = element[0], - point = svgElement.createSVGPoint(), - boundingBox = domElement.getBBox(), - matrix = domElement.getScreenCTM(), - halfWidth = boundingBox.width / 2, - halfHeight = boundingBox.height / 2, - placements = [], - placementKeys = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'], - coords, - rotation, - steps, - x; - - function pushPlacement() { - placements.push(point.matrixTransform(matrix)); - } - - // get bounding box corners and midpoints - point.x = boundingBox.x; - point.y = boundingBox.y; - pushPlacement(); - point.x += halfWidth; - pushPlacement(); - point.x += halfWidth; - pushPlacement(); - point.y += halfHeight; - pushPlacement(); - point.y += halfHeight; - pushPlacement(); - point.x -= halfWidth; - pushPlacement(); - point.x -= halfWidth; - pushPlacement(); - point.y -= halfHeight; - pushPlacement(); - - // determine rotation - if (placements[0].y !== placements[1].y || placements[0].x !== placements[7].x) { - rotation = Math.atan2(matrix.b, matrix.a) * RAD2DEG; - steps = Math.ceil(((rotation % 360) - 22.5) / 45); - if (steps < 1) { - steps += 8; - } - while (steps--) { - placementKeys.push(placementKeys.shift()); - } - } - - // find placement - for (x = 0; x < placements.length; x++) { - if (placementKeys[x] === placement) { - coords = placements[x]; - break; - } - } - - return { - top: coords.y + session.scrollTop, - left: coords.x + session.scrollLeft - }; - } - - // expose methods - this.compute = computePlacementCoords; - } - - /** - * Creates a new tooltip controller. - * @private - * @constructor - * @param {Object} options Options object containing settings. - */ - function TooltipController(options) { - var placementCalculator = new PlacementCalculator(), - tipElement = $('#' + options.popupId); - - // build and append tooltip div if it does not already exist - if (tipElement.length === 0) { - tipElement = $('
', { id: options.popupId }); - // grab body element if it was not populated when the script loaded - // note: this hack exists solely for jsfiddle support - if ($body.length === 0) { - $body = $('body'); - } - $body.append(tipElement); - } - - // hook mousemove for cursor follow tooltips - if (options.followMouse) { - // only one positionTipOnCursor hook per tooltip element, please - if (!tipElement.data(DATA_HASMOUSEMOVE)) { - $document.on('mousemove', positionTipOnCursor); - $window.on('scroll', positionTipOnCursor); - tipElement.data(DATA_HASMOUSEMOVE, true); - } - } - - // if we want to be able to mouse onto the tooltip then we need to attach - // hover events to the tooltip that will cancel a close request on hover and - // start a new close request on mouseleave - if (options.mouseOnToPopup) { - tipElement.on({ - mouseenter: function tipMouseEnter() { - // we only let the mouse stay on the tooltip if it is set to let - // users interact with it - if (tipElement.data(DATA_MOUSEONTOTIP)) { - // check activeHover in case the mouse cursor entered the - // tooltip during the fadeOut and close cycle - if (session.activeHover) { - session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel(); - } - } - }, - mouseleave: function tipMouseLeave() { - // check activeHover in case the mouse cursor entered the - // tooltip during the fadeOut and close cycle - if (session.activeHover) { - session.activeHover.data(DATA_DISPLAYCONTROLLER).hide(); - } - } - }); - } - - /** - * Gives the specified element the active-hover state and queues up the - * showTip function. - * @private - * @param {jQuery} element The element that the tooltip should target. - */ - function beginShowTip(element) { - element.data(DATA_HASACTIVEHOVER, true); - // show tooltip, asap - tipElement.queue(function queueTipInit(next) { - showTip(element); - next(); - }); - } - - /** - * Shows the tooltip, as soon as possible. - * @private - * @param {jQuery} element The element that the tooltip should target. - */ - function showTip(element) { - var tipContent; - - // it is possible, especially with keyboard navigation, to move on to - // another element with a tooltip during the queue to get to this point - // in the code. if that happens then we need to not proceed or we may - // have the fadeout callback for the last tooltip execute immediately - // after this code runs, causing bugs. - if (!element.data(DATA_HASACTIVEHOVER)) { - return; - } - - // if the tooltip is open and we got asked to open another one then the - // old one is still in its fadeOut cycle, so wait and try again - if (session.isTipOpen) { - if (!session.isClosing) { - hideTip(session.activeHover); - } - tipElement.delay(100).queue(function queueTipAgain(next) { - showTip(element); - next(); - }); - return; - } - - // trigger powerTipPreRender event - element.trigger('powerTipPreRender'); - - // set tooltip content - tipContent = getTooltipContent(element); - if (tipContent) { - tipElement.empty().append(tipContent); - } else { - // we have no content to display, give up - return; - } - - // trigger powerTipRender event - element.trigger('powerTipRender'); - - session.activeHover = element; - session.isTipOpen = true; - - tipElement.data(DATA_MOUSEONTOTIP, options.mouseOnToPopup); - - // set tooltip position - if (!options.followMouse) { - positionTipOnElement(element); - session.isFixedTipOpen = true; - } else { - positionTipOnCursor(); - } - - // fadein - tipElement.fadeIn(options.fadeInTime, function fadeInCallback() { - // start desync polling - if (!session.desyncTimeout) { - session.desyncTimeout = setInterval(closeDesyncedTip, 500); - } - - // trigger powerTipOpen event - element.trigger('powerTipOpen'); - }); - } - - /** - * Hides the tooltip. - * @private - * @param {jQuery} element The element that the tooltip should target. - */ - function hideTip(element) { - // reset session - session.isClosing = true; - session.activeHover = null; - session.isTipOpen = false; - - // stop desync polling - session.desyncTimeout = clearInterval(session.desyncTimeout); - - // reset element state - element.data(DATA_HASACTIVEHOVER, false); - element.data(DATA_FORCEDOPEN, false); - - // fade out - tipElement.fadeOut(options.fadeOutTime, function fadeOutCallback() { - var coords = new CSSCoordinates(); - - // reset session and tooltip element - session.isClosing = false; - session.isFixedTipOpen = false; - tipElement.removeClass(); - - // support mouse-follow and fixed position tips at the same time by - // moving the tooltip to the last cursor location after it is hidden - coords.set('top', session.currentY + options.offset); - coords.set('left', session.currentX + options.offset); - tipElement.css(coords); - - // trigger powerTipClose event - element.trigger('powerTipClose'); - }); - } - - /** - * Moves the tooltip to the users mouse cursor. - * @private - */ - function positionTipOnCursor() { - // to support having fixed tooltips on the same page as cursor tooltips, - // where both instances are referencing the same tooltip element, we - // need to keep track of the mouse position constantly, but we should - // only set the tip location if a fixed tip is not currently open, a tip - // open is imminent or active, and the tooltip element in question does - // have a mouse-follow using it. - if (!session.isFixedTipOpen && (session.isTipOpen || (session.tipOpenImminent && tipElement.data(DATA_HASMOUSEMOVE)))) { - // grab measurements - var tipWidth = tipElement.outerWidth(), - tipHeight = tipElement.outerHeight(), - coords = new CSSCoordinates(), - collisions, - collisionCount; - - // grab collisions - coords.set('top', session.currentY + options.offset); - coords.set('left', session.currentX + options.offset); - collisions = getViewportCollisions( - coords, - tipWidth, - tipHeight - ); - - // handle tooltip view port collisions - if (collisions !== Collision.none) { - collisionCount = countFlags(collisions); - if (collisionCount === 1) { - // if there is only one collision (bottom or right) then - // simply constrain the tooltip to the view port - if (collisions === Collision.right) { - coords.set('left', session.windowWidth - tipWidth); - } else if (collisions === Collision.bottom) { - coords.set('top', session.scrollTop + session.windowHeight - tipHeight); - } - } else { - // if the tooltip has more than one collision then it is - // trapped in the corner and should be flipped to get it out - // of the users way - coords.set('left', session.currentX - tipWidth - options.offset); - coords.set('top', session.currentY - tipHeight - options.offset); - } - } - - // position the tooltip - tipElement.css(coords); - } - } - - /** - * Sets the tooltip to the correct position relative to the specified target - * element. Based on options settings. - * @private - * @param {jQuery} element The element that the tooltip should target. - */ - function positionTipOnElement(element) { - var priorityList, - finalPlacement; - - if (options.smartPlacement) { - priorityList = $.fn.powerTip.smartPlacementLists[options.placement]; - - // iterate over the priority list and use the first placement option - // that does not collide with the view port. if they all collide - // then the last placement in the list will be used. - $.each(priorityList, function(idx, pos) { - // place tooltip and find collisions - var collisions = getViewportCollisions( - placeTooltip(element, pos), - tipElement.outerWidth(), - tipElement.outerHeight() - ); - - // update the final placement variable - finalPlacement = pos; - - // break if there were no collisions - if (collisions === Collision.none) { - return false; - } - }); - } else { - // if we're not going to use the smart placement feature then just - // compute the coordinates and do it - placeTooltip(element, options.placement); - finalPlacement = options.placement; - } - - // add placement as class for CSS arrows - tipElement.addClass(finalPlacement); - } - - /** - * Sets the tooltip position to the appropriate values to show the tip at - * the specified placement. This function will iterate and test the tooltip - * to support elastic tooltips. - * @private - * @param {jQuery} element The element that the tooltip should target. - * @param {string} placement The placement for the tooltip. - * @return {CSSCoordinates} A CSSCoordinates object with the top, left, and - * right position values. - */ - function placeTooltip(element, placement) { - var iterationCount = 0, - tipWidth, - tipHeight, - coords = new CSSCoordinates(); - - // set the tip to 0,0 to get the full expanded width - coords.set('top', 0); - coords.set('left', 0); - tipElement.css(coords); - - // to support elastic tooltips we need to check for a change in the - // rendered dimensions after the tooltip has been positioned - do { - // grab the current tip dimensions - tipWidth = tipElement.outerWidth(); - tipHeight = tipElement.outerHeight(); - - // get placement coordinates - coords = placementCalculator.compute( - element, - placement, - tipWidth, - tipHeight, - options.offset - ); - - // place the tooltip - tipElement.css(coords); - } while ( - // sanity check: limit to 5 iterations, and... - ++iterationCount <= 5 && - // try again if the dimensions changed after placement - (tipWidth !== tipElement.outerWidth() || tipHeight !== tipElement.outerHeight()) - ); - - return coords; - } - - /** - * Checks for a tooltip desync and closes the tooltip if one occurs. - * @private - */ - function closeDesyncedTip() { - var isDesynced = false; - // It is possible for the mouse cursor to leave an element without - // firing the mouseleave or blur event. This most commonly happens when - // the element is disabled under mouse cursor. If this happens it will - // result in a desynced tooltip because the tooltip was never asked to - // close. So we should periodically check for a desync situation and - // close the tip if such a situation arises. - if (session.isTipOpen && !session.isClosing && !session.delayInProgress) { - // user moused onto another tip or active hover is disabled - if (session.activeHover.data(DATA_HASACTIVEHOVER) === false || session.activeHover.is(':disabled')) { - isDesynced = true; - } else { - // hanging tip - have to test if mouse position is not over the - // active hover and not over a tooltip set to let the user - // interact with it. - // for keyboard navigation: this only counts if the element does - // not have focus. - // for tooltips opened via the api: we need to check if it has - // the forcedOpen flag. - if (!isMouseOver(session.activeHover) && !session.activeHover.is(':focus') && !session.activeHover.data(DATA_FORCEDOPEN)) { - if (tipElement.data(DATA_MOUSEONTOTIP)) { - if (!isMouseOver(tipElement)) { - isDesynced = true; - } - } else { - isDesynced = true; - } - } - } - - if (isDesynced) { - // close the desynced tip - hideTip(session.activeHover); - } - } - } - - // expose methods - this.showTip = beginShowTip; - this.hideTip = hideTip; - this.resetPosition = positionTipOnElement; - } - - /** - * Determine whether a jQuery object is an SVG element - * @private - * @param {jQuery} element The element to check - * @return {boolean} Whether this is an SVG element - */ - function isSvgElement(element) { - return window.SVGElement && element[0] instanceof SVGElement; - } - - /** - * Initializes the viewport dimension cache and hooks up the mouse position - * tracking and viewport dimension tracking events. - * Prevents attaching the events more than once. - * @private - */ - function initTracking() { - if (!session.mouseTrackingActive) { - session.mouseTrackingActive = true; - - // grab the current viewport dimensions on load - $(function getViewportDimensions() { - session.scrollLeft = $window.scrollLeft(); - session.scrollTop = $window.scrollTop(); - session.windowWidth = $window.width(); - session.windowHeight = $window.height(); - }); - - // hook mouse move tracking - $document.on('mousemove', trackMouse); - - // hook viewport dimensions tracking - $window.on({ - resize: function trackResize() { - session.windowWidth = $window.width(); - session.windowHeight = $window.height(); - }, - scroll: function trackScroll() { - var x = $window.scrollLeft(), - y = $window.scrollTop(); - if (x !== session.scrollLeft) { - session.currentX += x - session.scrollLeft; - session.scrollLeft = x; - } - if (y !== session.scrollTop) { - session.currentY += y - session.scrollTop; - session.scrollTop = y; - } - } - }); - } - } - - /** - * Saves the current mouse coordinates to the session object. - * @private - * @param {jQuery.Event} event The mousemove event for the document. - */ - function trackMouse(event) { - session.currentX = event.pageX; - session.currentY = event.pageY; - } - - /** - * Tests if the mouse is currently over the specified element. - * @private - * @param {jQuery} element The element to check for hover. - * @return {boolean} - */ - function isMouseOver(element) { - // use getBoundingClientRect() because jQuery's width() and height() - // methods do not work with SVG elements - // compute width/height because those properties do not exist on the object - // returned by getBoundingClientRect() in older versions of IE - var elementPosition = element.offset(), - elementBox = element[0].getBoundingClientRect(), - elementWidth = elementBox.right - elementBox.left, - elementHeight = elementBox.bottom - elementBox.top; - - return session.currentX >= elementPosition.left && - session.currentX <= elementPosition.left + elementWidth && - session.currentY >= elementPosition.top && - session.currentY <= elementPosition.top + elementHeight; - } - - /** - * Fetches the tooltip content from the specified element's data attributes. - * @private - * @param {jQuery} element The element to get the tooltip content for. - * @return {(string|jQuery|undefined)} The text/HTML string, jQuery object, or - * undefined if there was no tooltip content for the element. - */ - function getTooltipContent(element) { - var tipText = element.data(DATA_POWERTIP), - tipObject = element.data(DATA_POWERTIPJQ), - tipTarget = element.data(DATA_POWERTIPTARGET), - targetElement, - content; - - if (tipText) { - if ($.isFunction(tipText)) { - tipText = tipText.call(element[0]); - } - content = tipText; - } else if (tipObject) { - if ($.isFunction(tipObject)) { - tipObject = tipObject.call(element[0]); - } - if (tipObject.length > 0) { - content = tipObject.clone(true, true); - } - } else if (tipTarget) { - targetElement = $('#' + tipTarget); - if (targetElement.length > 0) { - content = targetElement.html(); - } - } - - return content; - } - - /** - * Finds any viewport collisions that an element (the tooltip) would have if it - * were absolutely positioned at the specified coordinates. - * @private - * @param {CSSCoordinates} coords Coordinates for the element. - * @param {number} elementWidth Width of the element in pixels. - * @param {number} elementHeight Height of the element in pixels. - * @return {number} Value with the collision flags. - */ - function getViewportCollisions(coords, elementWidth, elementHeight) { - var viewportTop = session.scrollTop, - viewportLeft = session.scrollLeft, - viewportBottom = viewportTop + session.windowHeight, - viewportRight = viewportLeft + session.windowWidth, - collisions = Collision.none; - - if (coords.top < viewportTop || Math.abs(coords.bottom - session.windowHeight) - elementHeight < viewportTop) { - collisions |= Collision.top; - } - if (coords.top + elementHeight > viewportBottom || Math.abs(coords.bottom - session.windowHeight) > viewportBottom) { - collisions |= Collision.bottom; - } - if (coords.left < viewportLeft || coords.right + elementWidth > viewportRight) { - collisions |= Collision.left; - } - if (coords.left + elementWidth > viewportRight || coords.right < viewportLeft) { - collisions |= Collision.right; - } - - return collisions; - } - - /** - * Counts the number of bits set on a flags value. - * @param {number} value The flags value. - * @return {number} The number of bits that have been set. - */ - function countFlags(value) { - var count = 0; - while (value) { - value &= value - 1; - count++; - } - return count; - } - -})); diff --git a/backend/vendor/assets/javascripts/solidus_admin/bind-polyfill.js b/backend/vendor/assets/javascripts/solidus_admin/bind-polyfill.js new file mode 100644 index 00000000000..6dae783dc05 --- /dev/null +++ b/backend/vendor/assets/javascripts/solidus_admin/bind-polyfill.js @@ -0,0 +1,28 @@ +// Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill +if (!Function.prototype.bind) { + Function.prototype.bind = function(oThis) { + if (typeof this !== 'function') { + // closest thing possible to the ECMAScript 5 + // internal IsCallable function + throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function() {}, + fBound = function() { + return fToBind.apply(this instanceof fNOP + ? this + : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + if (this.prototype) { + // Function.prototype doesn't have a prototype property + fNOP.prototype = this.prototype; + } + fBound.prototype = new fNOP(); + + return fBound; + }; +} diff --git a/backend/vendor/assets/stylesheets/jquery.powertip.css b/backend/vendor/assets/stylesheets/jquery.powertip.css deleted file mode 100644 index 42721d60366..00000000000 --- a/backend/vendor/assets/stylesheets/jquery.powertip.css +++ /dev/null @@ -1,85 +0,0 @@ -/* PowerTip Plugin */ -#powerTip { - cursor: default; - background-color: #333; /* fallback for browsers that dont support rgba */ - background-color: rgba(0, 0, 0, 0.8); - border-radius: 6px; - color: #FFF; - display: none; - padding: 10px; - position: absolute; - white-space: nowrap; - z-index: 2147483647; -} -#powerTip:before { - content: ""; - position: absolute; -} -#powerTip.n:before, #powerTip.s:before { - border-right: 5px solid transparent; - border-left: 5px solid transparent; - left: 50%; - margin-left: -5px; -} -#powerTip.e:before, #powerTip.w:before { - border-bottom: 5px solid transparent; - border-top: 5px solid transparent; - margin-top: -5px; - top: 50%; -} -#powerTip.n:before { - border-top: 10px solid rgba(0, 0, 0, 0.8); - bottom: -10px; -} -#powerTip.e:before { - border-right: 10px solid rgba(0, 0, 0, 0.8); - left: -10px; -} -#powerTip.s:before { - border-bottom: 10px solid rgba(0, 0, 0, 0.8); - top: -10px; -} -#powerTip.w:before { - border-left: 10px solid rgba(0, 0, 0, 0.8); - right: -10px; -} -#powerTip.ne:before, #powerTip.se:before { - border-right: 10px solid transparent; - border-left: 0; - left: 10px; -} -#powerTip.nw:before, #powerTip.sw:before { - border-left: 10px solid transparent; - border-right: 0; - right: 10px; -} -#powerTip.ne:before, #powerTip.nw:before { - border-top: 10px solid rgba(0, 0, 0, 0.8); - bottom: -10px; -} -#powerTip.se:before, #powerTip.sw:before { - border-bottom: 10px solid rgba(0, 0, 0, 0.8); - top: -10px; -} -#powerTip.nw-alt:before, #powerTip.ne-alt:before, -#powerTip.sw-alt:before, #powerTip.se-alt:before { - border-top: 10px solid rgba(0, 0, 0, 0.8); - bottom: -10px; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - left: 10px; -} -#powerTip.ne-alt:before { - left: auto; - right: 10px; -} -#powerTip.sw-alt:before, #powerTip.se-alt:before { - border-top: none; - border-bottom: 10px solid rgba(0, 0, 0, 0.8); - bottom: auto; - top: -10px; -} -#powerTip.se-alt:before { - left: auto; - right: 10px; -}