src/cm/media/js/lib/yui/yui3.0.0/examples/widget/widget-tooltip_clean.html
changeset 0 40c8f766c9b8
equal deleted inserted replaced
-1:000000000000 0:40c8f766c9b8
       
     1 
       
     2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
       
     3 <html>
       
     4 <head>
       
     5 <meta http-equiv="content-type" content="text/html; charset=utf-8">
       
     6 <title>Creating a simple Tooltip widget</title>
       
     7 
       
     8 <style type="text/css">
       
     9 /*margin and padding on body element
       
    10   can introduce errors in determining
       
    11   element position and are not recommended;
       
    12   we turn them off as a foundation for YUI
       
    13   CSS treatments. */
       
    14 body {
       
    15 	margin:0;
       
    16 	padding:0;
       
    17 }
       
    18 </style>
       
    19 
       
    20 <link type="text/css" rel="stylesheet" href="../../build/cssfonts/fonts-min.css" />
       
    21 <script type="text/javascript" src="../../build/yui/yui-min.js"></script>
       
    22 
       
    23 
       
    24 <!--begin custom header content for this example-->
       
    25 <style type="text/css">
       
    26     .yui-tooltip {
       
    27         position:absolute;
       
    28     }
       
    29 
       
    30     .yui-tooltip-content {
       
    31         color: #000;
       
    32         padding: 2px 5px;
       
    33         border-color: #D4C237 #A6982B #A6982B #A6982B;
       
    34         border-width: 1px;
       
    35         border-style: solid;
       
    36         background-color: #FFEE69;
       
    37     }
       
    38 
       
    39     .yui-tooltip-hidden {
       
    40         visibility:hidden;
       
    41     }
       
    42 
       
    43     div.yui-hastooltip {
       
    44         border:1px solid #243356;
       
    45         background-color:#406ED9;
       
    46         color:#ffffff;
       
    47         width:25em;
       
    48         margin:20px 0px;
       
    49         padding:5px;
       
    50         cursor:default;
       
    51     }
       
    52 
       
    53     div.yui-hastooltip span {
       
    54         font-style:italic;
       
    55         font-weight:bold;
       
    56         color:#ABCEFF;
       
    57     }
       
    58 
       
    59     .yui-tooltip-content strong {
       
    60         font-weight:bold;
       
    61     }
       
    62 </style>
       
    63 
       
    64 <!--end custom header content for this example-->
       
    65 
       
    66 </head>
       
    67 
       
    68 <body class=" yui-skin-sam">
       
    69 
       
    70 <h1>Creating a simple Tooltip widget</h1>
       
    71 
       
    72 <div class="exampleIntro">
       
    73 	This is an advanced example, in which we create a Tooltip widget, by extending the base <code>Widget</code> class, and adding <code>WidgetStack</code> and <code>WidgetPosition</code> extensions, through <code>Base.build</code>.			
       
    74 </div>
       
    75 
       
    76 <!--BEGIN SOURCE CODE FOR EXAMPLE =============================== -->
       
    77 
       
    78 <div id="delegate">
       
    79     <div class="yui-hastooltip" title="Tooltip 1" id="tt1">Tooltip One <span>(content from title)</span></div>
       
    80     <div class="yui-hastooltip" title="Tooltip 2" id="tt2">Tooltip Two <span>(content set in event listener)</span></div>
       
    81     <div class="yui-hastooltip" title="Tooltip 3" id="tt3">Tooltip Three <span>(content from lookup)</span></div>
       
    82     <div class="yui-hastooltip" title="Tooltip 4" id="tt4">Tooltip Four <span>(content from title)</span></div>
       
    83     <label><input type="checkbox" id="prevent" /> Prevent Tooltip Four</label>
       
    84 </div>
       
    85 
       
    86 <script type="text/javascript">
       
    87 YUI({base:"../../build/", timeout: 10000}).use("widget", "widget-position", "widget-stack", function(Y) {
       
    88     var Lang = Y.Lang,
       
    89         Node = Y.Node;
       
    90 
       
    91     /* Tooltip constructor */
       
    92     function Tooltip(config) {
       
    93         Tooltip.superclass.constructor.apply(this, arguments);
       
    94     }
       
    95 
       
    96     /* 
       
    97        Required NAME static field, used to identify the Widget class and 
       
    98        used as an event prefix, to generate class names etc. (set to the 
       
    99        class name in camel case). 
       
   100     */
       
   101     Tooltip.NAME = "tooltip";
       
   102 
       
   103     /* Static constants */
       
   104     Tooltip.OFFSET_X = 15;
       
   105     Tooltip.OFFSET_Y = 15;
       
   106     Tooltip.OFFSCREEN_X = -10000;
       
   107     Tooltip.OFFSCREEN_Y = -10000;
       
   108 
       
   109     /* Default Tooltip Attributes */
       
   110     Tooltip.ATTRS = {
       
   111 
       
   112         /* 
       
   113          * The tooltip content. This can either be a fixed content value, 
       
   114          * or a map of id-to-values, designed to be used when a single
       
   115          * tooltip is mapped to multiple trigger elements.
       
   116          */
       
   117         content : {
       
   118             value: null
       
   119         },
       
   120 
       
   121         /* 
       
   122          * The set of nodes to bind to the tooltip instance. Can be a string, 
       
   123          * or a node instance.
       
   124          */
       
   125         triggerNodes : {
       
   126             value: null,
       
   127             setter: function(val) {
       
   128                 if (val && Lang.isString(val)) {
       
   129                     val = Node.all(val);
       
   130                 }
       
   131                 return val;
       
   132             }
       
   133         },
       
   134 
       
   135         /*
       
   136          * The delegate node to which event listeners should be attached.
       
   137          * This node should be an ancestor of all trigger nodes bound
       
   138          * to the instance. By default the document is used.
       
   139          */
       
   140         delegate : {
       
   141             value: null,
       
   142             setter: function(val) {
       
   143                 return Y.one(val) || Y.one("document");
       
   144             }
       
   145         },
       
   146 
       
   147         /*
       
   148          * The time to wait, after the mouse enters the trigger node,
       
   149          * to display the tooltip
       
   150          */
       
   151         showDelay : {
       
   152             value:250
       
   153         },
       
   154 
       
   155         /*
       
   156          * The time to wait, after the mouse leaves the trigger node,
       
   157          * to hide the tooltip
       
   158          */
       
   159         hideDelay : {
       
   160             value:10
       
   161         },
       
   162 
       
   163         /*
       
   164          * The time to wait, after the tooltip is first displayed for 
       
   165          * a trigger node, to hide it, if the mouse has not left the 
       
   166          * trigger node
       
   167          */
       
   168         autoHideDelay : {
       
   169             value:2000
       
   170         },
       
   171 
       
   172         /*
       
   173          * Override the default visibility set by the widget base class
       
   174          */
       
   175         visible : {
       
   176             value:false
       
   177         },
       
   178 
       
   179         /*
       
   180          * Override the default XY value set by the widget base class,
       
   181          * to position the tooltip offscreen
       
   182          */
       
   183         xy: {
       
   184             value:[Tooltip.OFFSCREEN_X, Tooltip.OFFSCREEN_Y]
       
   185         }
       
   186     };
       
   187 
       
   188     /* Extend the base Widget class */
       
   189     Y.extend(Tooltip, Y.Widget, {
       
   190 
       
   191         /*
       
   192          * Initialization Code: Sets up privately used state
       
   193          * properties, and publishes the events Tooltip introduces
       
   194          */
       
   195         initializer : function(config) {
       
   196 
       
   197             this._triggerClassName = this.getClassName("trigger");
       
   198 
       
   199             // Currently bound trigger node information
       
   200             this._currTrigger = {
       
   201                 node: null,
       
   202                 title: null,
       
   203                 mouseX: Tooltip.OFFSCREEN_X,
       
   204                 mouseY: Tooltip.OFFSCREEN_Y
       
   205             };
       
   206 
       
   207             // Event handles - mouse over is set on the delegate
       
   208             // element, mousemove and mouseout are set on the trigger node
       
   209             this._eventHandles = {
       
   210                 delegate: null,
       
   211                 trigger: {
       
   212                     mouseMove : null,
       
   213                     mouseOut: null
       
   214                 }
       
   215             };
       
   216 
       
   217             // Show/hide timers
       
   218             this._timers = {
       
   219                 show: null,
       
   220                 hide: null
       
   221             };
       
   222 
       
   223             // Publish events introduced by Tooltip. Note the triggerEnter event is preventable,
       
   224             // with the default behavior defined in the _defTriggerEnterFn method 
       
   225             this.publish("triggerEnter", {defaultFn: this._defTriggerEnterFn, preventable:true});
       
   226             this.publish("triggerLeave", {preventable:false});
       
   227         },
       
   228 
       
   229         /*
       
   230          * Destruction Code: Clears event handles, timers,
       
   231          * and current trigger information
       
   232          */
       
   233         destructor : function() {
       
   234             this._clearCurrentTrigger();
       
   235             this._clearTimers();
       
   236             this._clearHandles();
       
   237         },
       
   238 
       
   239         /*
       
   240          * bindUI is used to bind attribute change and dom event
       
   241          * listeners
       
   242          */
       
   243         bindUI : function() {
       
   244             this.after("delegateChange", this._afterSetDelegate);
       
   245             this.after("nodesChange", this._afterSetNodes);
       
   246 
       
   247             this._bindDelegate();
       
   248         },
       
   249 
       
   250         /*
       
   251          * syncUI is used to update the rendered DOM, based on the current
       
   252          * Tooltip state
       
   253          */
       
   254         syncUI : function() {
       
   255             this._uiSetNodes(this.get("triggerNodes"));
       
   256         },
       
   257 
       
   258         /*
       
   259          * Public method, which can be used by triggerEvent event listeners
       
   260          * to set the content of the tooltip for the current trigger node
       
   261          */
       
   262         setTriggerContent : function(content) {
       
   263             var contentBox = this.get("contentBox");
       
   264             contentBox.set("innerHTML", "");
       
   265 
       
   266             if (content) {
       
   267                 if (content instanceof Node) {
       
   268                     for (var i = 0, l = content.size(); i < l; ++i) {
       
   269                         contentBox.appendChild(content.item(i));
       
   270                     }
       
   271                 } else if (Lang.isString(content)) {
       
   272                     contentBox.set("innerHTML", content);
       
   273                 }
       
   274             }
       
   275         },
       
   276 
       
   277         /*
       
   278          * Gets the closest ancestor of the given node,
       
   279          * which is a tooltip trigger node
       
   280          */
       
   281         getParentTrigger : function(node) {
       
   282             var cn = this._triggerClassName;
       
   283             return (node.hasClass(cn)) ? node : node.ancestor(function(node) {return node.hasClass(cn)});
       
   284         },
       
   285 
       
   286         /*
       
   287          * Default attribute change listener for 
       
   288          * the triggerNodes attribute
       
   289          */
       
   290         _afterSetNodes : function(e) {
       
   291             this._uiSetNodes(e.newVal);
       
   292         },
       
   293 
       
   294         /*
       
   295          * Default attribute change listener for 
       
   296          * the delegate attribute
       
   297          */
       
   298         _afterSetDelegate : function(e) {
       
   299             this._bindDelegate(e.newVal);
       
   300         },
       
   301 
       
   302         /*
       
   303          * Updates the rendered DOM to reflect the
       
   304          * set of trigger nodes passed in
       
   305          */
       
   306         _uiSetNodes : function(nodes) {
       
   307             if (this._triggerNodes) {
       
   308                 this._triggerNodes.removeClass(this._triggerClassName);
       
   309             }
       
   310 
       
   311             if (nodes) {
       
   312                 this._triggerNodes = nodes;
       
   313                 this._triggerNodes.addClass(this._triggerClassName);
       
   314             }
       
   315         },
       
   316 
       
   317         /*
       
   318          * Attaches the default mouseover DOM listener to the 
       
   319          * current delegate node
       
   320          */
       
   321         _bindDelegate : function() {
       
   322             var eventHandles = this._eventHandles;
       
   323 
       
   324             if (eventHandles.delegate) {
       
   325                 eventHandles.delegate.detach();
       
   326                 eventHandles.delegate = null;
       
   327             }
       
   328             eventHandles.delegate = Y.on("mouseover", Y.bind(this._onDelegateMouseOver, this), this.get("delegate"));
       
   329         },
       
   330 
       
   331         /*
       
   332          * Default mouse over DOM event listener.
       
   333          * 
       
   334          * Delegates to the _enterTrigger method,
       
   335          * if the mouseover enters a trigger node.
       
   336          */
       
   337         _onDelegateMouseOver : function(e) {
       
   338             var node = this.getParentTrigger(e.target);
       
   339             if (node && (!this._currTrigger.node || !node.compareTo(this._currTrigger.node))) {
       
   340                 this._enterTrigger(node, e.pageX, e.pageY);
       
   341             }
       
   342         },
       
   343 
       
   344         /*
       
   345          * Default mouse out DOM event listener
       
   346          * 
       
   347          * Delegates to _leaveTrigger if the mouseout
       
   348          * leaves the current trigger node
       
   349          */
       
   350         _onNodeMouseOut : function(e) {
       
   351             var to = e.relatedTarget;
       
   352             var trigger = e.currentTarget;
       
   353 
       
   354             if (!trigger.contains(to)) {
       
   355                 this._leaveTrigger(trigger);
       
   356             }
       
   357         },
       
   358 
       
   359         /*
       
   360          * Default mouse move DOM event listener
       
   361          */
       
   362         _onNodeMouseMove : function(e) {
       
   363             this._overTrigger(e.pageX, e.pageY);
       
   364         },
       
   365 
       
   366         /*
       
   367          * Default handler invoked when the mouse enters
       
   368          * a trigger node. Fires the triggerEnter
       
   369          * event which can be prevented by listeners to 
       
   370          * show the tooltip from being displayed.
       
   371          */
       
   372         _enterTrigger : function(node, x, y) {
       
   373             this._setCurrentTrigger(node, x, y);
       
   374             this.fire("triggerEnter", {node:node, pageX:x, pageY:y});
       
   375         },
       
   376 
       
   377         /*
       
   378          * Default handler for the triggerEvent event,
       
   379          * which will setup the timer to display the tooltip,
       
   380          * if the default handler has not been prevented.
       
   381          */
       
   382         _defTriggerEnterFn : function(e) {
       
   383             var node = e.node;
       
   384             if (!this.get("disabled")) {
       
   385                 this._clearTimers();
       
   386                 var delay = (this.get("visible")) ? 0 : this.get("showDelay");
       
   387                 this._timers.show = Y.later(delay, this, this._showTooltip, [node]);
       
   388             }
       
   389         },
       
   390 
       
   391         /*
       
   392          * Default handler invoked when the mouse leaves
       
   393          * the current trigger node. Fires the triggerLeave
       
   394          * event and sets up the hide timer
       
   395          */
       
   396         _leaveTrigger : function(node) {
       
   397             this.fire("triggerLeave");
       
   398 
       
   399             this._clearCurrentTrigger();
       
   400             this._clearTimers();
       
   401 
       
   402             this._timers.hide = Y.later(this.get("hideDelay"), this, this._hideTooltip);
       
   403         },
       
   404 
       
   405         /*
       
   406          * Default handler invoked for mousemove events
       
   407          * on the trigger node. Stores the current mouse 
       
   408          * x, y positions
       
   409          */
       
   410         _overTrigger : function(x, y) {
       
   411             this._currTrigger.mouseX = x;
       
   412             this._currTrigger.mouseY = y;
       
   413         },
       
   414 
       
   415         /*
       
   416          * Shows the tooltip, after moving it to the current mouse
       
   417          * position.
       
   418          */
       
   419         _showTooltip : function(node) {
       
   420             var x = this._currTrigger.mouseX;
       
   421             var y = this._currTrigger.mouseY;
       
   422 
       
   423             this.move(x + Tooltip.OFFSET_X, y + Tooltip.OFFSET_Y);
       
   424 
       
   425             this.show();
       
   426             this._clearTimers();
       
   427 
       
   428             this._timers.hide = Y.later(this.get("autoHideDelay"), this, this._hideTooltip);
       
   429         },
       
   430 
       
   431         /*
       
   432          * Hides the tooltip, after clearing existing timers.
       
   433          */
       
   434         _hideTooltip : function() {
       
   435             this._clearTimers();
       
   436             this.hide();
       
   437         },
       
   438 
       
   439         /*
       
   440          * Set the rendered content of the tooltip for the current
       
   441          * trigger, based on (in order of precedence):
       
   442          * 
       
   443          * a). The string/node content attribute value
       
   444          * b). From the content lookup map if it is set, or 
       
   445          * c). From the title attribute if set.
       
   446          */
       
   447         _setTriggerContent : function(node) {
       
   448             var content = this.get("content");
       
   449             if (content && !(content instanceof Node || Lang.isString(content))) {
       
   450                 content = content[node.get("id")] || node.getAttribute("title");
       
   451             }
       
   452             this.setTriggerContent(content);
       
   453         },
       
   454 
       
   455         /*
       
   456          * Set the currently bound trigger node information, clearing 
       
   457          * out the title attribute if set and setting up mousemove/out 
       
   458          * listeners.
       
   459          */
       
   460         _setCurrentTrigger : function(node, x, y) {
       
   461 
       
   462             var currTrigger = this._currTrigger,
       
   463                 triggerHandles = this._eventHandles.trigger;
       
   464 
       
   465             this._setTriggerContent(node);
       
   466 
       
   467             triggerHandles.mouseMove = Y.on("mousemove", Y.bind(this._onNodeMouseMove, this), node);
       
   468             triggerHandles.mouseOut = Y.on("mouseout", Y.bind(this._onNodeMouseOut, this), node);
       
   469 
       
   470             var title = node.getAttribute("title");
       
   471             node.setAttribute("title", "");
       
   472 
       
   473             currTrigger.mouseX = x;
       
   474             currTrigger.mouseY = y;
       
   475             currTrigger.node = node;
       
   476             currTrigger.title = title;
       
   477         },
       
   478 
       
   479         /*
       
   480          * Clear out the current trigger state, restoring
       
   481          * the title attribute on the trigger node, 
       
   482          * if it was originally set.
       
   483          */
       
   484         _clearCurrentTrigger : function() {
       
   485 
       
   486             var currTrigger = this._currTrigger,
       
   487                 triggerHandles = this._eventHandles.trigger;
       
   488 
       
   489             if (currTrigger.node) {
       
   490                 var node = currTrigger.node;
       
   491                 var title = currTrigger.title || "";
       
   492 
       
   493                 currTrigger.node = null;
       
   494                 currTrigger.title = "";
       
   495 
       
   496                 triggerHandles.mouseMove.detach();
       
   497                 triggerHandles.mouseOut.detach();
       
   498                 triggerHandles.mouseMove = null;
       
   499                 triggerHandles.mouseOut = null;
       
   500 
       
   501                 node.setAttribute("title", title);
       
   502             }
       
   503         },
       
   504 
       
   505         /*
       
   506          * Cancel any existing show/hide timers
       
   507          */
       
   508         _clearTimers : function() {
       
   509             var timers = this._timers;
       
   510             if (timers.hide) {
       
   511                 timers.hide.cancel();
       
   512                 timers.hide = null;
       
   513             }
       
   514             if (timers.show) {
       
   515               timers.show.cancel();
       
   516               timers.show = null;
       
   517             }
       
   518         },
       
   519 
       
   520         /*
       
   521          * Detach any stored event handles
       
   522          */
       
   523         _clearHandles : function() {
       
   524             var eventHandles = this._eventHandles;
       
   525 
       
   526             if (eventHandles.delegate) {
       
   527                 this._eventHandles.delegate.detach();
       
   528             }
       
   529             if (eventHandles.trigger.mouseOut) {
       
   530                 eventHandles.trigger.mouseOut.detach();
       
   531             }
       
   532             if (eventHandles.trigger.mouseMove) {
       
   533                 eventHandles.trigger.mouseMove.detach();
       
   534             }
       
   535         }
       
   536     });
       
   537 
       
   538     // dynamic:false = Modify the existing Tooltip class
       
   539     Tooltip = Y.Base.build(Tooltip.NAME, Tooltip, [Y.WidgetPosition, Y.WidgetStack], {dynamic:false});
       
   540 
       
   541     var tt = new Tooltip({
       
   542         triggerNodes:".yui-hastooltip",
       
   543         delegate: "#delegate",
       
   544         content: {
       
   545             tt3: "Tooltip 3 (from lookup)"
       
   546         },
       
   547         shim:false,
       
   548         zIndex:2
       
   549     });
       
   550     tt.render();
       
   551 
       
   552     tt.on("triggerEnter", function(e) {
       
   553         var node = e.node;
       
   554         if (node && node.get("id") == "tt2") {
       
   555             this.setTriggerContent("Tooltip 2 (from triggerEvent)");
       
   556         }
       
   557     });
       
   558 
       
   559     var prevent = Y.one("#prevent");
       
   560     tt.on("triggerEnter", function(e) {
       
   561         var node = e.node;
       
   562         if (prevent.get("checked")) {
       
   563             if (node && node.get("id") == "tt4") {
       
   564                 e.preventDefault();
       
   565             }
       
   566         }
       
   567     });
       
   568 });
       
   569 </script>
       
   570 
       
   571 <!--END SOURCE CODE FOR EXAMPLE =============================== -->
       
   572 
       
   573 </body>
       
   574 </html>