Discourse Pro

增强 Discourse 论坛

目前為 2025-01-02 提交的版本,檢視 最新版本

  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. var $headerWrap = $(headerWrap),
  345. $mainOutletWrapper = $(mainOutletWrapper),
  346. $mainOutlet = $(mainOutlet);
  347.  
  348. // 顶部撑满
  349. $headerWrap.css('max-width', '100%');
  350. // 侧边栏和主内容撑满
  351. $mainOutletWrapper.css('max-width', '100%');
  352. // 主内容撑满
  353. $mainOutlet.css('width', '100%');
  354.  
  355. // console.debug('话题页首次加载宽屏模式 + 监听话题列表变化')
  356. // 话题页首次加载宽屏模式 + 监听话题列表变化
  357. loadWidescreenModeByTopicAndObserver(options);
  358.  
  359. // 历史记录变化时话题页重新加载宽屏模式
  360. window.addEventListener('popstate', function () {
  361. // console.debug('历史记录变化时话题页重新加载宽屏模式')
  362. popstateAndPushStateListener(options);
  363. });
  364. // 单页面 pushState 切换页面时话题页重新加载宽屏模式
  365. window.addEventListener('pushState', function () {
  366. // console.debug('单页面 pushState 切换页面时话题页重新加载宽屏模式')
  367. popstateAndPushStateListener(options);
  368. });
  369. window.addEventListener('replaceState', function () {
  370. // console.debug('单页面 replaceState 切换页面时话题页重新加载宽屏模式')
  371. popstateAndPushStateListener(options);
  372. });
  373. }
  374.  
  375. /**
  376. * popstate 和 pushState 事件监听
  377. * @param options 选项
  378. */
  379. function popstateAndPushStateListener(options) {
  380. if (location.href.indexOf('/t/') !== -1) {
  381. // 等待 .post-stream 加载完成
  382. var interval = setInterval(function () {
  383. if ($(options.postStream).length > 0) {
  384. clearInterval(interval);
  385. loadWidescreenModeByTopicAndObserver(options);
  386. }
  387. }, 500);
  388. }
  389. }
  390.  
  391. /**
  392. * 话题页加载宽屏模式 + 监听话题内容变化
  393. * @param options 选项
  394. */
  395. function loadWidescreenModeByTopicAndObserver(options) {
  396. // 监听话题列表变化
  397. if (location.href.indexOf('/t/') == -1) {
  398. return;
  399. }
  400. loadWidescreenModeByTopic(options);
  401. var $postStream = $(options.postStream);
  402. if ($postStream.data('hasObserver')) {
  403. // console.debug('[discourse-pro-widescreenMode] 已存在话题内容变化监听器,跳过');
  404. return;
  405. }
  406.  
  407. // 防抖函数
  408. var debounceTimeout;
  409. var debounce = function debounce(func, delay) {
  410. clearTimeout(debounceTimeout);
  411. debounceTimeout = setTimeout(func, delay);
  412. };
  413. var observer = new MutationObserver(function (mutationsList) {
  414. debounce(function () {
  415. loadWidescreenModeByTopic(options);
  416. }, 1000);
  417. });
  418.  
  419. // 是否已监听
  420. $postStream.data('hasObserver', true);
  421. // 此处监听 .posts-wrapper 下的所有节点而不是 .post-stream 下的子节点,因为 .post-stream 会在时间轴跳动后重新加载
  422. observer.observe($postStream[0], {
  423. // 监听子节点
  424. childList: true,
  425. // 不监听子节点下的节点
  426. subtree: false
  427. });
  428. }
  429.  
  430. /**
  431. * 话题页加载宽屏模式
  432. * @param options
  433. */
  434. function loadWidescreenModeByTopic(options) {
  435. var mainOutlet = options.mainOutlet,
  436. postsContainer = options.postsContainer,
  437. postStream = options.postStream,
  438. topicAvatar = options.topicAvatar,
  439. topicBody = options.topicBody,
  440. topicMap = options.topicMap,
  441. smallActionDesc = options.smallActionDesc,
  442. topicPostVisitedLine = options.topicPostVisitedLine,
  443. loadingContainer = options.loadingContainer,
  444. topicTimerInfo = options.topicTimerInfo,
  445. topicFooterBtns = options.topicFooterBtns,
  446. moreTopicsContainer = options.moreTopicsContainer;
  447. var $mainOutlet = $(mainOutlet),
  448. $postsContainer = $(postsContainer),
  449. $postStream = $(postStream),
  450. $topicAvatar = $(topicAvatar),
  451. $topicBody = $(topicBody),
  452. $topicMap = $(topicMap),
  453. $smallActionDesc = $(smallActionDesc),
  454. $topicPostVisitedLine = $(topicPostVisitedLine),
  455. $loadingContainer = $(loadingContainer),
  456. $topicTimerInfo = $(topicTimerInfo),
  457. $topicFooterBtns = $(topicFooterBtns),
  458. $moreTopicsContainer = $(moreTopicsContainer);
  459. var $sidebarWrapper = $(options.sidebarWrapper);
  460. // 无侧边栏
  461. if ($sidebarWrapper.width() == 0) {
  462. $postsContainer.css('grid-template-columns', '75% 25%');
  463. // 没有侧边栏左侧增加边距
  464. $mainOutlet.css('margin-left', '30px');
  465. }
  466. var postStreamWidth = $postStream.width();
  467. var topicAvatarWidth = $topicAvatar.width();
  468. var topicWidth = postStreamWidth - 45;
  469. var topicBodyWidth = topicWidth - topicAvatarWidth + 'px';
  470.  
  471. // 如果第一个的宽度和最后一个的宽度不一样,说明话题列表变化了
  472. var firstTopicBodyWidth = $($topicBody[0]).css('width');
  473. var lastTopicBodyWidth = $($topicBody[$topicBody.length - 1]).css('width');
  474. if (firstTopicBodyWidth == lastTopicBodyWidth && firstTopicBodyWidth == topicBodyWidth) {
  475. // console.debug('[discourse-pro-widescreenMode] 话题页加载宽屏模式已加载过,跳过');
  476. return;
  477. }
  478.  
  479. // 话题内容撑满
  480. $topicBody.css('width', topicBodyWidth);
  481. // 话题主内容后浏览量、链接、回复人等信息撑满
  482. $topicMap.css('max-width', topicWidth + 'px');
  483. // 最后一个回复后的底边框撑满
  484. $loadingContainer.css('width', topicWidth + 'px');
  485. $topicTimerInfo.css('max-width', topicWidth + 'px');
  486. // 一段时间后的分隔线撑满
  487. $smallActionDesc.css('width', topicWidth - topicAvatarWidth + 'px');
  488. // 上次访问分隔线撑满
  489. $topicPostVisitedLine.css('width', topicWidth + 'px');
  490. // 话题底部按钮撑满
  491. $topicFooterBtns.css('max-width', topicWidth + 'px');
  492. // 更多话题列表撑满
  493. $moreTopicsContainer.css('max-width', topicWidth + 'px');
  494. }
  495.  
  496. ;// CONCATENATED MODULE: ./discourse-pro/src/module/dragBar.ts
  497.  
  498.  
  499. function loadDragBar(options) {
  500. var mainOutletWrapper = options.mainOutletWrapper,
  501. mainOutlet = options.mainOutlet,
  502. sidebarWrapper = options.sidebarWrapper,
  503. sidebar = options.sidebar,
  504. headerSidebarToggleBtn = options.headerSidebarToggleBtn,
  505. sidebarWidthKey = options.sidebarWidthKey,
  506. minSidebarWidth = options.minSidebarWidth,
  507. maxSidebarWidth = options.maxSidebarWidth;
  508. var $mainOutletWrapper = $(mainOutletWrapper),
  509. $mainOutlet = $(mainOutlet),
  510. $sidebarWrapper = $(sidebarWrapper),
  511. $sidebar = $(sidebar),
  512. $headerSidebarToggleBtn = $(headerSidebarToggleBtn);
  513.  
  514. // 侧边栏是否存在
  515. var sidebarExist = $sidebar.length > 0;
  516. if (sidebarExist) {
  517. // 读取存储的侧边栏宽度
  518. var storeSidebarWidth = Store/* default */.A.get(sidebarWidthKey);
  519. if (storeSidebarWidth) {
  520. $mainOutletWrapper.css('grid-template-columns', "".concat(storeSidebarWidth, "px minmax(0, 1fr)"));
  521. }
  522. }
  523.  
  524. // 在侧边栏内部追加一个拖拽条
  525. $sidebarWrapper.append("\n <div class=\"drag-bar\" style=\"width: 4px; cursor: ew-resize\"></div>\n ");
  526.  
  527. // 拖拽条
  528. var $dragBar = $sidebarWrapper.find('.drag-bar');
  529. // 是否正在拖拽
  530. var isDragging = false;
  531. // 鼠标按下时的 clientX
  532. var startClientX = 0;
  533. // 鼠标按下时的侧边栏宽度
  534. var startSidebarWidth = 0;
  535. // 侧边栏新宽度
  536. var newSidebarWidth = 0;
  537.  
  538. // 鼠标按下事件
  539. $dragBar.on('mousedown', function (e) {
  540. startClientX = e.clientX;
  541. startSidebarWidth = $sidebarWrapper.width() || 0;
  542. isDragging = true;
  543. // 改变鼠标样式
  544. document.body.style.cursor = 'ew-resize';
  545. // 设置拖拽条背景色
  546. $dragBar.css('background-color', '#e6e6e6');
  547. // 防止文本被选中
  548. e.preventDefault();
  549. });
  550.  
  551. // 鼠标移动事件
  552. $(document).on('mousemove', function (e) {
  553. if (!isDragging) return;
  554.  
  555. // 计算新的宽度
  556. var deltaX = e.clientX - startClientX;
  557. newSidebarWidth = Math.min(maxSidebarWidth, Math.max(minSidebarWidth, startSidebarWidth + deltaX));
  558. $mainOutletWrapper.css('grid-template-columns', "".concat(newSidebarWidth, "px minmax(0, 1fr)"));
  559. loadWidescreenModeByTopic(options);
  560. });
  561.  
  562. // 鼠标松开事件
  563. $(document).on('mouseup', function () {
  564. if (!isDragging) return;
  565. isDragging = false;
  566. // 恢复鼠标样式
  567. document.body.style.cursor = 'default';
  568. // 恢复拖拽条背景色
  569. $dragBar.css('background-color', 'transparent');
  570. // 记忆侧边栏宽度
  571. Store/* default */.A.set(sidebarWidthKey, newSidebarWidth);
  572. });
  573.  
  574. // 展开收起侧边栏按钮点击事件
  575. $headerSidebarToggleBtn.on('click', function () {
  576. sidebarExist = !sidebarExist;
  577. $mainOutletWrapper.css('grid-template-columns', "".concat(sidebarExist ? Store/* default */.A.get(sidebarWidthKey) + 'px' : '0', " minmax(0, 1fr)"));
  578. // 同 loadWidescreenModeByTopic 中在侧边栏缩起后加左外边距
  579. $mainOutlet.css('margin-left', !sidebarExist ? '30px' : 0);
  580.  
  581. // 延迟执行确保侧边栏已经展开或收起
  582. setTimeout(function () {
  583. loadWidescreenModeByTopic(options);
  584. }, 300);
  585. });
  586. }
  587. // EXTERNAL MODULE: ./discourse-pro/src/Options.ts + 2 modules
  588. var Options = __webpack_require__(545);
  589. ;// CONCATENATED MODULE: ./discourse-pro/src/main.ts
  590. 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); }
  591. 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; }
  592. 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; }
  593. 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; }
  594. function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
  595. 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); }
  596. // ==UserScript==
  597. // @name Discourse Pro
  598. // @namespace http://tampermonkey.net/
  599. // @version 0.1.5
  600. // @description 增强 Discourse 论坛
  601. // @author duanluan
  602. // @copyright 2024, duanluan (https://github.com/duanluan)
  603. // @license Apache-2.0; https://www.apache.org/licenses/LICENSE-2.0.txt
  604. // @homepage https://greasyfork.org/zh-CN/scripts/520817
  605. // @supportURL https://github.com/duanluan/tampermonkey-scripts/issues
  606. // @match *://greasyfork.org/*
  607. // @match *://meta.appinn.net/*
  608. // @match *://linux.do/*
  609. // @match *://answers.netlify.com/*
  610. // @match *://community.cloudflare.com/*
  611. // @match *://community.openai.com/*
  612. // @match *://forums.docker.com/*
  613. // @match *://discourse.webflow.com/*
  614. // @require https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.slim.min.js
  615. // @grant GM_getValue
  616. // @grant GM_setValue
  617. // @grant GM_registerMenuCommand
  618. // @grant GM_unregisterMenuCommand
  619. // ==/UserScript==
  620.  
  621. // ==OpenUserJS==
  622. // @author duanluan
  623. // @updateURL https://raw.kkgithub.com/duanluan/tampermonkey-scripts/main/discourse-pro/dist/discourse-pro.user.js
  624. // ==/OpenUserJS==
  625.  
  626.  
  627.  
  628.  
  629.  
  630. (function (_$) {
  631. 'use strict';
  632.  
  633. Options/* default */.A.registerAll();
  634. Options/* default */.A.loadInGreasyfork();
  635.  
  636. // 判断是否为 Discourse
  637. var generator = (_$ = $('meta[name="generator"]')) === null || _$ === void 0 ? void 0 : _$.attr('content');
  638. if (!generator || generator.indexOf('Discourse') == -1) return;
  639. var selector = {
  640. headerWrap: '.d-header>.wrap',
  641. // 侧边栏展开收起按钮
  642. headerSidebarToggleBtn: '.header-sidebar-toggle>button',
  643. // 侧边栏和主内容的父容器
  644. mainOutletWrapper: '#main-outlet-wrapper',
  645. // 侧边栏
  646. sidebarWrapper: '.sidebar-wrapper',
  647. sidebar: '#d-sidebar',
  648. // 主内容
  649. mainOutlet: '#main-outlet',
  650. // 话题内容和右侧内容
  651. postsContainer: '.container.posts',
  652. // 话题内容父容器
  653. postStream: '.post-stream',
  654. // 话题头像
  655. topicAvatar: '.topic-avatar',
  656. // 话题内容
  657. topicBody: '.topic-body',
  658. // 话题主内容后浏览量、链接、回复人等信息
  659. topicMap: '.topic-map',
  660. // 一段时间后的分隔线
  661. smallActionDesc: '.small-action-desc',
  662. // 上次访问分隔线
  663. topicPostVisitedLine: '.topic-post-visited-line',
  664. // 最后一个回复后的底边框
  665. loadingContainer: '.loading-container',
  666. topicTimerInfo: '.topic-timer-info',
  667. // 话题底部按钮
  668. topicFooterBtns: '#topic-footer-buttons',
  669. // 更多话题列表
  670. moreTopicsContainer: '.more-topics__container'
  671. };
  672. var storeKeys = {
  673. // 侧边栏宽度
  674. sidebarWidth: 'sidebarWidth_'
  675. };
  676.  
  677. // 加载拖拽条
  678. if (JSON.parse(Store/* default */.A.get(Options/* default */.A.Keys.dragBar)).value) {
  679. loadDragBar(_objectSpread(_objectSpread({}, selector), {}, {
  680. sidebarWidthKey: storeKeys.sidebarWidth + location.host,
  681. minSidebarWidth: 180,
  682. maxSidebarWidth: 500
  683. }));
  684. }
  685. // 加载宽屏模式
  686. if (JSON.parse(Store/* default */.A.get(Options/* default */.A.Keys.widescreenMode)).value) {
  687. loadWidescreenMode(_objectSpread({}, selector));
  688. }
  689. })();
  690.  
  691. /***/ }),
  692.  
  693. /***/ 915:
  694. /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
  695.  
  696. /* harmony export */ __webpack_require__.d(__webpack_exports__, {
  697. /* harmony export */ A: () => (/* binding */ Store)
  698. /* harmony export */ });
  699. 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); }
  700. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  701. 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); } }
  702. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
  703. function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
  704. 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); }
  705. /**
  706. * 存储
  707. */
  708. var Store = /*#__PURE__*/function () {
  709. function Store() {
  710. _classCallCheck(this, Store);
  711. }
  712. return _createClass(Store, null, [{
  713. key: "get",
  714. value:
  715. /**
  716. * 获取
  717. * @param key 键
  718. */
  719. function get(key) {
  720. return GM_getValue(key);
  721. }
  722.  
  723. /**
  724. * 设置
  725. * @param key 键
  726. * @param value 值
  727. */
  728. }, {
  729. key: "set",
  730. value: function set(key, value) {
  731. GM_setValue(key, value);
  732. }
  733. }]);
  734. }();
  735.  
  736.  
  737. /***/ })
  738.  
  739. /******/ });
  740. /************************************************************************/
  741. /******/ // The module cache
  742. /******/ var __webpack_module_cache__ = {};
  743. /******/
  744. /******/ // The require function
  745. /******/ function __webpack_require__(moduleId) {
  746. /******/ // Check if module is in cache
  747. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  748. /******/ if (cachedModule !== undefined) {
  749. /******/ return cachedModule.exports;
  750. /******/ }
  751. /******/ // Create a new module (and put it into the cache)
  752. /******/ var module = __webpack_module_cache__[moduleId] = {
  753. /******/ // no module.id needed
  754. /******/ // no module.loaded needed
  755. /******/ exports: {}
  756. /******/ };
  757. /******/
  758. /******/ // Execute the module function
  759. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  760. /******/
  761. /******/ // Return the exports of the module
  762. /******/ return module.exports;
  763. /******/ }
  764. /******/
  765. /************************************************************************/
  766. /******/ /* webpack/runtime/define property getters */
  767. /******/ (() => {
  768. /******/ // define getter functions for harmony exports
  769. /******/ __webpack_require__.d = (exports, definition) => {
  770. /******/ for(var key in definition) {
  771. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  772. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  773. /******/ }
  774. /******/ }
  775. /******/ };
  776. /******/ })();
  777. /******/
  778. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  779. /******/ (() => {
  780. /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  781. /******/ })();
  782. /******/
  783. /************************************************************************/
  784. /******/
  785. /******/ // startup
  786. /******/ // Load entry module and return exports
  787. /******/ // This entry module is referenced by other modules so it can't be inlined
  788. /******/ __webpack_require__(545);
  789. /******/ var __webpack_exports__ = __webpack_require__(150);
  790. /******/
  791. /******/ })()
  792. ;
  793. //# sourceMappingURL=discourse-pro.user.js.map