Tooltip.js #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • application/
  • ui/
  • resources/
  • dojo/
  • ui/
  • Tooltip.js
  • View
  • Commits
  • Open Download .zip Download (8 KB)
// summary:
//      A tooltip with our custom CSS class
//      and support for loading content via href

dojo.provide("p4cms.ui.Tooltip");
dojo.require("dijit.Tooltip");
dojo.require("dojox.layout.ContentPane");

dojo.declare("p4cms.ui.Tooltip", [dijit.Tooltip], {
    aroundNode:     null,
    contentPane:    null,
    href:           '',

    // ensure that when we startup, the master tooltip is created in the required class.
    constructor: function() {
        this.inherited(arguments);

        // if we already have a master tooltip, but it's the wrong kind, kill it.
        if (dijit._masterTT && dijit._masterTT.declaredClass !== 'p4cms.ui._MasterTooltip') {
            dijit._masterTT.destroy();
            dijit._masterTT = null;
        }

        if (!dijit._masterTT) {
            dijit._masterTT = new p4cms.ui._MasterTooltip();
        }

        if (!this.aroundNode) {
            this.aroundNode = this.attachNode;
        }
    },

    // extended to:
    //  - utilize aroundNode
    //  - add support for css classes on the content
    //  - support pulling content from an href (via a content pane).
    open: function(target) {
        target = this.aroundNode || target;

        // if tooltip content is via href - use a content pane to load it
        // and defer opening the tooltip until the content pane has loaded.
        if (this.href && !this.contentPane) {
            this._loadHref(target);
        } else {
            if (!this.label) {
                return;
            }

            // wrap tooltip contents in a div with tooltip classes
            // preserve original contents and restore afterwards
            var originalLabel = this.label;
            this.label = "<div class=\"" + this.get('class') + "\">" + this.label + "</div>";
            this.inherited(arguments);
            this.label = originalLabel;
        }
    },

    // load tooltip contents from an href into a content pane
    // and open tooltip -- not intended to be called externally
    _loadHref: function(target) {
        this.contentPane = new dojox.layout.ContentPane({preload: true});
        this.contentPane.set('href', this.href);

        // open the tooltip when the content pane loads
        this.connect(this.contentPane, 'onLoad', function(){
           this.label = this.contentPane.get('content');
           this.open(target);
        });
    }
});

dojo.declare("p4cms.ui._MasterTooltip", [dijit._MasterTooltip], {
    extraClasses:   'p4cms-ui',

    // COPY/PASTE of parent's orient so that we can inject 'extraClasses'.
    // @todo Update this method when we upgrade dojo (last copied from 1.6.1)
    orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ tooltipCorner, /*Object*/ spaceAvailable, /*Object*/ aroundNodeCoords){
        // summary:
        //		Private function to set CSS for tooltip node based on which position it's in.
        //		This is called by the dijit popup code.   It will also reduce the tooltip's
        //		width to whatever width is available
        // tags:
        //		protected
        this.connectorNode.style.top = ""; //reset to default

        //Adjust the spaceAvailable width, without changing the spaceAvailable object
        var tooltipSpaceAvaliableWidth = spaceAvailable.w - this.connectorNode.offsetWidth;

        node.className = "dijitTooltip " + this.extraClasses + " " +
            {
                "BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
                "TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
                "BR-TR": "dijitTooltipBelow dijitTooltipABRight",
                "TR-BR": "dijitTooltipAbove dijitTooltipABRight",
                "BR-BL": "dijitTooltipRight",
                "BL-BR": "dijitTooltipLeft"
            }[aroundCorner + "-" + tooltipCorner];

        // reduce tooltip's width to the amount of width available, so that it doesn't overflow screen
        this.domNode.style.width = "auto";
        var size = dojo.contentBox(this.domNode);

        var width = Math.min((Math.max(tooltipSpaceAvaliableWidth,1)), size.w);
        var widthWasReduced = width < size.w;

        this.domNode.style.width = width+"px";

        //Adjust width for tooltips that have a really long word or a nowrap setting
        if(widthWasReduced){
            this.containerNode.style.overflow = "auto"; //temp change to overflow to detect if our tooltip needs to be wider to support the content
            var scrollWidth = this.containerNode.scrollWidth;
            this.containerNode.style.overflow = "visible"; //change it back
            if(scrollWidth > width){
                scrollWidth = scrollWidth + dojo.style(this.domNode,"paddingLeft") + dojo.style(this.domNode,"paddingRight");
                this.domNode.style.width = scrollWidth + "px";
            }
        }

        // Reposition the tooltip connector.
        if(tooltipCorner.charAt(0) === 'B' && aroundCorner.charAt(0) === 'B'){
            var mb = dojo.marginBox(node);
            var tooltipConnectorHeight = this.connectorNode.offsetHeight;
            if(mb.h > spaceAvailable.h){
                // The tooltip starts at the top of the page and will extend past the aroundNode
                var aroundNodePlacement = spaceAvailable.h - (aroundNodeCoords.h / 2) - (tooltipConnectorHeight / 2);
                this.connectorNode.style.top = aroundNodePlacement + "px";
                this.connectorNode.style.bottom = "";
            }else{
                // Align center of connector with center of aroundNode, except don't let bottom
                // of connector extend below bottom of tooltip content, or top of connector
                // extend past top of tooltip content
                this.connectorNode.style.bottom = Math.min(
                    Math.max(aroundNodeCoords.h/2 - tooltipConnectorHeight/2, 0),
                    mb.h - tooltipConnectorHeight) + "px";
                this.connectorNode.style.top = "";
            }
        }else{
            // reset the tooltip back to the defaults
            this.connectorNode.style.top = "";
            this.connectorNode.style.bottom = "";
        }

        return Math.max(0, size.w - tooltipSpaceAvaliableWidth);
    },

    // extends show to defer presentation until all images are loaded.
    show: function(innerHTML,  aroundNode, position, rtl) {
        // return if the aroundNode is no longer part of the page
        var nodeList = new dojo.NodeList(aroundNode);
        if (!nodeList.closest('body').length) {
            return;
        }

        this.inherited(arguments);

        // if content contains images, wait until images are loaded.
        var images = dojo.query('img', this.domNode);
        if (images.length) {

            // hide tooltip while images are loading.
            dojo.style(this.domNode, 'visibility', 'hidden');

            // open tooltip when all of the images are loaded.
            var loaded = 0;
            images.connect('onload', dojo.hitch(this, function(){
                if (++loaded >= images.length && this.isShowingNow) {
                    var pos     = (position && position.length)
                                ? position : dijit.Tooltip.defaultPosition,
                        align   = dijit.getPopupAroundAlignment(pos, !rtl);

                    //make sure the target still exists
                    var nodeList = new dojo.NodeList(aroundNode);
                    if (!nodeList.closest('body').length) {
                        return;
                    }

                    dijit.placeOnScreenAroundElement(this.domNode, aroundNode,
                        align, dojo.hitch(this, "orient"));

                    // fade it in.
                    dojo.style(this.domNode, {
                        visibility: 'visible',
                        opacity:    0
                    });
                    this.fadeIn.play();
                }
            }));
        }
    }
});
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/application/ui/resources/dojo/ui/Tooltip.js
#1 8972 Matt Attaway Initial add of the Chronicle source code