duoshuo-ua.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /**
  2. * Duoshuo UA Plugin
  3. * @version v1.0.6
  4. * @license MIT
  5. * @author Gerald <gera2ld@163.com>
  6. */
  7. !function(){
  8. /**
  9. * 多说User-Agent插件核心脚本
  10. * 用于监听DUOSHUO及评论加载过程并执行注入
  11. *
  12. * @author Gerald <gera2ld@163.com>
  13. *
  14. * Optional requirements:
  15. * ./default.js
  16. */
  17. var _this = this;
  18. function emptyString(local) {
  19. return '';
  20. }
  21. var myIds;
  22. function callBefore(local, args) {
  23. if (!myIds) {
  24. myIds = duoshuoQuery.myIds || [];
  25. if (!myIds.slice) myIds = [myIds];
  26. myIds.reverse();
  27. }
  28. var e = args[0];
  29. if (args.length == 1) // embed.unstable.js
  30. e = e.post;
  31. local.agent = e.agent;
  32. local.webmaster = 0;
  33. var id = e.author_id;
  34. for (var i = myIds.length; i--; )
  35. if (myIds[i] == id) {
  36. local.webmaster = id;
  37. break;
  38. }
  39. }
  40. function callAfter(local, args) {
  41. var res = local.result;
  42. var i = res.indexOf('<div class="ds-comment-header">');
  43. var j = res.indexOf('</div>', i);
  44. var func = duoshuoQuery.getUAString || getUAString || emptyString;
  45. local.result = res.slice(0, j) + func.call(_this, local) + res.slice(j);
  46. }
  47. function init() {
  48. var post = DUOSHUO.templates.post;
  49. DUOSHUO.templates.post = function () {
  50. var local = {};
  51. var args = arguments;
  52. callBefore.call(this, local, args);
  53. local.result = post.apply(this, args);
  54. callAfter.call(this, local, args);
  55. return local.result;
  56. }
  57. }
  58. function observeProperty(item, key, callback) {
  59. function callbackOnce() {
  60. var cb = callback;
  61. if (cb) {
  62. callback = null;
  63. cb();
  64. }
  65. }
  66. var value;
  67. if (item[key]) callbackOnce();
  68. else Object.defineProperty(item, key, {
  69. get: function () {return value;},
  70. set: function (val) {
  71. value = val;
  72. callbackOnce();
  73. },
  74. configurable: true,
  75. });
  76. }
  77. function observePropertyChain(item, keys, callback) {
  78. function observe() {
  79. observeProperty(item, key, function () {
  80. item = item[key];
  81. if(key = keys.shift()) observe();
  82. else callback();
  83. });
  84. }
  85. var key = keys.shift();
  86. observe();
  87. }
  88. observePropertyChain(window, ['DUOSHUO', 'templates', 'post'], init);
  89. /**
  90. * User-Agent parser
  91. * @author Gerald <gera2ld@163.com>
  92. */
  93. this.UAParser = function () {
  94. var mapper = {
  95. reg: function (str, maps) {
  96. return str.replace(maps[0], maps[1]);
  97. },
  98. str: function (str, maps) {
  99. return (str in maps) ? maps[str] : maps[''];
  100. },
  101. ieVer: function (str) {
  102. return parseInt(str, 10) + 4;
  103. },
  104. };
  105. var maps = {
  106. winVer: {
  107. '4.90': 'ME',
  108. 'NT3.51': 'NT 3.11',
  109. 'NT4.0': 'NT 4.0',
  110. 'NT 5.0': '2000',
  111. 'NT 5.1': 'XP',
  112. 'NT 5.2': 'XP',
  113. 'NT 6.0': 'Vista',
  114. 'NT 6.1': '7',
  115. 'NT 6.2': '8',
  116. 'NT 6.3': '8.1',
  117. 'NT 6.4': '10',
  118. 'NT 10.0': '10',
  119. 'ARM': 'RT',
  120. '': '山寨版',
  121. },
  122. };
  123. var NAME = 'name';
  124. var VERSION = 'version';
  125. var CLASS = 'cls';
  126. var CLS_WIN = [CLASS, 'windows'];
  127. var rules = {
  128. os: [
  129. // Windows
  130. [/(Windows Phone)(?: OS)? ?([^; )]*)/i,
  131. [NAME, VERSION, CLS_WIN]],
  132. [/(Windows) ([^;)]*)/i,
  133. [NAME, [VERSION, mapper.str, maps.winVer], CLS_WIN]],
  134. [/\b(Windows)\b/i,
  135. [NAME, [VERSION, '超级山寨版'], CLS_WIN]],
  136. // Mac
  137. [/(iPhone|iPod|iPad|Mac OS X)/i,
  138. [NAME, [CLASS, 'mac']]],
  139. // Android
  140. [/(Android) ?([^; )]*)/i,
  141. [NAME, VERSION, [CLASS, 'android']]],
  142. // Linux
  143. [/(Ubuntu|Linux)/i,
  144. [NAME, [CLASS, 'linux']]],
  145. [/()/i,
  146. [[NAME, '山寨操作系统'], [CLASS, 'other']]],
  147. ],
  148. browser: [
  149. // Opera
  150. [/(Opera Mini)\/(\d+)/i,
  151. [NAME, VERSION]],
  152. [[/(OPR)\/(\S+)/i, /(Presto)\/.*?Version\/(\S+)/i],
  153. [[NAME, 'Opera'], VERSION]],
  154. // Chromium based browsers
  155. [/(Maxthon|Vivaldi)\/(\S+)/i,
  156. [NAME, VERSION]],
  157. // Chrome
  158. // Chrome must be checked after other Chromium base browsers are checked
  159. [/(Chrome)\/(\S+)/i,
  160. [NAME, VERSION]],
  161. // UC/QQ
  162. [/(UC|QQ)Browser\/(\S+)/i,
  163. [[NAME, mapper.reg, [/$/, '浏览器']], VERSION]],
  164. // Safari
  165. [/Version\/(\S+) .*?(Safari)\//i,
  166. [VERSION, NAME]],
  167. // Firefox
  168. [/(Firefox)\/(\S+)/i,
  169. [NAME, VERSION]],
  170. // IE
  171. [/MS(IE) (\d+)\.0/i,
  172. [[NAME, 'Internet Explorer'], VERSION]],
  173. [/(Trident)\/(\d+)\.0/i,
  174. [[NAME, 'Internet Explorer'], [VERSION, mapper.ieVer]]],
  175. [/()/i,
  176. [[NAME, '山寨浏览器']]],
  177. ],
  178. };
  179. function getResult(matches, keys) {
  180. var res = {};
  181. keys.forEach(function(key, i) {
  182. var match = matches[i + 1];
  183. if (Array.isArray(key)) {
  184. if (typeof key[1] == 'function')
  185. res[key[0]] = key[1](match, key[2]);
  186. else res[key[0]] = key[1];
  187. } else res[key] = match;
  188. });
  189. return res;
  190. }
  191. function getString(obj) {
  192. var str = obj.name;
  193. if (obj.version)
  194. str += ' ' + obj.version;
  195. return str;
  196. }
  197. function parse(agent) {
  198. var result = {};
  199. for (var key in rules)
  200. rules[key].some(function (rule) {
  201. var regex = rule[0];
  202. var attrs = rule[1];
  203. if (!Array.isArray(regex))
  204. regex = [regex];
  205. return regex.some(function(re) {
  206. var matches = agent.match(re);
  207. if (matches) {
  208. result[key] = getResult(matches, attrs);
  209. return true;
  210. }
  211. });
  212. });
  213. return result;
  214. }
  215. return {
  216. parse: parse,
  217. getString: getString,
  218. };
  219. }();
  220. var getUAString = function (local) {
  221. var UAParser = this.UAParser;
  222. var agent = UAParser.parse(local.agent);
  223. return '<div class="ds-os">' + UAParser.getString(agent.os) + '</div>' +
  224. '<div class="ds-br">' + UAParser.getString(agent.browser) + '</div>' +
  225. (local.webmaster ? '<div class=ds-webmaster>站长</div>' : '');
  226. };
  227. }.call({});