jquery.html5autofallback.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /**
  2. * JS-Fallback for some new HTML5 features
  3. * - placeholder (by Mark)
  4. * - details (by Mathias)
  5. *
  6. * Requires:
  7. * - jquery1.6 (maybe less)
  8. * - jquery.livequery to work with ajax content
  9. *
  10. * @author Mark Scherer
  11. * @licence MIT
  12. * 2011-11-29 ms
  13. */
  14. (function() {
  15. /* placeholder */
  16. var input = document.createElement('input');
  17. if(!('placeholder' in input)) {
  18. $('input[placeholder], textarea[placeholder]').livequery(function() {
  19. var obj = $(this);
  20. var setPlaceholder = function() {
  21. if (!obj.val() || obj.val() == obj.attr('placeholder')) {
  22. obj.val(obj.attr('placeholder')).addClass('pseudoPlaceholder').data('fallbackPlaceholder', true);
  23. }
  24. }
  25. setPlaceholder();
  26. var unsetPlaceholder = function() {
  27. obj.val('').removeClass('pseudoPlaceholder').data('fallbackPlaceholder', false);
  28. }
  29. obj.blur(function() {
  30. if(!obj.val().length) {
  31. setPlaceholder();
  32. }
  33. });
  34. obj.focus(function() {
  35. if(obj.data('fallbackPlaceholder')) {
  36. unsetPlaceholder();
  37. }
  38. });
  39. });
  40. $('form').live('submit', function() {
  41. $(this).find(".pseudoPlaceholder").each(function() {
  42. var obj = $(this);
  43. obj.removeClass('pseudoPlaceholder');
  44. if (!obj.val() || obj.val() == obj.attr('placeholder')) {
  45. obj.val('');
  46. };
  47. });
  48. });
  49. }
  50. if(!('autofocus' in input)) {
  51. $('input[autofocus], textarea[placeholder]').livequery(function() {
  52. $(this).focus();
  53. });
  54. }
  55. /* details - http://mathiasbynens.be/notes/html5-details-jquery */
  56. var isDetailsSupported = (function(doc) {
  57. var el = doc.createElement('details'),
  58. de = doc.documentElement,
  59. fake,
  60. root = doc.body || (function() {
  61. fake = true;
  62. return de.insertBefore(doc.createElement('body'), de.firstChildElement || de.firstChild);
  63. }()),
  64. diff;
  65. el.innerHTML = '<summary>a</summary>b';
  66. el.style.display = 'block';
  67. root.appendChild(el);
  68. diff = el.offsetHeight;
  69. el.open = true;
  70. diff = diff != el.offsetHeight;
  71. root.removeChild(el);
  72. if (fake) {
  73. root.parentNode.removeChild(root);
  74. }
  75. return diff;
  76. }(document));
  77. // Execute the fallback only if there’s no native `details` support
  78. if (!isDetailsSupported) {
  79. document.documentElement.className += ' no-details';
  80. // Loop through all `details` elements
  81. $('details').each(function() {
  82. // Store a reference to the current `details` element in a variable
  83. var $details = $(this),
  84. // Store a reference to the `summary` element of the current `details` element (if any) in a variable
  85. $detailsSummary = $('summary', $details),
  86. // Do the same for the info within the `details` element
  87. $detailsNotSummary = $details.children(':not(summary)'),
  88. // This will be used later to look for direct child text nodes
  89. $detailsNotSummaryContents = $details.contents(':not(summary)'),
  90. // This will be used later on
  91. open;
  92. // If there is no `summary` in the current `details` element…
  93. if (!$detailsSummary.length) {
  94. // …create one with default text
  95. $detailsSummary = $(document.createElement('summary')).text('Details').prependTo($details);
  96. }
  97. // Look for direct child text nodes
  98. if ($detailsNotSummary.length !== $detailsNotSummaryContents.length) {
  99. // Wrap child text nodes in a `span` element
  100. $detailsNotSummaryContents.filter(function() {
  101. // Only keep the node in the collection if it’s a text node containing more than only whitespace
  102. return (this.nodeType === 3) && (/[^\t\n\r ]/.test(this.data));
  103. }).wrap('<span>');
  104. // There are now no direct child text nodes anymore — they’re wrapped in `span` elements
  105. $detailsNotSummary = $details.children(':not(summary)');
  106. }
  107. // Hide content unless there’s an `open` attribute
  108. // Chrome 10 already recognizes the `open` attribute as a boolean (even though it doesn’t support rendering `<details>` yet
  109. // Other browsers without `<details>` support treat it as a string
  110. /* fix - 2011-05-13 ms */
  111. open = $details.get()[0].getAttribute('open');
  112. if (typeof open == 'string' || (typeof open == 'boolean' && open)) {
  113. $details.addClass('open');
  114. $detailsNotSummary.show();
  115. } else {
  116. $detailsNotSummary.hide();
  117. }
  118. // Set the `tabindex` attribute of the `summary` element to 0 to make it keyboard accessible
  119. $detailsSummary.attr('tabindex', 0).click(function() {
  120. // Focus on the `summary` element
  121. $detailsSummary.focus();
  122. // Toggle the `open` attribute of the `details` element
  123. typeof $details.attr('open') !== 'undefined' ? $details.removeAttr('open') : $details.attr('open', 'open');
  124. // Toggle the additional information in the `details` element
  125. $detailsNotSummary.toggle(0);
  126. $details.toggleClass('open');
  127. }).keyup(function(event) {
  128. if (13 === event.keyCode || 32 === event.keyCode) {
  129. // Enter or Space is pressed — trigger the `click` event on the `summary` element
  130. // Opera already seems to trigger the `click` event when Enter is pressed
  131. if (!($.browser.opera && 13 === event.keyCode)) {
  132. event.preventDefault();
  133. $detailsSummary.click();
  134. }
  135. }
  136. });
  137. });
  138. }
  139. if(!('list' in input)) {
  140. $('input[list]').livequery(function() {
  141. $(this).datalist();
  142. });
  143. }
  144. })();