Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1123 lines
37 KiB

  1. /*!
  2. * Ext JS Library 3.2.0
  3. * Copyright(c) 2006-2010 Ext JS, Inc.
  4. * licensing@extjs.com
  5. * http://www.extjs.com/license
  6. */
  7. /**
  8. * @class Ext.Tip
  9. * @extends Ext.Panel
  10. * @xtype tip
  11. * This is the base class for {@link Ext.QuickTip} and {@link Ext.Tooltip} that provides the basic layout and
  12. * positioning that all tip-based classes require. This class can be used directly for simple, statically-positioned
  13. * tips that are displayed programmatically, or it can be extended to provide custom tip implementations.
  14. * @constructor
  15. * Create a new Tip
  16. * @param {Object} config The configuration options
  17. */
  18. Ext.Tip = Ext.extend(Ext.Panel, {
  19. /**
  20. * @cfg {Boolean} closable True to render a close tool button into the tooltip header (defaults to false).
  21. */
  22. /**
  23. * @cfg {Number} width
  24. * Width in pixels of the tip (defaults to auto). Width will be ignored if it exceeds the bounds of
  25. * {@link #minWidth} or {@link #maxWidth}. The maximum supported value is 500.
  26. */
  27. /**
  28. * @cfg {Number} minWidth The minimum width of the tip in pixels (defaults to 40).
  29. */
  30. minWidth : 40,
  31. /**
  32. * @cfg {Number} maxWidth The maximum width of the tip in pixels (defaults to 300). The maximum supported value is 500.
  33. */
  34. maxWidth : 300,
  35. /**
  36. * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
  37. * for bottom-right shadow (defaults to "sides").
  38. */
  39. shadow : "sides",
  40. /**
  41. * @cfg {String} defaultAlign <b>Experimental</b>. The default {@link Ext.Element#alignTo} anchor position value
  42. * for this tip relative to its element of origin (defaults to "tl-bl?").
  43. */
  44. defaultAlign : "tl-bl?",
  45. autoRender: true,
  46. quickShowInterval : 250,
  47. // private panel overrides
  48. frame:true,
  49. hidden:true,
  50. baseCls: 'x-tip',
  51. floating:{shadow:true,shim:true,useDisplay:true,constrain:false},
  52. autoHeight:true,
  53. closeAction: 'hide',
  54. // private
  55. initComponent : function(){
  56. Ext.Tip.superclass.initComponent.call(this);
  57. if(this.closable && !this.title){
  58. this.elements += ',header';
  59. }
  60. },
  61. // private
  62. afterRender : function(){
  63. Ext.Tip.superclass.afterRender.call(this);
  64. if(this.closable){
  65. this.addTool({
  66. id: 'close',
  67. handler: this[this.closeAction],
  68. scope: this
  69. });
  70. }
  71. },
  72. /**
  73. * Shows this tip at the specified XY position. Example usage:
  74. * <pre><code>
  75. // Show the tip at x:50 and y:100
  76. tip.showAt([50,100]);
  77. </code></pre>
  78. * @param {Array} xy An array containing the x and y coordinates
  79. */
  80. showAt : function(xy){
  81. Ext.Tip.superclass.show.call(this);
  82. if(this.measureWidth !== false && (!this.initialConfig || typeof this.initialConfig.width != 'number')){
  83. this.doAutoWidth();
  84. }
  85. if(this.constrainPosition){
  86. xy = this.el.adjustForConstraints(xy);
  87. }
  88. this.setPagePosition(xy[0], xy[1]);
  89. },
  90. // protected
  91. doAutoWidth : function(adjust){
  92. adjust = adjust || 0;
  93. var bw = this.body.getTextWidth();
  94. if(this.title){
  95. bw = Math.max(bw, this.header.child('span').getTextWidth(this.title));
  96. }
  97. bw += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr") + adjust;
  98. this.setWidth(bw.constrain(this.minWidth, this.maxWidth));
  99. // IE7 repaint bug on initial show
  100. if(Ext.isIE7 && !this.repainted){
  101. this.el.repaint();
  102. this.repainted = true;
  103. }
  104. },
  105. /**
  106. * <b>Experimental</b>. Shows this tip at a position relative to another element using a standard {@link Ext.Element#alignTo}
  107. * anchor position value. Example usage:
  108. * <pre><code>
  109. // Show the tip at the default position ('tl-br?')
  110. tip.showBy('my-el');
  111. // Show the tip's top-left corner anchored to the element's top-right corner
  112. tip.showBy('my-el', 'tl-tr');
  113. </code></pre>
  114. * @param {Mixed} el An HTMLElement, Ext.Element or string id of the target element to align to
  115. * @param {String} position (optional) A valid {@link Ext.Element#alignTo} anchor position (defaults to 'tl-br?' or
  116. * {@link #defaultAlign} if specified).
  117. */
  118. showBy : function(el, pos){
  119. if(!this.rendered){
  120. this.render(Ext.getBody());
  121. }
  122. this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign));
  123. },
  124. initDraggable : function(){
  125. this.dd = new Ext.Tip.DD(this, typeof this.draggable == 'boolean' ? null : this.draggable);
  126. this.header.addClass('x-tip-draggable');
  127. }
  128. });
  129. Ext.reg('tip', Ext.Tip);
  130. // private - custom Tip DD implementation
  131. Ext.Tip.DD = function(tip, config){
  132. Ext.apply(this, config);
  133. this.tip = tip;
  134. Ext.Tip.DD.superclass.constructor.call(this, tip.el.id, 'WindowDD-'+tip.id);
  135. this.setHandleElId(tip.header.id);
  136. this.scroll = false;
  137. };
  138. Ext.extend(Ext.Tip.DD, Ext.dd.DD, {
  139. moveOnly:true,
  140. scroll:false,
  141. headerOffsets:[100, 25],
  142. startDrag : function(){
  143. this.tip.el.disableShadow();
  144. },
  145. endDrag : function(e){
  146. this.tip.el.enableShadow(true);
  147. }
  148. });/**
  149. * @class Ext.ToolTip
  150. * @extends Ext.Tip
  151. * A standard tooltip implementation for providing additional information when hovering over a target element.
  152. * @xtype tooltip
  153. * @constructor
  154. * Create a new Tooltip
  155. * @param {Object} config The configuration options
  156. */
  157. Ext.ToolTip = Ext.extend(Ext.Tip, {
  158. /**
  159. * When a Tooltip is configured with the <code>{@link #delegate}</code>
  160. * option to cause selected child elements of the <code>{@link #target}</code>
  161. * Element to each trigger a seperate show event, this property is set to
  162. * the DOM element which triggered the show.
  163. * @type DOMElement
  164. * @property triggerElement
  165. */
  166. /**
  167. * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to monitor
  168. * for mouseover events to trigger showing this ToolTip.
  169. */
  170. /**
  171. * @cfg {Boolean} autoHide True to automatically hide the tooltip after the
  172. * mouse exits the target element or after the <code>{@link #dismissDelay}</code>
  173. * has expired if set (defaults to true). If <code>{@link closable} = true</code>
  174. * a close tool button will be rendered into the tooltip header.
  175. */
  176. /**
  177. * @cfg {Number} showDelay Delay in milliseconds before the tooltip displays
  178. * after the mouse enters the target element (defaults to 500)
  179. */
  180. showDelay : 500,
  181. /**
  182. * @cfg {Number} hideDelay Delay in milliseconds after the mouse exits the
  183. * target element but before the tooltip actually hides (defaults to 200).
  184. * Set to 0 for the tooltip to hide immediately.
  185. */
  186. hideDelay : 200,
  187. /**
  188. * @cfg {Number} dismissDelay Delay in milliseconds before the tooltip
  189. * automatically hides (defaults to 5000). To disable automatic hiding, set
  190. * dismissDelay = 0.
  191. */
  192. dismissDelay : 5000,
  193. /**
  194. * @cfg {Array} mouseOffset An XY offset from the mouse position where the
  195. * tooltip should be shown (defaults to [15,18]).
  196. */
  197. /**
  198. * @cfg {Boolean} trackMouse True to have the tooltip follow the mouse as it
  199. * moves over the target element (defaults to false).
  200. */
  201. trackMouse : false,
  202. /**
  203. * @cfg {Boolean} anchorToTarget True to anchor the tooltip to the target
  204. * element, false to anchor it relative to the mouse coordinates (defaults
  205. * to true). When <code>anchorToTarget</code> is true, use
  206. * <code>{@link #defaultAlign}</code> to control tooltip alignment to the
  207. * target element. When <code>anchorToTarget</code> is false, use
  208. * <code>{@link #anchorPosition}</code> instead to control alignment.
  209. */
  210. anchorToTarget : true,
  211. /**
  212. * @cfg {Number} anchorOffset A numeric pixel value used to offset the
  213. * default position of the anchor arrow (defaults to 0). When the anchor
  214. * position is on the top or bottom of the tooltip, <code>anchorOffset</code>
  215. * will be used as a horizontal offset. Likewise, when the anchor position
  216. * is on the left or right side, <code>anchorOffset</code> will be used as
  217. * a vertical offset.
  218. */
  219. anchorOffset : 0,
  220. /**
  221. * @cfg {String} delegate <p>Optional. A {@link Ext.DomQuery DomQuery}
  222. * selector which allows selection of individual elements within the
  223. * <code>{@link #target}</code> element to trigger showing and hiding the
  224. * ToolTip as the mouse moves within the target.</p>
  225. * <p>When specified, the child element of the target which caused a show
  226. * event is placed into the <code>{@link #triggerElement}</code> property
  227. * before the ToolTip is shown.</p>
  228. * <p>This may be useful when a Component has regular, repeating elements
  229. * in it, each of which need a Tooltip which contains information specific
  230. * to that element. For example:</p><pre><code>
  231. var myGrid = new Ext.grid.gridPanel(gridConfig);
  232. myGrid.on('render', function(grid) {
  233. var store = grid.getStore(); // Capture the Store.
  234. var view = grid.getView(); // Capture the GridView.
  235. myGrid.tip = new Ext.ToolTip({
  236. target: view.mainBody, // The overall target element.
  237. delegate: '.x-grid3-row', // Each grid row causes its own seperate show and hide.
  238. trackMouse: true, // Moving within the row should not hide the tip.
  239. renderTo: document.body, // Render immediately so that tip.body can be
  240. // referenced prior to the first show.
  241. listeners: { // Change content dynamically depending on which element
  242. // triggered the show.
  243. beforeshow: function updateTipBody(tip) {
  244. var rowIndex = view.findRowIndex(tip.triggerElement);
  245. tip.body.dom.innerHTML = 'Over Record ID ' + store.getAt(rowIndex).id;
  246. }
  247. }
  248. });
  249. });
  250. *</code></pre>
  251. */
  252. // private
  253. targetCounter : 0,
  254. constrainPosition : false,
  255. // private
  256. initComponent : function(){
  257. Ext.ToolTip.superclass.initComponent.call(this);
  258. this.lastActive = new Date();
  259. this.initTarget(this.target);
  260. this.origAnchor = this.anchor;
  261. },
  262. // private
  263. onRender : function(ct, position){
  264. Ext.ToolTip.superclass.onRender.call(this, ct, position);
  265. this.anchorCls = 'x-tip-anchor-' + this.getAnchorPosition();
  266. this.anchorEl = this.el.createChild({
  267. cls: 'x-tip-anchor ' + this.anchorCls
  268. });
  269. },
  270. // private
  271. afterRender : function(){
  272. Ext.ToolTip.superclass.afterRender.call(this);
  273. this.anchorEl.setStyle('z-index', this.el.getZIndex() + 1);
  274. },
  275. /**
  276. * Binds this ToolTip to the specified element. The tooltip will be displayed when the mouse moves over the element.
  277. * @param {Mixed} t The Element, HtmlElement, or ID of an element to bind to
  278. */
  279. initTarget : function(target){
  280. var t;
  281. if((t = Ext.get(target))){
  282. if(this.target){
  283. var tg = Ext.get(this.target);
  284. this.mun(tg, 'mouseover', this.onTargetOver, this);
  285. this.mun(tg, 'mouseout', this.onTargetOut, this);
  286. this.mun(tg, 'mousemove', this.onMouseMove, this);
  287. }
  288. this.mon(t, {
  289. mouseover: this.onTargetOver,
  290. mouseout: this.onTargetOut,
  291. mousemove: this.onMouseMove,
  292. scope: this
  293. });
  294. this.target = t;
  295. }
  296. if(this.anchor){
  297. this.anchorTarget = this.target;
  298. }
  299. },
  300. // private
  301. onMouseMove : function(e){
  302. var t = this.delegate ? e.getTarget(this.delegate) : this.triggerElement = true;
  303. if (t) {
  304. this.targetXY = e.getXY();
  305. if (t === this.triggerElement) {
  306. if(!this.hidden && this.trackMouse){
  307. this.setPagePosition(this.getTargetXY());
  308. }
  309. } else {
  310. this.hide();
  311. this.lastActive = new Date(0);
  312. this.onTargetOver(e);
  313. }
  314. } else if (!this.closable && this.isVisible()) {
  315. this.hide();
  316. }
  317. },
  318. // private
  319. getTargetXY : function(){
  320. if(this.delegate){
  321. this.anchorTarget = this.triggerElement;
  322. }
  323. if(this.anchor){
  324. this.targetCounter++;
  325. var offsets = this.getOffsets(),
  326. xy = (this.anchorToTarget && !this.trackMouse) ? this.el.getAlignToXY(this.anchorTarget, this.getAnchorAlign()) : this.targetXY,
  327. dw = Ext.lib.Dom.getViewWidth() - 5,
  328. dh = Ext.lib.Dom.getViewHeight() - 5,
  329. de = document.documentElement,
  330. bd = document.body,
  331. scrollX = (de.scrollLeft || bd.scrollLeft || 0) + 5,
  332. scrollY = (de.scrollTop || bd.scrollTop || 0) + 5,
  333. axy = [xy[0] + offsets[0], xy[1] + offsets[1]],
  334. sz = this.getSize();
  335. this.anchorEl.removeClass(this.anchorCls);
  336. if(this.targetCounter < 2){
  337. if(axy[0] < scrollX){
  338. if(this.anchorToTarget){
  339. this.defaultAlign = 'l-r';
  340. if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  341. }
  342. this.anchor = 'left';
  343. return this.getTargetXY();
  344. }
  345. if(axy[0]+sz.width > dw){
  346. if(this.anchorToTarget){
  347. this.defaultAlign = 'r-l';
  348. if(this.mouseOffset){this.mouseOffset[0] *= -1;}
  349. }
  350. this.anchor = 'right';
  351. return this.getTargetXY();
  352. }
  353. if(axy[1] < scrollY){
  354. if(this.anchorToTarget){
  355. this.defaultAlign = 't-b';
  356. if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  357. }
  358. this.anchor = 'top';
  359. return this.getTargetXY();
  360. }
  361. if(axy[1]+sz.height > dh){
  362. if(this.anchorToTarget){
  363. this.defaultAlign = 'b-t';
  364. if(this.mouseOffset){this.mouseOffset[1] *= -1;}
  365. }
  366. this.anchor = 'bottom';
  367. return this.getTargetXY();
  368. }
  369. }
  370. this.anchorCls = 'x-tip-anchor-'+this.getAnchorPosition();
  371. this.anchorEl.addClass(this.anchorCls);
  372. this.targetCounter = 0;
  373. return axy;
  374. }else{
  375. var mouseOffset = this.getMouseOffset();
  376. return [this.targetXY[0]+mouseOffset[0], this.targetXY[1]+mouseOffset[1]];
  377. }
  378. },
  379. getMouseOffset : function(){
  380. var offset = this.anchor ? [0,0] : [15,18];
  381. if(this.mouseOffset){
  382. offset[0] += this.mouseOffset[0];
  383. offset[1] += this.mouseOffset[1];
  384. }
  385. return offset;
  386. },
  387. // private
  388. getAnchorPosition : function(){
  389. if(this.anchor){
  390. this.tipAnchor = this.anchor.charAt(0);
  391. }else{
  392. var m = this.defaultAlign.match(/^([a-z]+)-([a-z]+)(\?)?$/);
  393. if(!m){
  394. throw 'AnchorTip.defaultAlign is invalid';
  395. }
  396. this.tipAnchor = m[1].charAt(0);
  397. }
  398. switch(this.tipAnchor){
  399. case 't': return 'top';
  400. case 'b': return 'bottom';
  401. case 'r': return 'right';
  402. }
  403. return 'left';
  404. },
  405. // private
  406. getAnchorAlign : function(){
  407. switch(this.anchor){
  408. case 'top' : return 'tl-bl';
  409. case 'left' : return 'tl-tr';
  410. case 'right': return 'tr-tl';
  411. default : return 'bl-tl';
  412. }
  413. },
  414. // private
  415. getOffsets : function(){
  416. var offsets,
  417. ap = this.getAnchorPosition().charAt(0);
  418. if(this.anchorToTarget && !this.trackMouse){
  419. switch(ap){
  420. case 't':
  421. offsets = [0, 9];
  422. break;
  423. case 'b':
  424. offsets = [0, -13];
  425. break;
  426. case 'r':
  427. offsets = [-13, 0];
  428. break;
  429. default:
  430. offsets = [9, 0];
  431. break;
  432. }
  433. }else{
  434. switch(ap){
  435. case 't':
  436. offsets = [-15-this.anchorOffset, 30];
  437. break;
  438. case 'b':
  439. offsets = [-19-this.anchorOffset, -13-this.el.dom.offsetHeight];
  440. break;
  441. case 'r':
  442. offsets = [-15-this.el.dom.offsetWidth, -13-this.anchorOffset];
  443. break;
  444. default:
  445. offsets = [25, -13-this.anchorOffset];
  446. break;
  447. }
  448. }
  449. var mouseOffset = this.getMouseOffset();
  450. offsets[0] += mouseOffset[0];
  451. offsets[1] += mouseOffset[1];
  452. return offsets;
  453. },
  454. // private
  455. onTargetOver : function(e){
  456. if(this.disabled || e.within(this.target.dom, true)){
  457. return;
  458. }
  459. var t = e.getTarget(this.delegate);
  460. if (t) {
  461. this.triggerElement = t;
  462. this.clearTimer('hide');
  463. this.targetXY = e.getXY();
  464. this.delayShow();
  465. }
  466. },
  467. // private
  468. delayShow : function(){
  469. if(this.hidden && !this.showTimer){
  470. if(this.lastActive.getElapsed() < this.quickShowInterval){
  471. this.show();
  472. }else{
  473. this.showTimer = this.show.defer(this.showDelay, this);
  474. }
  475. }else if(!this.hidden && this.autoHide !== false){
  476. this.show();
  477. }
  478. },
  479. // private
  480. onTargetOut : function(e){
  481. if(this.disabled || e.within(this.target.dom, true)){
  482. return;
  483. }
  484. this.clearTimer('show');
  485. if(this.autoHide !== false){
  486. this.delayHide();
  487. }
  488. },
  489. // private
  490. delayHide : function(){
  491. if(!this.hidden && !this.hideTimer){
  492. this.hideTimer = this.hide.defer(this.hideDelay, this);
  493. }
  494. },
  495. /**
  496. * Hides this tooltip if visible.
  497. */
  498. hide: function(){
  499. this.clearTimer('dismiss');
  500. this.lastActive = new Date();
  501. if(this.anchorEl){
  502. this.anchorEl.hide();
  503. }
  504. Ext.ToolTip.superclass.hide.call(this);
  505. delete this.triggerElement;
  506. },
  507. /**
  508. * Shows this tooltip at the current event target XY position.
  509. */
  510. show : function(){
  511. if(this.anchor){
  512. // pre-show it off screen so that the el will have dimensions
  513. // for positioning calcs when getting xy next
  514. this.showAt([-1000,-1000]);
  515. this.origConstrainPosition = this.constrainPosition;
  516. this.constrainPosition = false;
  517. this.anchor = this.origAnchor;
  518. }
  519. this.showAt(this.getTargetXY());
  520. if(this.anchor){
  521. this.syncAnchor();
  522. this.anchorEl.show();
  523. this.constrainPosition = this.origConstrainPosition;
  524. }else{
  525. this.anchorEl.hide();
  526. }
  527. },
  528. // inherit docs
  529. showAt : function(xy){
  530. this.lastActive = new Date();
  531. this.clearTimers();
  532. Ext.ToolTip.superclass.showAt.call(this, xy);
  533. if(this.dismissDelay && this.autoHide !== false){
  534. this.dismissTimer = this.hide.defer(this.dismissDelay, this);
  535. }
  536. if(this.anchor && !this.anchorEl.isVisible()){
  537. this.syncAnchor();
  538. this.anchorEl.show();
  539. }
  540. },
  541. // private
  542. syncAnchor : function(){
  543. var anchorPos, targetPos, offset;
  544. switch(this.tipAnchor.charAt(0)){
  545. case 't':
  546. anchorPos = 'b';
  547. targetPos = 'tl';
  548. offset = [20+this.anchorOffset, 2];
  549. break;
  550. case 'r':
  551. anchorPos = 'l';
  552. targetPos = 'tr';
  553. offset = [-2, 11+this.anchorOffset];
  554. break;
  555. case 'b':
  556. anchorPos = 't';
  557. targetPos = 'bl';
  558. offset = [20+this.anchorOffset, -2];
  559. break;
  560. default:
  561. anchorPos = 'r';
  562. targetPos = 'tl';
  563. offset = [2, 11+this.anchorOffset];
  564. break;
  565. }
  566. this.anchorEl.alignTo(this.el, anchorPos+'-'+targetPos, offset);
  567. },
  568. // private
  569. setPagePosition : function(x, y){
  570. Ext.ToolTip.superclass.setPagePosition.call(this, x, y);
  571. if(this.anchor){
  572. this.syncAnchor();
  573. }
  574. },
  575. // private
  576. clearTimer : function(name){
  577. name = name + 'Timer';
  578. clearTimeout(this[name]);
  579. delete this[name];
  580. },
  581. // private
  582. clearTimers : function(){
  583. this.clearTimer('show');
  584. this.clearTimer('dismiss');
  585. this.clearTimer('hide');
  586. },
  587. // private
  588. onShow : function(){
  589. Ext.ToolTip.superclass.onShow.call(this);
  590. Ext.getDoc().on('mousedown', this.onDocMouseDown, this);
  591. },
  592. // private
  593. onHide : function(){
  594. Ext.ToolTip.superclass.onHide.call(this);
  595. Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  596. },
  597. // private
  598. onDocMouseDown : function(e){
  599. if(this.autoHide !== true && !this.closable && !e.within(this.el.dom)){
  600. this.disable();
  601. this.doEnable.defer(100, this);
  602. }
  603. },
  604. // private
  605. doEnable : function(){
  606. if(!this.isDestroyed){
  607. this.enable();
  608. }
  609. },
  610. // private
  611. onDisable : function(){
  612. this.clearTimers();
  613. this.hide();
  614. },
  615. // private
  616. adjustPosition : function(x, y){
  617. if(this.contstrainPosition){
  618. var ay = this.targetXY[1], h = this.getSize().height;
  619. if(y <= ay && (y+h) >= ay){
  620. y = ay-h-5;
  621. }
  622. }
  623. return {x : x, y: y};
  624. },
  625. beforeDestroy : function(){
  626. this.clearTimers();
  627. Ext.destroy(this.anchorEl);
  628. delete this.anchorEl;
  629. delete this.target;
  630. delete this.anchorTarget;
  631. delete this.triggerElement;
  632. Ext.ToolTip.superclass.beforeDestroy.call(this);
  633. },
  634. // private
  635. onDestroy : function(){
  636. Ext.getDoc().un('mousedown', this.onDocMouseDown, this);
  637. Ext.ToolTip.superclass.onDestroy.call(this);
  638. }
  639. });
  640. Ext.reg('tooltip', Ext.ToolTip);/**
  641. * @class Ext.QuickTip
  642. * @extends Ext.ToolTip
  643. * @xtype quicktip
  644. * A specialized tooltip class for tooltips that can be specified in markup and automatically managed by the global
  645. * {@link Ext.QuickTips} instance. See the QuickTips class header for additional usage details and examples.
  646. * @constructor
  647. * Create a new Tip
  648. * @param {Object} config The configuration options
  649. */
  650. Ext.QuickTip = Ext.extend(Ext.ToolTip, {
  651. /**
  652. * @cfg {Mixed} target The target HTMLElement, Ext.Element or id to associate with this quicktip (defaults to the document).
  653. */
  654. /**
  655. * @cfg {Boolean} interceptTitles True to automatically use the element's DOM title value if available (defaults to false).
  656. */
  657. interceptTitles : false,
  658. // private
  659. tagConfig : {
  660. namespace : "ext",
  661. attribute : "qtip",
  662. width : "qwidth",
  663. target : "target",
  664. title : "qtitle",
  665. hide : "hide",
  666. cls : "qclass",
  667. align : "qalign",
  668. anchor : "anchor"
  669. },
  670. // private
  671. initComponent : function(){
  672. this.target = this.target || Ext.getDoc();
  673. this.targets = this.targets || {};
  674. Ext.QuickTip.superclass.initComponent.call(this);
  675. },
  676. /**
  677. * Configures a new quick tip instance and assigns it to a target element. The following config values are
  678. * supported (for example usage, see the {@link Ext.QuickTips} class header):
  679. * <div class="mdetail-params"><ul>
  680. * <li>autoHide</li>
  681. * <li>cls</li>
  682. * <li>dismissDelay (overrides the singleton value)</li>
  683. * <li>target (required)</li>
  684. * <li>text (required)</li>
  685. * <li>title</li>
  686. * <li>width</li></ul></div>
  687. * @param {Object} config The config object
  688. */
  689. register : function(config){
  690. var cs = Ext.isArray(config) ? config : arguments;
  691. for(var i = 0, len = cs.length; i < len; i++){
  692. var c = cs[i];
  693. var target = c.target;
  694. if(target){
  695. if(Ext.isArray(target)){
  696. for(var j = 0, jlen = target.length; j < jlen; j++){
  697. this.targets[Ext.id(target[j])] = c;
  698. }
  699. } else{
  700. this.targets[Ext.id(target)] = c;
  701. }
  702. }
  703. }
  704. },
  705. /**
  706. * Removes this quick tip from its element and destroys it.
  707. * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
  708. */
  709. unregister : function(el){
  710. delete this.targets[Ext.id(el)];
  711. },
  712. /**
  713. * Hides a visible tip or cancels an impending show for a particular element.
  714. * @param {String/HTMLElement/Element} el The element that is the target of the tip.
  715. */
  716. cancelShow: function(el){
  717. var at = this.activeTarget;
  718. el = Ext.get(el).dom;
  719. if(this.isVisible()){
  720. if(at && at.el == el){
  721. this.hide();
  722. }
  723. }else if(at && at.el == el){
  724. this.clearTimer('show');
  725. }
  726. },
  727. getTipCfg: function(e) {
  728. var t = e.getTarget(),
  729. ttp,
  730. cfg;
  731. if(this.interceptTitles && t.title && Ext.isString(t.title)){
  732. ttp = t.title;
  733. t.qtip = ttp;
  734. t.removeAttribute("title");
  735. e.preventDefault();
  736. }else{
  737. cfg = this.tagConfig;
  738. ttp = t.qtip || Ext.fly(t).getAttribute(cfg.attribute, cfg.namespace);
  739. }
  740. return ttp;
  741. },
  742. // private
  743. onTargetOver : function(e){
  744. if(this.disabled){
  745. return;
  746. }
  747. this.targetXY = e.getXY();
  748. var t = e.getTarget();
  749. if(!t || t.nodeType !== 1 || t == document || t == document.body){
  750. return;
  751. }
  752. if(this.activeTarget && ((t == this.activeTarget.el) || Ext.fly(this.activeTarget.el).contains(t))){
  753. this.clearTimer('hide');
  754. this.show();
  755. return;
  756. }
  757. if(t && this.targets[t.id]){
  758. this.activeTarget = this.targets[t.id];
  759. this.activeTarget.el = t;
  760. this.anchor = this.activeTarget.anchor;
  761. if(this.anchor){
  762. this.anchorTarget = t;
  763. }
  764. this.delayShow();
  765. return;
  766. }
  767. var ttp, et = Ext.fly(t), cfg = this.tagConfig, ns = cfg.namespace;
  768. if(ttp = this.getTipCfg(e)){
  769. var autoHide = et.getAttribute(cfg.hide, ns);
  770. this.activeTarget = {
  771. el: t,
  772. text: ttp,
  773. width: et.getAttribute(cfg.width, ns),
  774. autoHide: autoHide != "user" && autoHide !== 'false',
  775. title: et.getAttribute(cfg.title, ns),
  776. cls: et.getAttribute(cfg.cls, ns),
  777. align: et.getAttribute(cfg.align, ns)
  778. };
  779. this.anchor = et.getAttribute(cfg.anchor, ns);
  780. if(this.anchor){
  781. this.anchorTarget = t;
  782. }
  783. this.delayShow();
  784. }
  785. },
  786. // private
  787. onTargetOut : function(e){
  788. // If moving within the current target, and it does not have a new tip, ignore the mouseout
  789. if (this.activeTarget && e.within(this.activeTarget.el) && !this.getTipCfg(e)) {
  790. return;
  791. }
  792. this.clearTimer('show');
  793. if(this.autoHide !== false){
  794. this.delayHide();
  795. }
  796. },
  797. // inherit docs
  798. showAt : function(xy){
  799. var t = this.activeTarget;
  800. if(t){
  801. if(!this.rendered){
  802. this.render(Ext.getBody());
  803. this.activeTarget = t;
  804. }
  805. if(t.width){
  806. this.setWidth(t.width);
  807. this.body.setWidth(this.adjustBodyWidth(t.width - this.getFrameWidth()));
  808. this.measureWidth = false;
  809. } else{
  810. this.measureWidth = true;
  811. }
  812. this.setTitle(t.title || '');
  813. this.body.update(t.text);
  814. this.autoHide = t.autoHide;
  815. this.dismissDelay = t.dismissDelay || this.dismissDelay;
  816. if(this.lastCls){
  817. this.el.removeClass(this.lastCls);
  818. delete this.lastCls;
  819. }
  820. if(t.cls){
  821. this.el.addClass(t.cls);
  822. this.lastCls = t.cls;
  823. }
  824. if(this.anchor){
  825. this.constrainPosition = false;
  826. }else if(t.align){ // TODO: this doesn't seem to work consistently
  827. xy = this.el.getAlignToXY(t.el, t.align);
  828. this.constrainPosition = false;
  829. }else{
  830. this.constrainPosition = true;
  831. }
  832. }
  833. Ext.QuickTip.superclass.showAt.call(this, xy);
  834. },
  835. // inherit docs
  836. hide: function(){
  837. delete this.activeTarget;
  838. Ext.QuickTip.superclass.hide.call(this);
  839. }
  840. });
  841. Ext.reg('quicktip', Ext.QuickTip);/**
  842. * @class Ext.QuickTips
  843. * <p>Provides attractive and customizable tooltips for any element. The QuickTips
  844. * singleton is used to configure and manage tooltips globally for multiple elements
  845. * in a generic manner. To create individual tooltips with maximum customizability,
  846. * you should consider either {@link Ext.Tip} or {@link Ext.ToolTip}.</p>
  847. * <p>Quicktips can be configured via tag attributes directly in markup, or by
  848. * registering quick tips programmatically via the {@link #register} method.</p>
  849. * <p>The singleton's instance of {@link Ext.QuickTip} is available via
  850. * {@link #getQuickTip}, and supports all the methods, and all the all the
  851. * configuration properties of Ext.QuickTip. These settings will apply to all
  852. * tooltips shown by the singleton.</p>
  853. * <p>Below is the summary of the configuration properties which can be used.
  854. * For detailed descriptions see {@link #getQuickTip}</p>
  855. * <p><b>QuickTips singleton configs (all are optional)</b></p>
  856. * <div class="mdetail-params"><ul><li>dismissDelay</li>
  857. * <li>hideDelay</li>
  858. * <li>maxWidth</li>
  859. * <li>minWidth</li>
  860. * <li>showDelay</li>
  861. * <li>trackMouse</li></ul></div>
  862. * <p><b>Target element configs (optional unless otherwise noted)</b></p>
  863. * <div class="mdetail-params"><ul><li>autoHide</li>
  864. * <li>cls</li>
  865. * <li>dismissDelay (overrides singleton value)</li>
  866. * <li>target (required)</li>
  867. * <li>text (required)</li>
  868. * <li>title</li>
  869. * <li>width</li></ul></div>
  870. * <p>Here is an example showing how some of these config options could be used:</p>
  871. * <pre><code>
  872. // Init the singleton. Any tag-based quick tips will start working.
  873. Ext.QuickTips.init();
  874. // Apply a set of config properties to the singleton
  875. Ext.apply(Ext.QuickTips.getQuickTip(), {
  876. maxWidth: 200,
  877. minWidth: 100,
  878. showDelay: 50,
  879. trackMouse: true
  880. });
  881. // Manually register a quick tip for a specific element
  882. Ext.QuickTips.register({
  883. target: 'my-div',
  884. title: 'My Tooltip',
  885. text: 'This tooltip was added in code',
  886. width: 100,
  887. dismissDelay: 20
  888. });
  889. </code></pre>
  890. * <p>To register a quick tip in markup, you simply add one or more of the valid QuickTip attributes prefixed with
  891. * the <b>ext:</b> namespace. The HTML element itself is automatically set as the quick tip target. Here is the summary
  892. * of supported attributes (optional unless otherwise noted):</p>
  893. * <ul><li><b>hide</b>: Specifying "user" is equivalent to setting autoHide = false. Any other value will be the
  894. * same as autoHide = true.</li>
  895. * <li><b>qclass</b>: A CSS class to be applied to the quick tip (equivalent to the 'cls' target element config).</li>
  896. * <li><b>qtip (required)</b>: The quick tip text (equivalent to the 'text' target element config).</li>
  897. * <li><b>qtitle</b>: The quick tip title (equivalent to the 'title' target element config).</li>
  898. * <li><b>qwidth</b>: The quick tip width (equivalent to the 'width' target element config).</li></ul>
  899. * <p>Here is an example of configuring an HTML element to display a tooltip from markup:</p>
  900. * <pre><code>
  901. // Add a quick tip to an HTML button
  902. &lt;input type="button" value="OK" ext:qtitle="OK Button" ext:qwidth="100"
  903. ext:qtip="This is a quick tip from markup!">&lt;/input>
  904. </code></pre>
  905. * @singleton
  906. */
  907. Ext.QuickTips = function(){
  908. var tip, locks = [];
  909. return {
  910. /**
  911. * Initialize the global QuickTips instance and prepare any quick tips.
  912. * @param {Boolean} autoRender True to render the QuickTips container immediately to preload images. (Defaults to true)
  913. */
  914. init : function(autoRender){
  915. if(!tip){
  916. if(!Ext.isReady){
  917. Ext.onReady(function(){
  918. Ext.QuickTips.init(autoRender);
  919. });
  920. return;
  921. }
  922. tip = new Ext.QuickTip({elements:'header,body'});
  923. if(autoRender !== false){
  924. tip.render(Ext.getBody());
  925. }
  926. }
  927. },
  928. /**
  929. * Enable quick tips globally.
  930. */
  931. enable : function(){
  932. if(tip){
  933. locks.pop();
  934. if(locks.length < 1){
  935. tip.enable();
  936. }
  937. }
  938. },
  939. /**
  940. * Disable quick tips globally.
  941. */
  942. disable : function(){
  943. if(tip){
  944. tip.disable();
  945. }
  946. locks.push(1);
  947. },
  948. /**
  949. * Returns true if quick tips are enabled, else false.
  950. * @return {Boolean}
  951. */
  952. isEnabled : function(){
  953. return tip !== undefined && !tip.disabled;
  954. },
  955. /**
  956. * Gets the global QuickTips instance.
  957. */
  958. getQuickTip : function(){
  959. return tip;
  960. },
  961. /**
  962. * Configures a new quick tip instance and assigns it to a target element. See
  963. * {@link Ext.QuickTip#register} for details.
  964. * @param {Object} config The config object
  965. */
  966. register : function(){
  967. tip.register.apply(tip, arguments);
  968. },
  969. /**
  970. * Removes any registered quick tip from the target element and destroys it.
  971. * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
  972. */
  973. unregister : function(){
  974. tip.unregister.apply(tip, arguments);
  975. },
  976. /**
  977. * Alias of {@link #register}.
  978. * @param {Object} config The config object
  979. */
  980. tips :function(){
  981. tip.register.apply(tip, arguments);
  982. }
  983. }
  984. }();/**
  985. * @class Ext.slider.Tip
  986. * @extends Ext.Tip
  987. * Simple plugin for using an Ext.Tip with a slider to show the slider value. Example usage:
  988. <pre>
  989. new Ext.Slider({
  990. width: 214,
  991. minValue: 0,
  992. maxValue: 100,
  993. plugins: new Ext.slider.Tip()
  994. });
  995. </pre>
  996. * Optionally provide your own tip text by overriding getText:
  997. <pre>
  998. new Ext.Slider({
  999. width: 214,
  1000. minValue: 0,
  1001. maxValue: 100,
  1002. plugins: new Ext.slider.Tip({
  1003. getText: function(thumb){
  1004. return String.format('<b>{0}% complete</b>', thumb.value);
  1005. }
  1006. })
  1007. });
  1008. </pre>
  1009. */
  1010. Ext.slider.Tip = Ext.extend(Ext.Tip, {
  1011. minWidth: 10,
  1012. offsets : [0, -10],
  1013. init: function(slider) {
  1014. slider.on({
  1015. scope : this,
  1016. dragstart: this.onSlide,
  1017. drag : this.onSlide,
  1018. dragend : this.hide,
  1019. destroy : this.destroy
  1020. });
  1021. },
  1022. /**
  1023. * @private
  1024. * Called whenever a dragstart or drag event is received on the associated Thumb.
  1025. * Aligns the Tip with the Thumb's new position.
  1026. * @param {Ext.slider.MultiSlider} slider The slider
  1027. * @param {Ext.EventObject} e The Event object
  1028. * @param {Ext.slider.Thumb} thumb The thumb that the Tip is attached to
  1029. */
  1030. onSlide : function(slider, e, thumb) {
  1031. this.show();
  1032. this.body.update(this.getText(thumb));
  1033. this.doAutoWidth();
  1034. this.el.alignTo(thumb.el, 'b-t?', this.offsets);
  1035. },
  1036. /**
  1037. * Used to create the text that appears in the Tip's body. By default this just returns
  1038. * the value of the Slider Thumb that the Tip is attached to. Override to customize.
  1039. * @param {Ext.slider.Thumb} thumb The Thumb that the Tip is attached to
  1040. * @return {String} The text to display in the tip
  1041. */
  1042. getText : function(thumb) {
  1043. return String(thumb.value);
  1044. }
  1045. });
  1046. //backwards compatibility - SliderTip used to be a ux before 3.2
  1047. Ext.ux.SliderTip = Ext.slider.Tip;