Discourse Pro

增强 Discourse 论坛。

目前为 2024-12-26 提交的版本,查看 最新版本

  1. /******/ (() => { // webpackBootstrap
  2. /******/ "use strict";
  3. /******/ var __webpack_modules__ = ({
  4.  
  5. /***/ 545:
  6. /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
  7.  
  8.  
  9. // EXPORTS
  10. __webpack_require__.d(__webpack_exports__, {
  11. A: () => (/* binding */ Options)
  12. });
  13.  
  14. // EXTERNAL MODULE: ./utils/src/gm/Store.ts
  15. var Store = __webpack_require__(915);
  16. ;// CONCATENATED MODULE: ./utils/src/gm/MenuCmd.ts
  17. function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
  18. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  19. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
  20. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
  21. function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
  22. function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
  23. /**
  24. * 选项菜单
  25. */
  26. var MenuCmd = /*#__PURE__*/function () {
  27. function MenuCmd() {
  28. _classCallCheck(this, MenuCmd);
  29. }
  30. return _createClass(MenuCmd, null, [{
  31. key: "register",
  32. value:
  33. /**
  34. * 注册
  35. * @param name 名称
  36. * @param fn 点击菜单时执行的函数
  37. */
  38. function register(name, fn) {
  39. return GM_registerMenuCommand(name, fn);
  40. }
  41.  
  42. /**
  43. * 注销
  44. * @param menuCmdId 注册时返回的 ID
  45. */
  46. }, {
  47. key: "unregister",
  48. value: function unregister(menuCmdId) {
  49. GM_unregisterMenuCommand(menuCmdId);
  50. }
  51. }]);
  52. }();
  53.  
  54. ;// CONCATENATED MODULE: ./utils/src/CommonOptions.ts
  55. function CommonOptions_typeof(o) { "@babel/helpers - typeof"; return CommonOptions_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, CommonOptions_typeof(o); }
  56. function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
  57. function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
  58. function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
  59. function CommonOptions_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  60. function CommonOptions_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, CommonOptions_toPropertyKey(descriptor.key), descriptor); } }
  61. function CommonOptions_createClass(Constructor, protoProps, staticProps) { if (protoProps) CommonOptions_defineProperties(Constructor.prototype, protoProps); if (staticProps) CommonOptions_defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
  62. function CommonOptions_toPropertyKey(t) { var i = CommonOptions_toPrimitive(t, "string"); return "symbol" == CommonOptions_typeof(i) ? i : i + ""; }
  63. function CommonOptions_toPrimitive(t, r) { if ("object" != CommonOptions_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != CommonOptions_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
  64.  
  65.  
  66.  
  67. /**
  68. * 选项菜单
  69. */
  70. var CommonOptions = /*#__PURE__*/function () {
  71. function CommonOptions() {
  72. CommonOptions_classCallCheck(this, CommonOptions);
  73. }
  74. return CommonOptions_createClass(CommonOptions, null, [{
  75. key: "registerBoolOption",
  76. value:
  77. /**
  78. * 注册 bool 类型的选项
  79. *
  80. * @param option 选项
  81. */
  82. function registerBoolOption(option) {
  83. var _this = this;
  84. var val = option.value,
  85. valIsBool = typeof val === 'boolean';
  86. if (!valIsBool) {
  87. return;
  88. }
  89. // 注册选项和选项点击事件
  90. var currentMenuCmdId = MenuCmd.register((val ? '✅ ' : '🔲 ') + option.label, function () {
  91. // 点击后取反
  92. option.value = !option.value;
  93. Store/* default */.A.set(option.name, JSON.stringify(option));
  94.  
  95. // 重新注册
  96. MenuCmd.unregister(currentMenuCmdId);
  97. _this.registerBoolOption(option);
  98. // 刷新页面
  99. window.location.reload();
  100. });
  101.  
  102. // 保存选项 ID
  103. option.menuCmdId = currentMenuCmdId;
  104. Store/* default */.A.set(option.name, JSON.stringify(option));
  105. }
  106.  
  107. /**
  108. * 注册所有选项
  109. *
  110. * @param options 选项
  111. * @param moreOptionsUrl 更多设置页面 URL
  112. */
  113. }, {
  114. key: "registerAll",
  115. value: function registerAll(options, moreOptionsUrl) {
  116. // 注册“更多设置”选项,点击后打开新页面
  117. MenuCmd.register('更多设置', function () {
  118. window.open(moreOptionsUrl, '_blank');
  119. });
  120. var _iterator = _createForOfIteratorHelper(options),
  121. _step;
  122. try {
  123. for (_iterator.s(); !(_step = _iterator.n()).done;) {
  124. var option = _step.value;
  125. // TODO 【调试】不保留选项的值,每次都从 Store 中获取
  126. // Store.set(option.name, null);
  127.  
  128. var storeOption = Store/* default */.A.get(option.name) ? JSON.parse(Store/* default */.A.get(option.name)) : null;
  129. // 如果选项不存在 || 版本不一致 时重置选项
  130. if (storeOption === null || !storeOption['version'] || storeOption['version'] < option.version) {
  131. Store/* default */.A.set(option.name, JSON.stringify(option));
  132. storeOption = option;
  133. }
  134. this.registerBoolOption(storeOption);
  135. }
  136. } catch (err) {
  137. _iterator.e(err);
  138. } finally {
  139. _iterator.f();
  140. }
  141. }
  142.  
  143. /**
  144. * 在 Greasy Fork 脚本详情页中加载选项
  145. *
  146. * @param scriptId 脚本 ID
  147. * @param loadOptionContentFn 加载选项内容的函数
  148. */
  149. }, {
  150. key: "loadInGreasyfork",
  151. value: function loadInGreasyfork(scriptId, loadOptionContentFn) {
  152. // 非脚本详情页结束
  153. if (location.host !== 'greasyfork.org' || location.href.indexOf('/scripts/' + scriptId) == -1) {
  154. return;
  155. }
  156. var selector = {
  157. scriptLinks: '#script-links',
  158. scriptOptions: '#script-options',
  159. scriptContent: '#script-content'
  160. };
  161. var $body = $(document.body),
  162. $scriptLinks = $(selector.scriptLinks),
  163. $scriptContent = $(selector.scriptContent);
  164.  
  165. // 添加“脚本设置”选项卡和点击事件
  166. $scriptLinks.children('li:eq(0)').after("<li><a href=\"javascript:;\" id=\"script-options\">\u811A\u672C\u8BBE\u7F6E</a></li>");
  167. $body.on('click', selector.scriptOptions, function () {
  168. // 移除其他已选中选项的样式
  169. var $currentLi = $scriptLinks.children('li.current');
  170. $currentLi.html("<a href=\"".concat(location.href, "\">").concat($currentLi.text(), "</a>"));
  171. $currentLi.removeClass('current');
  172. // 给“脚本设置”选项卡添加选中选项的样式
  173. var $scriptOptions = $(selector.scriptOptions);
  174. $scriptOptions.parent().addClass('current');
  175. loadOptionContentFn($scriptContent);
  176. });
  177. }
  178. }]);
  179. }();
  180.  
  181. ;// CONCATENATED MODULE: ./discourse-pro/src/Options.ts
  182. var _Options;
  183. function Options_typeof(o) { "@babel/helpers - typeof"; return Options_typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, Options_typeof(o); }
  184. function Options_createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = Options_unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
  185. function Options_unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return Options_arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return Options_arrayLikeToArray(o, minLen); }
  186. function Options_arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
  187. function Options_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  188. function Options_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, Options_toPropertyKey(descriptor.key), descriptor); } }
  189. function Options_createClass(Constructor, protoProps, staticProps) { if (protoProps) Options_defineProperties(Constructor.prototype, protoProps); if (staticProps) Options_defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
  190. function _defineProperty(obj, key, value) { key = Options_toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  191. function Options_toPropertyKey(t) { var i = Options_toPrimitive(t, "string"); return "symbol" == Options_typeof(i) ? i : i + ""; }
  192. function Options_toPrimitive(t, r) { if ("object" != Options_typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != Options_typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
  193.  
  194.  
  195.  
  196. var Options = /*#__PURE__*/function () {
  197. function Options() {
  198. Options_classCallCheck(this, Options);
  199. }
  200. return Options_createClass(Options, null, [{
  201. key: "registerBoolOption",
  202. value:
  203. /**
  204. * 注册 bool 类型的选项
  205. * @param option 选项
  206. */
  207. function registerBoolOption(option) {
  208. CommonOptions.registerBoolOption(option);
  209. }
  210.  
  211. /**
  212. * 注册所有选项
  213. */
  214. }, {
  215. key: "registerAll",
  216. value: function registerAll() {
  217. CommonOptions.registerAll(this.options, 'https://greasyfork.org/scripts/' + this.SCRIPT_ID);
  218. }
  219. }, {
  220. key: "onChangByBoolOption",
  221. value: function onChangByBoolOption(key) {
  222. var _this = this;
  223. var optionSelector = '#script-options-' + key;
  224. $(document.body).on('change', optionSelector, function () {
  225. var option = JSON.parse(Store/* default */.A.get(key));
  226. option.value = !option.value;
  227. // 重新注册选项
  228. MenuCmd.unregister(option.menuCmdId);
  229. _this.registerBoolOption(option);
  230. });
  231. }
  232.  
  233. /**
  234. * 在页面中加载选项
  235. */
  236. }, {
  237. key: "loadInGreasyfork",
  238. value: function loadInGreasyfork() {
  239. var _this2 = this;
  240. CommonOptions.loadInGreasyfork(this.SCRIPT_ID, function ($scriptContent) {
  241. // 添加脚本设置的内容
  242. var scriptContent = '';
  243. var _iterator = Options_createForOfIteratorHelper(_this2.options),
  244. _step;
  245. try {
  246. for (_iterator.s(); !(_step = _iterator.n()).done;) {
  247. var option = _step.value;
  248. var storeOption = JSON.parse(Store/* default */.A.get(option.name)),
  249. optionName = storeOption.name,
  250. optionVal = storeOption.value;
  251. scriptContent += "<h3>".concat(option.label, "</h3>");
  252. switch (optionName) {
  253. case _this2.Keys.dragBar:
  254. scriptContent += "<label><input type=\"checkbox\" id=\"script-options-".concat(optionName, "\" ").concat(optionVal ? 'checked' : '', "> \u4FA7\u8FB9\u680F\u62D6\u62FD\u6761\uFF08\u4FA7\u8FB9\u680F\u548C\u4E3B\u5185\u5BB9\u95F4\u6DFB\u52A0\u62D6\u62FD\u6761\uFF0C\u7528\u4E8E\u8C03\u6574\u4E24\u8005\u5BBD\u5EA6\uFF09</label>");
  255. break;
  256. case _this2.Keys.widescreenMode:
  257. scriptContent += "<label><input type=\"checkbox\" id=\"script-options-".concat(optionName, "\" ").concat(optionVal ? 'checked' : '', "> \u5BBD\u5C4F\u6A21\u5F0F</label>");
  258. break;
  259. }
  260. }
  261. } catch (err) {
  262. _iterator.e(err);
  263. } finally {
  264. _iterator.f();
  265. }
  266. $scriptContent.html(scriptContent);
  267.  
  268. // 侧边栏拖拽条
  269. _this2.onChangByBoolOption(_this2.Keys.dragBar);
  270. // 宽屏模式
  271. _this2.onChangByBoolOption(_this2.Keys.widescreenMode);
  272. });
  273. }
  274. }]);
  275. }();
  276. _Options = Options;
  277. _defineProperty(Options, "SCRIPT_ID", 520817);
  278. /**
  279. * 选项 Key
  280. */
  281. _defineProperty(Options, "Keys", {
  282. dragBar: 'dragBar',
  283. widescreenMode: 'widescreenMode'
  284. });
  285. /**
  286. * 选项
  287. * @private
  288. */
  289. _defineProperty(Options, "options", [{
  290. label: '侧边栏拖拽条',
  291. name: _Options.Keys.dragBar,
  292. version: 1,
  293. value: false,
  294. menuCmdId: null
  295. }, {
  296. label: '宽屏模式',
  297. name: _Options.Keys.widescreenMode,
  298. version: 1,
  299. value: false,
  300. menuCmdId: null,
  301. token: ''
  302. }]);
  303.  
  304.  
  305. /***/ }),
  306.  
  307. /***/ 150:
  308. /***/ ((__unused_webpack_module, __unused_webpack___webpack_exports__, __webpack_require__) => {
  309.  
  310.  
  311. // EXTERNAL MODULE: ./utils/src/gm/Store.ts
  312. var Store = __webpack_require__(915);
  313. ;// CONCATENATED MODULE: ./discourse-pro/src/module/widescreenMode.ts
  314. /**
  315. * 添加 history 的 pushState 和 replaceState 事件
  316. *
  317. * 参考:https://segmentfault.com/a/1190000017560688#item-4
  318. */
  319. function addPushReplaceStateEvent() {
  320. var _wr = function _wr(type) {
  321. var orig = history[type];
  322. return function () {
  323. var rv = orig.apply(this, arguments);
  324. var e = new Event(type);
  325. // @ts-ignore
  326. e.arguments = arguments;
  327. window.dispatchEvent(e);
  328. return rv;
  329. };
  330. };
  331. history.pushState = _wr('pushState');
  332. history.replaceState = _wr('replaceState');
  333. }
  334.  
  335. /**
  336. * 加载宽屏模式
  337. * @param options
  338. */
  339. function loadWidescreenMode(options) {
  340. addPushReplaceStateEvent();
  341. var headerWrap = options.headerWrap,
  342. mainOutletWrapper = options.mainOutletWrapper,
  343. mainOutlet = options.mainOutlet,
  344. postStream = options.postStream;
  345. var $headerWrap = $(headerWrap),
  346. $mainOutletWrapper = $(mainOutletWrapper),
  347. $mainOutlet = $(mainOutlet),
  348. $postStream = $(postStream);
  349.  
  350. // 顶部撑满
  351. $headerWrap.css('max-width', '100%');
  352. // 侧边栏和主内容撑满
  353. $mainOutletWrapper.css('max-width', '100%');
  354. // 主内容撑满
  355. $mainOutlet.css('width', '100%');
  356.  
  357. // console.debug('话题页首次加载宽屏模式 + 监听话题列表变化')
  358. // 话题页首次加载宽屏模式 + 监听话题列表变化
  359. loadWidescreenModeByTopicAndObserver(options, $postStream);
  360.  
  361. // 历史记录变化时话题页重新加载宽屏模式
  362. window.addEventListener('popstate', function () {
  363. // console.debug('历史记录变化时话题页重新加载宽屏模式')
  364. popstateAndPushStateListener(postStream, options, $mainOutlet);
  365. });
  366. // 单页面 pushState 切换页面时话题页重新加载宽屏模式
  367. window.addEventListener('pushState', function () {
  368. // console.debug('单页面 pushState 切换页面时话题页重新加载宽屏模式')
  369. popstateAndPushStateListener(postStream, options, $mainOutlet);
  370. });
  371. window.addEventListener('replaceState', function () {
  372. // console.debug('单页面 replaceState 切换页面时话题页重新加载宽屏模式')
  373. popstateAndPushStateListener(postStream, options, $mainOutlet);
  374. });
  375. }
  376.  
  377. /**
  378. * popstate 和 pushState 事件监听
  379. * @param postStreamSelector 话题内容选择器
  380. * @param options 选项
  381. * @param $mainOutlet 主内容
  382. */
  383. function popstateAndPushStateListener(postStreamSelector, options, $mainOutlet) {
  384. if (location.href.indexOf('/topic/') !== -1) {
  385. // 等待 .post-stream 加载完成
  386. var interval = setInterval(function () {
  387. var $newPostStreamWrapper = $(postStreamSelector);
  388. if ($newPostStreamWrapper.length > 0) {
  389. clearInterval(interval);
  390. loadWidescreenModeByTopicAndObserver(options, $(postStreamSelector));
  391. }
  392. }, 500);
  393. }
  394. }
  395.  
  396. /**
  397. * 话题页加载宽屏模式 + 监听话题内容变化
  398. * @param options 选项
  399. * @param $postStream 话题内容
  400. */
  401. function loadWidescreenModeByTopicAndObserver(options, $postStream) {
  402. // 监听话题列表变化
  403. if (location.href.indexOf('/topic/') == -1) {
  404. return;
  405. }
  406. loadWidescreenModeByTopic(options);
  407. if ($postStream.data('hasObserver')) {
  408. // console.debug('[discourse-pro-widescreenMode] 已存在话题内容变化监听器,跳过');
  409. return;
  410. }
  411.  
  412. // 防抖函数
  413. var debounceTimeout;
  414. var debounce = function debounce(func, delay) {
  415. clearTimeout(debounceTimeout);
  416. debounceTimeout = setTimeout(func, delay);
  417. };
  418. var observer = new MutationObserver(function (mutationsList) {
  419. debounce(function () {
  420. loadWidescreenModeByTopic(options);
  421. }, 1000);
  422. });
  423.  
  424. // 是否已监听
  425. $postStream.data('hasObserver', true);
  426. // 此处监听 .posts-wrapper 下的所有节点而不是 .post-stream 下的子节点,因为 .post-stream 会在时间轴跳动后重新加载
  427. observer.observe($postStream[0], {
  428. // 监听子节点
  429. childList: true,
  430. // 不监听子节点下的节点
  431. subtree: false
  432. });
  433. }
  434.  
  435. /**
  436. * 话题页加载宽屏模式
  437. * @param options
  438. */
  439. function loadWidescreenModeByTopic(options) {
  440. var postStream = options.postStream,
  441. topicAvatar = options.topicAvatar,
  442. topicBody = options.topicBody,
  443. topicMap = options.topicMap,
  444. loadingContainer = options.loadingContainer,
  445. topicTimerInfo = options.topicTimerInfo,
  446. topicFooterBtns = options.topicFooterBtns,
  447. moreTopicsContainer = options.moreTopicsContainer;
  448. var $postStream = $(postStream),
  449. $topicAvatar = $(topicAvatar),
  450. $topicBody = $(topicBody),
  451. $topicMap = $(topicMap),
  452. $loadingContainer = $(loadingContainer),
  453. $topicTimerInfo = $(topicTimerInfo),
  454. $topicFooterBtns = $(topicFooterBtns),
  455. $moreTopicsContainer = $(moreTopicsContainer);
  456. var postStreamWidth = $postStream.width();
  457. var topicAvatarWidth = $topicAvatar.width();
  458. var topicWidth = postStreamWidth - 45;
  459. var topicBodyWidth = topicWidth - topicAvatarWidth + 'px';
  460.  
  461. // 如果第一个的宽度和最后一个的宽度不一样,说明话题列表变化了
  462. var firstTopicBodyWidth = $($topicBody[0]).css('width');
  463. var lastTopicBodyWidth = $($topicBody[$topicBody.length - 1]).css('width');
  464. if (firstTopicBodyWidth == lastTopicBodyWidth && firstTopicBodyWidth == topicBodyWidth) {
  465. // console.debug('[discourse-pro-widescreenMode] 话题页加载宽屏模式已加载过,跳过');
  466. return;
  467. }
  468.  
  469. // 话题内容撑满
  470. $topicBody.css('width', topicBodyWidth);
  471. // 话题主内容后浏览量、链接、回复人等信息撑满
  472. $topicMap.css('max-width', topicWidth + 'px');
  473. // 最后一个回复后的底边框撑满
  474. $loadingContainer.css('width', topicWidth + 'px');
  475. $topicTimerInfo.css('max-width', topicWidth + 'px');
  476. // 话题底部按钮撑满
  477. $topicFooterBtns.css('max-width', topicWidth + 'px');
  478. // 更多话题列表撑满
  479. $moreTopicsContainer.css('max-width', topicWidth + 'px');
  480. }
  481.  
  482. ;// CONCATENATED MODULE: ./discourse-pro/src/module/dragBar.ts
  483.  
  484.  
  485. function loadDragBar(options) {
  486. var mainOutletWrapper = options.mainOutletWrapper,
  487. sidebarWrapper = options.sidebarWrapper,
  488. sidebar = options.sidebar,
  489. headerSidebarToggleBtn = options.headerSidebarToggleBtn,
  490. sidebarWidthKey = options.sidebarWidthKey,
  491. minSidebarWidth = options.minSidebarWidth,
  492. maxSidebarWidth = options.maxSidebarWidth;
  493. var $mainOutletWrapper = $(mainOutletWrapper),
  494. $sidebarWrapper = $(sidebarWrapper),
  495. $sidebar = $(sidebar),
  496. $headerSidebarToggleBtn = $(headerSidebarToggleBtn);
  497.  
  498. // 侧边栏是否存在
  499. var sidebarExist = $sidebar.length > 0;
  500. if (sidebarExist) {
  501. // 读取存储的侧边栏宽度
  502. var storeSidebarWidth = Store/* default */.A.get(sidebarWidthKey);
  503. if (storeSidebarWidth) {
  504. $mainOutletWrapper.css('grid-template-columns', "".concat(storeSidebarWidth, "px minmax(0, 1fr)"));
  505. }
  506. }
  507.  
  508. // 在侧边栏内部追加一个拖拽条
  509. $sidebarWrapper.append("\n <div class=\"drag-bar\" style=\"width: 4px; cursor: ew-resize\"></div>\n ");
  510.  
  511. // 拖拽条
  512. var $dragBar = $sidebarWrapper.find('.drag-bar');
  513. // 是否正在拖拽
  514. var isDragging = false;
  515. // 鼠标按下时的 clientX
  516. var startClientX = 0;
  517. // 鼠标按下时的侧边栏宽度
  518. var startSidebarWidth = 0;
  519. // 侧边栏新宽度
  520. var newSidebarWidth = 0;
  521.  
  522. // 鼠标按下事件
  523. $dragBar.on('mousedown', function (e) {
  524. startClientX = e.clientX;
  525. startSidebarWidth = $sidebarWrapper.width() || 0;
  526. isDragging = true;
  527. // 改变鼠标样式
  528. document.body.style.cursor = 'ew-resize';
  529. // 设置拖拽条背景色
  530. $dragBar.css('background-color', '#e6e6e6');
  531. // 防止文本被选中
  532. e.preventDefault();
  533. });
  534.  
  535. // 鼠标移动事件
  536. $(document).on('mousemove', function (e) {
  537. if (!isDragging) return;
  538.  
  539. // 计算新的宽度
  540. var deltaX = e.clientX - startClientX;
  541. newSidebarWidth = Math.min(maxSidebarWidth, Math.max(minSidebarWidth, startSidebarWidth + deltaX));
  542. $mainOutletWrapper.css('grid-template-columns', "".concat(newSidebarWidth, "px minmax(0, 1fr)"));
  543. loadWidescreenModeByTopic(options);
  544. });
  545.  
  546. // 鼠标松开事件
  547. $(document).on('mouseup', function () {
  548. if (!isDragging) return;
  549. isDragging = false;
  550. // 恢复鼠标样式
  551. document.body.style.cursor = 'default';
  552. // 恢复拖拽条背景色
  553. $dragBar.css('background-color', 'transparent');
  554. // 记忆侧边栏宽度
  555. Store/* default */.A.set(sidebarWidthKey, newSidebarWidth);
  556. });
  557.  
  558. // 展开收起侧边栏按钮点击事件
  559. $headerSidebarToggleBtn.on('click', function () {
  560. sidebarExist = !sidebarExist;
  561. $mainOutletWrapper.css('grid-template-columns', "".concat(sidebarExist ? Store/* default */.A.get(sidebarWidthKey) + 'px' : '0', " minmax(0, 1fr)"));
  562. });
  563. }
  564. // EXTERNAL MODULE: ./discourse-pro/src/Options.ts + 2 modules
  565. var Options = __webpack_require__(545);
  566. ;// CONCATENATED MODULE: ./discourse-pro/src/main.ts
  567. function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
  568. function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
  569. function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
  570. function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  571. function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
  572. function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
  573. // ==UserScript==
  574. // @name Discourse Pro
  575. // @namespace http://tampermonkey.net/
  576. // @version 0.1.3
  577. // @description 增强 Discourse 论坛。
  578. // @author duanluan
  579. // @copyright 2024, duanluan (https://github.com/duanluan)
  580. // @license Apache-2.0; https://www.apache.org/licenses/LICENSE-2.0.txt
  581. // @homepage https://greasyfork.org/zh-CN/scripts/520817
  582. // @supportURL https://github.com/duanluan/tampermonkey-scripts/issues
  583. // @match *://greasyfork.org/*
  584. // @match *://linux.do/*
  585. // @match *://meta.appinn.net/*
  586. // @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.slim.min.js
  587. // @grant GM_getValue
  588. // @grant GM_setValue
  589. // @grant GM_registerMenuCommand
  590. // @grant GM_unregisterMenuCommand
  591. // ==/UserScript==
  592.  
  593. // ==OpenUserJS==
  594. // @author duanluan
  595. // @updateURL https://raw.kkgithub.com/duanluan/tampermonkey-scripts/main/discourse-pro/dist/discourse-pro.user.js
  596. // ==/OpenUserJS==
  597.  
  598.  
  599.  
  600.  
  601.  
  602. (function (_$) {
  603. 'use strict';
  604.  
  605. Options/* default */.A.registerAll();
  606. Options/* default */.A.loadInGreasyfork();
  607.  
  608. // 判断是否为 Discourse
  609. var generator = (_$ = $('meta[name="generator"]')) === null || _$ === void 0 ? void 0 : _$.attr('content');
  610. if (!generator || generator.indexOf('Discourse') == -1) return;
  611. var selector = {
  612. headerWrap: '.d-header>.wrap',
  613. // 侧边栏展开收起按钮
  614. headerSidebarToggleBtn: '.header-sidebar-toggle>button',
  615. // 侧边栏和主内容的父容器
  616. mainOutletWrapper: '#main-outlet-wrapper',
  617. // 侧边栏
  618. sidebarWrapper: '.sidebar-wrapper',
  619. sidebar: '#d-sidebar',
  620. // 主内容
  621. mainOutlet: '#main-outlet',
  622. // 话题内容父容器
  623. postStream: '.post-stream',
  624. // 话题头像
  625. topicAvatar: '.topic-avatar',
  626. // 话题内容
  627. topicBody: '.topic-body',
  628. // 话题主内容后浏览量、链接、回复人等信息
  629. topicMap: '.topic-map',
  630. // 最后一个回复后的底边框
  631. loadingContainer: '.loading-container',
  632. topicTimerInfo: '.topic-timer-info',
  633. // 话题底部按钮
  634. topicFooterBtns: '#topic-footer-buttons',
  635. // 更多话题列表
  636. moreTopicsContainer: '.more-topics__container'
  637. };
  638. var storeKeys = {
  639. // 侧边栏宽度
  640. sidebarWidth: 'sidebarWidth_'
  641. };
  642.  
  643. // 加载拖拽条
  644. if (JSON.parse(Store/* default */.A.get(Options/* default */.A.Keys.dragBar)).value) {
  645. loadDragBar(_objectSpread(_objectSpread({}, selector), {}, {
  646. sidebarWidthKey: storeKeys.sidebarWidth + location.host,
  647. minSidebarWidth: 180,
  648. maxSidebarWidth: 500
  649. }));
  650. }
  651. // 加载宽屏模式
  652. if (JSON.parse(Store/* default */.A.get(Options/* default */.A.Keys.widescreenMode)).value) {
  653. loadWidescreenMode(_objectSpread({}, selector));
  654. }
  655. })();
  656.  
  657. /***/ }),
  658.  
  659. /***/ 915:
  660. /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
  661.  
  662. /* harmony export */ __webpack_require__.d(__webpack_exports__, {
  663. /* harmony export */ A: () => (/* binding */ Store)
  664. /* harmony export */ });
  665. function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
  666. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  667. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
  668. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
  669. function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
  670. function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
  671. /**
  672. * 存储
  673. */
  674. var Store = /*#__PURE__*/function () {
  675. function Store() {
  676. _classCallCheck(this, Store);
  677. }
  678. return _createClass(Store, null, [{
  679. key: "get",
  680. value:
  681. /**
  682. * 获取
  683. * @param key 键
  684. */
  685. function get(key) {
  686. return GM_getValue(key);
  687. }
  688.  
  689. /**
  690. * 设置
  691. * @param key 键
  692. * @param value 值
  693. */
  694. }, {
  695. key: "set",
  696. value: function set(key, value) {
  697. GM_setValue(key, value);
  698. }
  699. }]);
  700. }();
  701.  
  702.  
  703. /***/ })
  704.  
  705. /******/ });
  706. /************************************************************************/
  707. /******/ // The module cache
  708. /******/ var __webpack_module_cache__ = {};
  709. /******/
  710. /******/ // The require function
  711. /******/ function __webpack_require__(moduleId) {
  712. /******/ // Check if module is in cache
  713. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  714. /******/ if (cachedModule !== undefined) {
  715. /******/ return cachedModule.exports;
  716. /******/ }
  717. /******/ // Create a new module (and put it into the cache)
  718. /******/ var module = __webpack_module_cache__[moduleId] = {
  719. /******/ // no module.id needed
  720. /******/ // no module.loaded needed
  721. /******/ exports: {}
  722. /******/ };
  723. /******/
  724. /******/ // Execute the module function
  725. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  726. /******/
  727. /******/ // Return the exports of the module
  728. /******/ return module.exports;
  729. /******/ }
  730. /******/
  731. /************************************************************************/
  732. /******/ /* webpack/runtime/define property getters */
  733. /******/ (() => {
  734. /******/ // define getter functions for harmony exports
  735. /******/ __webpack_require__.d = (exports, definition) => {
  736. /******/ for(var key in definition) {
  737. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  738. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  739. /******/ }
  740. /******/ }
  741. /******/ };
  742. /******/ })();
  743. /******/
  744. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  745. /******/ (() => {
  746. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  747. /******/ })();
  748. /******/
  749. /************************************************************************/
  750. /******/
  751. /******/ // startup
  752. /******/ // Load entry module and return exports
  753. /******/ // This entry module is referenced by other modules so it can't be inlined
  754. /******/ __webpack_require__(545);
  755. /******/ var __webpack_exports__ = __webpack_require__(150);
  756. /******/
  757. /******/ })()
  758. ;
  759. //# sourceMappingURL=discourse-pro.user.js.map