ellipsis.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. define("dojox/html/ellipsis",["dojo/_base/kernel", "dojo/_base/lang", "dojo/_base/array", "dojo/_base/Color", "dojo/colors"], function(d){
  2. /*=====
  3. dojox.html.ellipsis = {
  4. // summary: offers cross-browser support for text-overflow: ellipsis
  5. //
  6. // description: Add "dojoxEllipsis" on any node that you want to ellipsis-ize. In order to function properly,
  7. // the node with the dojoxEllipsis class set on it should be a child of a node with a defined width.
  8. // It should also be a block-level element (i.e. <div>) - it will not work on td elements.
  9. // NOTE: When using the dojoxEllipsis class within tables, the table needs to have the table-layout: fixed style
  10. }
  11. =====*/
  12. if(d.isFF < 7){ //TODO: feature detect text-overflow in computed style?
  13. // The delay (in ms) to wait so that we don't keep querying when many
  14. // changes happen at once - set config "dojoxFFEllipsisDelay" if you
  15. // want a different value
  16. var delay = 1;
  17. if("dojoxFFEllipsisDelay" in d.config){
  18. delay = Number(d.config.dojoxFFEllipsisDelay);
  19. if(isNaN(delay)){
  20. delay = 1;
  21. }
  22. }
  23. try{
  24. var createXULEllipsis = (function(){
  25. // Create our stub XUL elements for cloning later
  26. // NOTE: this no longer works as of FF 4.0:
  27. // https://developer.mozilla.org/En/Firefox_4_for_developers#Remote_XUL_support_removed
  28. var sNS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
  29. var xml = document.createElementNS(sNS, 'window');
  30. var label = document.createElementNS(sNS, 'description');
  31. label.setAttribute('crop', 'end');
  32. xml.appendChild(label);
  33. return function(/* Node */ n){
  34. // Summary:
  35. // Given a node, it creates the XUL and sets its
  36. // content so that it will have an ellipsis
  37. var x = xml.cloneNode(true);
  38. x.firstChild.setAttribute('value', n.textContent);
  39. n.innerHTML = '';
  40. n.appendChild(x);
  41. };
  42. })();
  43. }catch(e){}
  44. // Create our iframe elements for cloning later
  45. var create = d.create;
  46. var dd = d.doc;
  47. var dp = d.place;
  48. var iFrame = create("iframe", {className: "dojoxEllipsisIFrame",
  49. src: "javascript:'<html><head><script>if(\"loadFirebugConsole\" in window){window.loadFirebugConsole();}</script></head><body></body></html>'", style: {display: "none"}});
  50. var rollRange = function(/* W3C Range */ r, /* int? */ cnt){
  51. // Summary:
  52. // Rolls the given range back one character from the end
  53. //
  54. // r: W3C Range
  55. // The range to roll back
  56. // cnt: int?
  57. // An optional number of times to roll back (defaults 1)
  58. if(r.collapsed){
  59. // Do nothing - we are already collapsed
  60. return;
  61. }
  62. if(cnt > 0){
  63. do{
  64. rollRange(r);
  65. cnt--;
  66. }while(cnt);
  67. return;
  68. }
  69. if(r.endContainer.nodeType == 3 && r.endOffset > 0){
  70. r.setEnd(r.endContainer, r.endOffset - 1);
  71. }else if(r.endContainer.nodeType == 3){
  72. r.setEndBefore(r.endContainer);
  73. rollRange(r);
  74. return;
  75. }else if(r.endOffset && r.endContainer.childNodes.length >= r.endOffset){
  76. var nCont = r.endContainer.childNodes[r.endOffset - 1];
  77. if(nCont.nodeType == 3){
  78. r.setEnd(nCont, nCont.length - 1);
  79. }else if(nCont.childNodes.length){
  80. r.setEnd(nCont, nCont.childNodes.length);
  81. rollRange(r);
  82. return;
  83. }else{
  84. r.setEndBefore(nCont);
  85. rollRange(r);
  86. return;
  87. }
  88. }else{
  89. r.setEndBefore(r.endContainer);
  90. rollRange(r);
  91. return;
  92. }
  93. };
  94. var createIFrameEllipsis = function(/* Node */ n){
  95. // Summary:
  96. // Given a node, it creates an iframe and and ellipsis div and
  97. // sets up the connections so that they will work correctly.
  98. // This function is used when createXULEllipsis is not able
  99. // to be used (because there is markup within the node) - it's
  100. // a bit slower, but does the trick
  101. var c = create("div", {className: "dojoxEllipsisContainer"});
  102. var e = create("div", {className: "dojoxEllipsisShown", style: {display: "none"}});
  103. n.parentNode.replaceChild(c, n);
  104. c.appendChild(n);
  105. c.appendChild(e);
  106. var i = iFrame.cloneNode(true);
  107. var ns = n.style;
  108. var es = e.style;
  109. var ranges;
  110. var resizeNode = function(){
  111. ns.display = "";
  112. es.display = "none";
  113. if(n.scrollWidth <= n.offsetWidth){ return; }
  114. var r = dd.createRange();
  115. r.selectNodeContents(n);
  116. ns.display = "none";
  117. es.display = "";
  118. var done = false;
  119. do{
  120. var numRolls = 1;
  121. dp(r.cloneContents(), e, "only");
  122. var sw = e.scrollWidth, ow = e.offsetWidth;
  123. done = (sw <= ow);
  124. var pct = (1 - ((ow * 1) / sw));
  125. if(pct > 0){
  126. numRolls = Math.max(Math.round(e.textContent.length * pct) - 1, 1);
  127. }
  128. rollRange(r, numRolls);
  129. }while(!r.collapsed && !done);
  130. };
  131. i.onload = function(){
  132. i.contentWindow.onresize = resizeNode;
  133. resizeNode();
  134. };
  135. c.appendChild(i);
  136. };
  137. // Function for updating the ellipsis
  138. var hc = d.hasClass;
  139. var doc = d.doc;
  140. var s, fn, opt;
  141. if(doc.querySelectorAll){
  142. s = doc;
  143. fn = "querySelectorAll";
  144. opt = ".dojoxEllipsis";
  145. }else if(doc.getElementsByClassName){
  146. s = doc;
  147. fn = "getElementsByClassName";
  148. opt = "dojoxEllipsis";
  149. }else{
  150. s = d;
  151. fn = "query";
  152. opt = ".dojoxEllipsis";
  153. }
  154. fx = function(){
  155. d.forEach(s[fn].apply(s, [opt]), function(n){
  156. if(!n || n._djx_ellipsis_done){ return; }
  157. n._djx_ellipsis_done = true;
  158. if(createXULEllipsis && n.textContent == n.innerHTML && !hc(n, "dojoxEllipsisSelectable")){
  159. // We can do the faster XUL version, instead of calculating
  160. createXULEllipsis(n);
  161. }else{
  162. createIFrameEllipsis(n);
  163. }
  164. });
  165. };
  166. d.addOnLoad(function(){
  167. // Apply our initial stuff
  168. var t = null;
  169. var c = null;
  170. var connFx = function(){
  171. if(c){
  172. // disconnect us - so we don't fire anymore
  173. d.disconnect(c);
  174. c = null;
  175. }
  176. if(t){ clearTimeout(t); }
  177. t = setTimeout(function(){
  178. t = null;
  179. fx();
  180. // Connect to the modified function so that we can catch
  181. // our next change
  182. c = d.connect(d.body(), "DOMSubtreeModified", connFx);
  183. }, delay);
  184. };
  185. connFx();
  186. });
  187. }
  188. });