1+ // ==UserScript==
2+ // @name 全球主机交流论坛增强
3+ // @version 1.0.0
4+ // @author X.I.U
5+ // @description 自动无缝翻页
6+ // @match *://www.hostloc.com/*
7+ // @icon https://www.hostloc.com/favicon.ico
8+ // @grant GM_xmlhttpRequest
9+ // @license GPL-3.0 License
10+ // @run -at document-end
11+ // @namespace https://greasyfork.org/scripts/414005
12+ // ==/UserScript==
13+
14+ ( function ( ) {
15+ // 是否开启帖子内自动翻页功能,true 为开启,false 为关闭。
16+ var thread_pageLoading = true ;
17+
18+ // 默认 ID 为 0
19+ var curSite = { SiteTypeID : 0 } ;
20+
21+ // 自动翻页规则
22+ let DBSite = {
23+ forum : {
24+ SiteTypeID : 1
25+ } ,
26+ thread : {
27+ SiteTypeID : 2 ,
28+ pager : {
29+ nextLink : '//div[@id="pgt"]//a[contains(text(),"下一页")][@href]' ,
30+ pageElement : 'css;div#postlist > div[id^="post_"]' ,
31+ HT_insert : [ 'css;div#postlist' , 2 ] ,
32+ replaceE : '//div[@class="pg"] | //div[@class="pgbtn"]' ,
33+ }
34+ } ,
35+ guide : {
36+ SiteTypeID : 3 ,
37+ pager : {
38+ nextLink : '//div[@id="pgt"]//a[contains(text(),"下一页")][@href]' ,
39+ pageElement : 'css;div#threadlist div.bm_c table > tbody[id^="normalthread_"]' ,
40+ HT_insert : [ 'css;div#threadlist div.bm_c table' , 2 ] ,
41+ replaceE : 'css;div.pg' ,
42+ }
43+ }
44+ } ;
45+
46+ // 用于脚本内部判断当前 URL 类型
47+ let SiteType = {
48+ FORUM : DBSite . forum . SiteTypeID , // 各板块帖子列表
49+ THREAD : DBSite . thread . SiteTypeID , // 帖子内
50+ GUIDE : DBSite . guide . SiteTypeID // 导读帖子列表
51+ } ;
52+
53+ // URL 匹配正则表达式
54+ var patt_thread = / \/ t h r e a d - \d + - \d + \- \d + .h t m l / ,
55+ patt_thread_2 = / m o d \= v i e w t h r e a d / ,
56+ patt_forum = / \/ f o r u m - \d + - \d + \. h t m l / ,
57+ patt_forum_2 = / m o d \= f o r u m d i s p l a y / ,
58+ patt_guide = / m o d \= g u i d e \& v i e w \= ( h o t | d i g e s t ) /
59+
60+ // URL 判断
61+ if ( patt_thread . test ( location . pathname ) || patt_thread_2 . test ( location . search ) ) {
62+ // 帖子内
63+ if ( thread_pageLoading ) curSite = DBSite . thread ;
64+ // 自动显示帖子内被隐藏的回复
65+ showPosts ( ) ;
66+ } else if ( patt_forum . test ( location . pathname ) || patt_forum_2 . test ( location . search ) ) {
67+ // 各板块帖子列表
68+ curSite = DBSite . forum ;
69+ } else if ( patt_guide . test ( location . search ) ) {
70+ // 导读帖子列表
71+ curSite = DBSite . guide ;
72+ }
73+ curSite . pageUrl = "" ; // 下一页URL
74+
75+
76+ pageLoading ( ) ; // 自动翻页
77+
78+
79+ // 自动翻页
80+ function pageLoading ( ) {
81+ if ( curSite . SiteTypeID > 0 ) {
82+ windowScroll ( function ( direction , e ) {
83+ if ( direction === "down" ) { // 下滑才准备翻页
84+ var scrollTop = document . documentElement . scrollTop || window . pageYOffset || document . body . scrollTop ;
85+ let scrollDelta = 666 ;
86+ if ( document . documentElement . scrollHeight <= document . documentElement . clientHeight + scrollTop + scrollDelta ) {
87+ if ( curSite . SiteTypeID === SiteType . FORUM ) { // 如果是各版块帖子列表则直接点下一页就行了
88+ var autopbn = document . querySelector ( '#autopbn' ) ;
89+ if ( autopbn && autopbn . innerText == "下一页 »" ) { // 如果已经在加载中了,就忽略
90+ autopbn . click ( ) ;
91+ }
92+ } else {
93+ ShowPager . loadMorePage ( ) ;
94+ }
95+ }
96+ }
97+ } ) ;
98+ }
99+ }
100+
101+
102+ // 自动显示帖子内被隐藏的回复
103+ function showPosts ( ) {
104+ var showposts = document . querySelector ( '#hiddenpoststip a' ) ;
105+ if ( showposts ) { // 如果存在
106+ showposts . click ( ) ;
107+ }
108+ }
109+
110+
111+ // 滚动条事件
112+ function windowScroll ( fn1 ) {
113+ var beforeScrollTop = document . documentElement . scrollTop ,
114+ fn = fn1 || function ( ) { } ;
115+ setTimeout ( function ( ) { // 延时执行,避免刚载入到页面就触发翻页事件
116+ window . addEventListener ( "scroll" , function ( e ) {
117+ var afterScrollTop = document . documentElement . scrollTop ,
118+ delta = afterScrollTop - beforeScrollTop ;
119+ if ( delta == 0 ) return false ;
120+ fn ( delta > 0 ? "down" : "up" , e ) ;
121+ beforeScrollTop = afterScrollTop ;
122+ } , false ) ;
123+ } , 1000 )
124+ }
125+
126+
127+ var ShowPager = { // 修改自 https://greasyfork.org/scripts/14178
128+ getFullHref : function ( e ) {
129+ if ( e == null ) return '' ;
130+ "string" != typeof e && ( e = e . getAttribute ( "href" ) ) ;
131+ var t = this . getFullHref . a ;
132+ return t || ( this . getFullHref . a = t = document . createElement ( "a" ) ) , t . href = e , t . href ;
133+ } ,
134+ createDocumentByString : function ( e ) {
135+ if ( e ) {
136+ if ( "HTML" !== document . documentElement . nodeName ) return ( new DOMParser ) . parseFromString ( e , "application/xhtml+xml" ) ;
137+ var t ;
138+ try {
139+ t = ( new DOMParser ) . parseFromString ( e , "text/html" ) ;
140+ } catch ( e ) {
141+ }
142+ if ( t ) return t ;
143+ if ( document . implementation . createHTMLDocument ) t = document . implementation . createHTMLDocument ( "ADocument" ) ; else try {
144+ ( t = document . cloneNode ( ! 1 ) ) . appendChild ( t . importNode ( document . documentElement , ! 1 ) ) ,
145+ t . documentElement . appendChild ( t . createElement ( "head" ) ) , t . documentElement . appendChild ( t . createElement ( "body" ) ) ;
146+ } catch ( e ) {
147+ }
148+ if ( t ) {
149+ var r = document . createRange ( ) ;
150+ r . selectNodeContents ( document . body ) ;
151+ var n = r . createContextualFragment ( e ) ;
152+ t . body . appendChild ( n ) ;
153+ for ( var a , o = {
154+ TITLE : ! 0 ,
155+ META : ! 0 ,
156+ LINK : ! 0 ,
157+ STYLE : ! 0 ,
158+ BASE : ! 0
159+ } , i = t . body , s = i . childNodes , c = s . length - 1 ; c >= 0 ; c -- ) o [ ( a = s [ c ] ) . nodeName ] && i . removeChild ( a ) ;
160+ return t ;
161+ }
162+ } else console . error ( "没有找到要转成DOM的字符串" ) ;
163+ } ,
164+ loadMorePage : function ( ) {
165+ if ( curSite . pager ) {
166+ let curPageEle = getElementByXpath ( curSite . pager . nextLink ) ;
167+ var url = this . getFullHref ( curPageEle ) ;
168+ //console.log(`${url} ${curPageEle} ${curSite.pageUrl}`);
169+ if ( url === '' ) return ;
170+ if ( curSite . pageUrl === url ) return ; // 不会重复加载相同的页面
171+ curSite . pageUrl = url ;
172+ // 读取下一页的数据
173+ curSite . pager . startFilter && curSite . pager . startFilter ( ) ;
174+ GM_xmlhttpRequest ( {
175+ url : url ,
176+ method : "GET" ,
177+ timeout : 5000 ,
178+ onload : function ( response ) {
179+ try {
180+ var newBody = ShowPager . createDocumentByString ( response . responseText ) ;
181+ let pageElems = getAllElements ( curSite . pager . pageElement , newBody , newBody ) ;
182+ let toElement = getAllElements ( curSite . pager . HT_insert [ 0 ] ) [ 0 ] ;
183+ if ( pageElems . length >= 0 ) {
184+ let addTo = "beforeend" ;
185+ if ( curSite . pager . HT_insert [ 1 ] == 1 ) addTo = "beforebegin" ;
186+ // 插入新页面元素
187+ pageElems . forEach ( function ( one ) {
188+ toElement . insertAdjacentElement ( addTo , one ) ;
189+ } ) ;
190+ // 替换待替换元素
191+ try {
192+ let oriE = getAllElements ( curSite . pager . replaceE ) ;
193+ let repE = getAllElements ( curSite . pager . replaceE , newBody , newBody ) ;
194+ if ( oriE . length === repE . length ) {
195+ for ( var i = 0 ; i < oriE . length ; i ++ ) {
196+ oriE [ i ] . outerHTML = repE [ i ] . outerHTML ;
197+ }
198+ }
199+ } catch ( e ) {
200+ console . log ( e ) ;
201+ }
202+ }
203+ } catch ( e ) {
204+ console . log ( e ) ;
205+ }
206+ }
207+ } ) ;
208+ }
209+ } ,
210+ } ;
211+
212+
213+ function getElementByXpath ( e , t , r ) {
214+ r = r || document , t = t || r ;
215+ try {
216+ return r . evaluate ( e , t , null , XPathResult . FIRST_ORDERED_NODE_TYPE , null ) . singleNodeValue ;
217+ } catch ( t ) {
218+ return void console . error ( "无效的xpath" ) ;
219+ }
220+ }
221+
222+
223+ function getAllElements ( e , t , r , n , o ) {
224+ let getAllElementsByXpath = function ( e , t , r ) {
225+ return r = r || document , t = t || r , r . evaluate ( e , t , null , XPathResult . ORDERED_NODE_SNAPSHOT_TYPE , null ) ;
226+ }
227+
228+ var i , s = [ ] ;
229+ if ( ! e ) return s ;
230+ if ( r = r || document , n = n || window , o = o || void 0 , t = t || r , "string" == typeof e ) i = 0 === e . search ( / ^ c s s ; / i) ? function getAllElementsByCSS ( e , t ) {
231+ return ( t || document ) . querySelectorAll ( e ) ;
232+ } ( e . slice ( 4 ) , t ) : getAllElementsByXpath ( e , t , r ) ; else {
233+ if ( ! ( i = e ( r , n , o ) ) ) return s ;
234+ if ( i . nodeType ) return s [ 0 ] = i , s ;
235+ }
236+ return function makeArray ( e ) {
237+ var t , r , n , o = [ ] ;
238+ if ( e . pop ) {
239+ for ( t = 0 , r = e . length ; t < r ; t ++ ) ( n = e [ t ] ) && ( n . nodeType ? o . push ( n ) : o = o . concat ( makeArray ( n ) ) ) ;
240+ return a ( ) ( o ) ;
241+ }
242+ if ( e . item ) {
243+ for ( t = e . length ; t ; ) o [ -- t ] = e [ t ] ;
244+ return o ;
245+ }
246+ if ( e . iterateNext ) {
247+ for ( t = e . snapshotLength ; t ; ) o [ -- t ] = e . snapshotItem ( t ) ;
248+ return o ;
249+ }
250+ } ( i ) ;
251+ }
252+ } ) ( ) ;
0 commit comments