fcp-html-doctype.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /**
  2. * 注册命名空间
  3. */
  4. baidu.namespace.register("baidu.doctype");
  5. /**
  6. * 计算documentMode
  7. * @author zhaoxianlie
  8. */
  9. baidu.doctype = (function(){
  10. var documentMode = {
  11. //在未定义DTD的时候,浏览器默认将以混杂模式进行渲染
  12. IE: 'Q',
  13. WebKit: 'Q',
  14. // 在DTD前是否存在注释(在我们的所有模板前面,都有一段注释:STATUS OK)
  15. hasCommentBeforeDTD: false,
  16. // 在DTD钱是否存在IE条件注释
  17. hasConditionalCommentBeforeDTD: false,
  18. // 是否为一个奇怪的DTD
  19. isUnusualDocType: false,
  20. // 是否有DTD
  21. hasDocType: false
  22. };
  23. /**
  24. * <!DOCTYPE "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'">
  25. * 这个DTD将使页面在IE下以标准模式渲染,在Webkit下以混杂模式渲染
  26. * 比如这个站点: http://www.nasa.gov/
  27. * @param {string} name 值为:document.doctype.name.toLowerCase()
  28. * @param {string} publicId 值为:document.doctype.publicId
  29. * @param {string} systemId 值为:document.doctype.systemId
  30. */
  31. function fixDocTypeOfNASA(name, publicId, systemId){
  32. if (name.toLowerCase() == "\"xmlns:xsl='http://www.w3.org/1999/xsl/transform'\"" &&
  33. publicId == '' &&
  34. systemId == '') {
  35. documentMode.IE = 'S';
  36. documentMode.WebKit = 'Q';
  37. documentMode.isUnusualDocType = false;
  38. }
  39. }
  40. /**
  41. * 判断一个Comment是否为IE的条件注释
  42. * @param {string} Comment内容
  43. */
  44. function isConditionalComment(nodeValue){
  45. return baidu.FlConst.CONDITIONAL_COMMENT_REGEXP.test(nodeValue);
  46. }
  47. /**
  48. * 判断一个Comment内容是否为非IE的注释
  49. * @param {string} Comment内容
  50. */
  51. function isNotIEHiddenConditionalComment(nodeValue){
  52. return baidu.FlConst.NOT_IE_HIDDEN_CONDITIONAL_COMMENT_REGEXP.test(nodeValue);
  53. }
  54. /**
  55. * 判断一个Comment是否为注释的结束部分
  56. * @param {string} Comment内容
  57. */
  58. function isRevealedClosingConditionalComment(nodeValue){
  59. return baidu.FlConst.REVEALED_CLOSING_CONDITIONAL_COMMENT_REGEXP.test(nodeValue);
  60. }
  61. /**
  62. * 判断一个Comment是否为非IE注释的开始
  63. * @param {string} Comment内容
  64. */
  65. function isNotIERevealedOpeningConditionalComment(nodeValue){
  66. return baidu.FlConst.NOT_IE_REVEALED_OPENING_CONDITIONAL_COMMENT_REGEXP.test(nodeValue);
  67. }
  68. /**
  69. * 试图在某个Comment前面找到一个非IE注释的开始
  70. */
  71. function getPreviousRevealedOpeningConditionalComment(node){
  72. var prev = node.previousSibling;
  73. for (; prev; prev = prev.previousSibling) {
  74. if (isNotIERevealedOpeningConditionalComment(prev.nodeValue)) {
  75. return prev;
  76. }
  77. }
  78. return null;
  79. }
  80. /**
  81. * 检测文档头DTD前面是否有注释
  82. */
  83. function checkForCommentBeforeDTD(){
  84. var result = {
  85. hasCommentBeforeDTD: false,
  86. hasConditionalCommentBeforeDTD: false
  87. };
  88. var doctype = document.doctype;
  89. if (!doctype) {
  90. return result;
  91. }
  92. //从<html>向上搜索,进行检测
  93. var prev = doctype.previousSibling;
  94. for (; prev; prev = prev.previousSibling) {
  95. if (prev.nodeType == Node.COMMENT_NODE) {
  96. var nodeValue = prev.nodeValue;
  97. //向上搜索的过程中,如果碰到某个Comment是注释的结束部分,再继续搜索其上是否存在注释的开始部分
  98. if (isRevealedClosingConditionalComment(nodeValue)) {
  99. prev = getPreviousRevealedOpeningConditionalComment(prev);
  100. // 向上发现了注释的开始部分,则说明DTD前存在条件注释
  101. if (prev) {
  102. result.hasConditionalCommentBeforeDTD = true;
  103. return result;
  104. }
  105. continue;
  106. }
  107. // 判断某个Comment是否为一个条件注释
  108. var isConditionalComm = isConditionalComment(nodeValue);
  109. if (!isConditionalComm) {
  110. result.hasCommentBeforeDTD = true;
  111. continue;
  112. }
  113. // 存在非IE的条件注释:如<!--[if !IE]> some text <![endif]-->
  114. if (isNotIEHiddenConditionalComment(nodeValue)) {
  115. result.hasConditionalCommentBeforeDTD = true;
  116. }
  117. }
  118. }
  119. return result;
  120. }
  121. /**
  122. * 开始进行文档类型的侦测
  123. */
  124. function processDoctypeDetectionResult(){
  125. //获取doctype
  126. var doctype = document.doctype;
  127. var compatMode = document.compatMode.toLowerCase();
  128. documentMode.hasDocType = (doctype) ? true : false;
  129. // 如果页面是以混杂模式渲染的,则compatMode为BackCompat
  130. documentMode.WebKit = (compatMode == 'backcompat') ? 'Q' : 'S';
  131. documentMode.IE = documentMode.WebKit;
  132. // 如果文档压根儿就没有写doctype,则不需要继续侦测了
  133. if (!doctype) {
  134. return;
  135. }
  136. //下面三个是doctype中最重要的组成部分
  137. var name = doctype ? doctype.name.toLowerCase() : '';
  138. var publicId = doctype ? doctype.publicId : '';
  139. var systemId = doctype ? doctype.systemId : '';
  140. // 非正常工作模式
  141. if (name != 'html') {
  142. documentMode.IE = undefined;
  143. documentMode.isUnusualDocType = true;
  144. } else {
  145. //在白名单中进一步检测publicId和systemId
  146. if (publicId in baidu.FlConst.PUBLIC_ID_WHITE_LIST) {
  147. if (!(systemId in baidu.FlConst.PUBLIC_ID_WHITE_LIST[publicId].systemIds)) {
  148. documentMode.IE = undefined;
  149. documentMode.isUnusualDocType = true;
  150. }
  151. } else {
  152. documentMode.IE = undefined;
  153. documentMode.isUnusualDocType = true;
  154. }
  155. }
  156. // 对documentMode进行修正判断
  157. if ((publicId in baidu.FlConst.COMPAT_MODE_DIFF_PUBLIC_ID_MAP) &&
  158. (systemId in baidu.FlConst.COMPAT_MODE_DIFF_PUBLIC_ID_MAP[publicId].systemIds)) {
  159. documentMode.IE = baidu.FlConst.COMPAT_MODE_DIFF_PUBLIC_ID_MAP[publicId].systemIds[systemId].IE;
  160. documentMode.isUnusualDocType = false;
  161. }
  162. // 进一步修正
  163. fixDocTypeOfNASA(name, publicId, systemId);
  164. // 判断文档头前面是否存在注释
  165. if (documentMode.IE != 'Q') {
  166. var result = checkForCommentBeforeDTD();
  167. if (result.hasConditionalCommentBeforeDTD) {
  168. documentMode.IE = undefined;
  169. documentMode.hasConditionalCommentBeforeDTD = true;
  170. }
  171. else
  172. if (result.hasCommentBeforeDTD) {
  173. // IE6 DTD 前的任何非空白符都将使浏览器忽略 DTD,包括注释和 XML 声明。
  174. //IE7 IE8 DTD 前的任何非空白符都将使浏览器忽略 DTD,包括注释,但不包括 XML 声明。
  175. //Firefox DTD 前的任何包含“<”的字符都将使浏览器忽略 DTD,但不包括 XML 声明。
  176. //Chrome Safari Opera DTD 前的任何非空白符都将使浏览器忽略 DTD,但不包括 XML 声明。
  177. documentMode.IE = 'Q';
  178. documentMode.hasCommentBeforeDTD = true;
  179. }
  180. }
  181. }
  182. /**
  183. * 对外公开调用接口
  184. */
  185. return {
  186. getDocMode : function(){
  187. //检测documentMode
  188. processDoctypeDetectionResult();
  189. return documentMode;
  190. }
  191. }
  192. })();