skaviouz

AutoPagerizer Script Install

Mar 30th, 2017
367
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 36.71 KB | None | 0 0
  1. // ==UserScript==
  2. // @name AutoPagerize
  3. // @namespace http://swdyh.yu.to/
  4. // @description loading next page and inserting into current page.
  5. // @include http://*
  6. // @include https://*
  7. // @exclude https://mail.google.com/*
  8. // @exclude http://b.hatena.ne.jp/*
  9. // @exclude http://www.facebook.com/plugins/like.php*
  10. // @exclude http://api.tweetmeme.com/button.js*
  11. // @version 0.0.66
  12. // @icon http://autopagerize.net/img/icons/icon_032.png
  13. // @grant GM_getValue
  14. // @grant GM_setValue
  15. // @grant GM_addStyle
  16. // @grant GM_log
  17. // @grant GM_xmlhttpRequest
  18. // @grant GM_registerMenuCommand
  19. // ==/UserScript==
  20. //
  21. // auther: swdyh http://d.hatena.ne.jp/swdyh/
  22. // version: 0.0.66 2012-08-31T18:23:34+09:00
  23. //
  24. // this script based on
  25. // GoogleAutoPager(http://la.ma.la/blog/diary_200506231749.htm) and
  26. // estseek autopager(http://la.ma.la/blog/diary_200601100209.htm).
  27. // thanks to ma.la.
  28. //
  29. // Released under the GPL license
  30. // http://www.gnu.org/copyleft/gpl.html
  31. //
  32.  
  33. if (isGreasemonkey()) {
  34. var ep = getPref('exclude_patterns')
  35. if (ep && isExclude(ep)) {
  36. // FIXME
  37. // return
  38. }
  39. }
  40. else {
  41. gmCompatible()
  42. }
  43.  
  44. var URL = 'http://autopagerize.net/'
  45. var VERSION = '0.0.66'
  46. var DEBUG = false
  47. var AUTO_START = true
  48. var CACHE_EXPIRE = 24 * 60 * 60 * 1000
  49. var BASE_REMAIN_HEIGHT = 400
  50. var FORCE_TARGET_WINDOW = getPref('force_target_window', true)
  51. var XHR_TIMEOUT = 30 * 1000
  52. var SITEINFO_IMPORT_URLS = [
  53. 'http://wedata.net/databases/AutoPagerize/items.json',
  54. ]
  55. var COLOR = {
  56. on: '#0f0',
  57. off: '#ccc',
  58. loading: '#0ff',
  59. terminated: '#00f',
  60. error: '#f0f'
  61. }
  62. var SITEINFO = [
  63. {
  64. url: '^https?://',
  65. nextLink: '//*[@id="post-1274"]/div/p[45]/a[3] | //span[text()=\'Next Chapter\']/.. | //a[text()=\'Next Chapter\'] | //a[text()=\'Next Chapter \'] | //a[text()=\'Next Chapter ->\']',
  66. pageElement: '//div[@class=\'entry-content\']',
  67. exampleUrl: 'https://zirusmusings.com/db-ch18/',
  68. },
  69. {
  70. url: 'http://www.wuxiaworld.com/*',
  71. nextLink: '//a[text()=\'Next Chapter\'] | //span[text()=\'Next Chapter\']/.. | //a[text()=\'Next Chapter \'] | //article/div[@class=\'entry-content\']/div/div/p[1]/span/a',
  72. pageElement: '//article/div[@class=\'entry-content\']',
  73. exampleUrl: 'http://www.wuxiaworld.com/mga-index/mga-chapter-1478/',
  74. },
  75. {
  76. url: 'http://moonbunnycafe.com/*',
  77. nextLink: '//a[text()=\'Next Chapter ->\']',
  78. pageElement: '//div[@class=\'entry-content\']/..',
  79. exampleUrl: 'http://www.wuxiaworld.com/mga-index/mga-chapter-1478/',
  80. },
  81. /* sample
  82. {
  83. ^https?://(?:www\\.)?celebjihad\\.com
  84. ^https?:\/\/(?:www\.)?[a-zA-Z0-9]+\.com\/20[0-1][0-9]\/[0-9]{2}\/[0-9]{2}\/
  85. /html/body[@class='page-template-default page page-id-6815 page-child parent-pageid-6614 custom-background group-blog']/div[@id='page']/div[@id='content']/div[@id='primary']/main[@id='main']/article[@id='post-6815']/div[@class='entry-content']/div[1]/div/p[2]/span/strong
  86. url: 'http://(.*).google.+/(search).+',
  87. nextLink: 'id("navbar")//td[last()]/a',
  88. pageElement: '//div[@id="res"]/div',
  89. exampleUrl: 'http://www.google.com/search?q=nsIObserver',
  90. },
  91. */
  92. /* template
  93. {
  94. url: '',
  95. nextLink: '',
  96. pageElement: '',
  97. exampleUrl: '',
  98. },
  99. */
  100. ]
  101. var MICROFORMAT = {
  102. url: '.*',
  103. nextLink: '//a[@rel="next"] | //link[@rel="next"] | //a[@rel="Next Chapter"] | //link[@rel="Next Chapter"]',
  104. insertBefore: '//*[contains(@class, "autopagerize_insert_before")]',
  105. pageElement: '//*[contains(@class, "autopagerize_page_element")]',
  106. }
  107.  
  108. var AutoPager = function(info) {
  109. this.pageNum = 1
  110. this.info = info
  111. this.state = AUTO_START ? 'enable' : 'disable'
  112. var self = this
  113. var url = this.getNextURL(info.nextLink, document, location.href)
  114.  
  115. if ( !url ) {
  116. debug("getNextURL returns null.", info.nextLink)
  117. return
  118. }
  119. if (info.insertBefore) {
  120. this.insertPoint = getFirstElementByXPath(info.insertBefore)
  121. }
  122.  
  123. if (!this.insertPoint) {
  124. var lastPageElement = getElementsByXPath(info.pageElement).pop()
  125. if (lastPageElement) {
  126. this.insertPoint = lastPageElement.nextSibling ||
  127. lastPageElement.parentNode.appendChild(document.createTextNode(' '))
  128. }
  129. }
  130.  
  131. if (!this.insertPoint) {
  132. debug("insertPoint not found.", lastPageElement, info.pageElement)
  133. return
  134. }
  135.  
  136. this.requestURL = url
  137. this.loadedURLs = {}
  138. this.loadedURLs[location.href] = true
  139. var toggle = function() {self.stateToggle()}
  140. this.toggle = toggle
  141. GM_registerMenuCommand('AutoPagerize - on/off', toggle)
  142. this.scroll= function() { self.onScroll() }
  143. window.addEventListener("scroll", this.scroll, false)
  144.  
  145. if (isFirefoxExtension()) {
  146. var div = document.createElement("div")
  147. div.setAttribute('id', 'autopagerize_icon')
  148. div.style.display = 'none'
  149. document.body.appendChild(div)
  150. this.icon = div
  151. }
  152. else if (isChromeExtension() || isSafariExtension() || isJetpack()) {
  153. var frame = document.createElement('iframe')
  154. frame.style.display = 'none'
  155. frame.style.position = 'fixed'
  156. frame.style.bottom = '0px'
  157. frame.style.left = '0px'
  158. frame.style.height = '25px'
  159. frame.style.border = '0px'
  160. frame.style.opacity = '0.8'
  161. frame.style.zIndex = '1000'
  162. frame.width = '100%'
  163. frame.scrolling = 'no'
  164. this.messageFrame = frame
  165. var u = settings['extension_path'] ?
  166. settings['extension_path'] + 'loading.html' :
  167. 'http://autopagerize.net/files/loading.html'
  168. this.messageFrame.src = u
  169. document.body.appendChild(frame)
  170. if (isSafariExtension()) {
  171. safari.self.tab.dispatchMessage('launched', {url: location.href })
  172. }
  173. else if (isChromeExtension()) {
  174. chrome.extension.connect({name: "launched"}).postMessage()
  175. }
  176. if (isJetpack()) {
  177. postMessage({name: 'launched', data: location.href })
  178. }
  179. }
  180. else {
  181. this.initIcon()
  182. this.initHelp()
  183. GM_addStyle('@media print{#autopagerize_icon, #autopagerize_help {display: none !important;}}')
  184. GM_addStyle('hr.autopagerize_page_separator {clear: both;}')
  185. this.icon.addEventListener("mouseover", function() {
  186. self.viewHelp()
  187. }, true)
  188. }
  189.  
  190. var scrollHeight = getScrollHeight()
  191. var bottom = getElementPosition(this.insertPoint).top ||
  192. this.getPageElementsBottom() ||
  193. (Math.round(scrollHeight * 0.8))
  194. this.remainHeight = scrollHeight - bottom + BASE_REMAIN_HEIGHT
  195. this.onScroll()
  196.  
  197. var that = this
  198. document.addEventListener('AutoPagerizeToggleRequest', function() {
  199. that.toggle()
  200. }, false)
  201. document.addEventListener('AutoPagerizeUpdateIconRequest', function() {
  202. that.updateIcon()
  203. }, false)
  204. that.updateIcon()
  205. }
  206.  
  207. AutoPager.prototype.getPageElementsBottom = function() {
  208. try {
  209. var elem = getElementsByXPath(this.info.pageElement).pop()
  210. return getElementBottom(elem)
  211. }
  212. catch(e) {}
  213. }
  214.  
  215. AutoPager.prototype.initHelp = function() {
  216. var helpDiv = document.createElement('div')
  217. helpDiv.setAttribute('id', 'autopagerize_help')
  218. helpDiv.setAttribute('style', 'padding:5px;position:fixed;' +
  219. 'top:-200px;right:3px;font-size:10px;' +
  220. 'background:#fff;color:#000;border:1px solid #ccc;' +
  221. 'z-index:256;text-align:left;font-weight:normal;' +
  222. 'line-height:120%;font-family:verdana;')
  223.  
  224. var toggleDiv = document.createElement('div')
  225. toggleDiv.setAttribute('style', 'margin:0 0 0 50px;')
  226. var a = document.createElement('a')
  227. a.setAttribute('class', 'autopagerize_link')
  228. a.innerHTML = 'on/off'
  229. a.href = 'javascript:void(0)'
  230. var self = this
  231. var toggle = function() {
  232. self.stateToggle()
  233. helpDiv.style.top = '-200px'
  234. }
  235. a.addEventListener('click', toggle, false)
  236. toggleDiv.appendChild(a)
  237.  
  238. var s = '<div style="width:100px; float:left;">'
  239. for (var i in COLOR) {
  240. s += '<div style="float:left;width:1em;height:1em;' +
  241. 'margin:0 3px;background-color:' + COLOR[i] + ';' +
  242. '"></div><div style="margin:0 3px">' + i + '</div>'
  243. }
  244. s += '</div>'
  245. var colorDiv = document.createElement('div')
  246. colorDiv.innerHTML = s
  247. helpDiv.appendChild(colorDiv)
  248. helpDiv.appendChild(toggleDiv)
  249.  
  250. var versionDiv = document.createElement('div')
  251. versionDiv.setAttribute('style', 'clear:both;')
  252. versionDiv.innerHTML = '<a href="' + URL +
  253. '">AutoPagerize</a> ver ' + VERSION
  254. helpDiv.appendChild(versionDiv)
  255. document.body.appendChild(helpDiv)
  256.  
  257. var proc = function(e) {
  258. var c_style = document.defaultView.getComputedStyle(helpDiv, '')
  259. var s = ['top', 'left', 'height', 'width'].map(function(i) {
  260. return parseInt(c_style.getPropertyValue(i)) })
  261. if (e.clientX < s[1] || e.clientX > (s[1] + s[3] + 11) ||
  262. e.clientY < s[0] || e.clientY > (s[0] + s[2] + 11)) {
  263. helpDiv.style.top = '-200px'
  264. }
  265. }
  266. helpDiv.addEventListener('mouseout', proc, false)
  267. this.helpLayer = helpDiv
  268. GM_addStyle('#autopagerize_help a { color: #0f0; text-decoration: underline;}')
  269. }
  270.  
  271. AutoPager.prototype.viewHelp = function() {
  272. this.helpLayer.style.top = '3px'
  273. }
  274.  
  275. AutoPager.prototype.onScroll = function() {
  276. var scrollHeight = Math.max(document.documentElement.scrollHeight,
  277. document.body.scrollHeight)
  278. var remain = scrollHeight - window.innerHeight - window.scrollY
  279. if (this.state == 'enable' && remain < this.remainHeight) {
  280. this.request()
  281. }
  282. }
  283.  
  284. AutoPager.prototype.stateToggle = function() {
  285. if (this.state == 'enable') {
  286. this.disable()
  287. }
  288. else {
  289. this.enable()
  290. }
  291. }
  292.  
  293. AutoPager.prototype.enable = function() {
  294. this.state = 'enable'
  295. this.updateIcon()
  296. }
  297.  
  298. AutoPager.prototype.disable = function() {
  299. this.state = 'disable'
  300. this.updateIcon()
  301. }
  302.  
  303. AutoPager.prototype.updateIcon = function(state) {
  304. var st = state || this.state
  305. var rename = {'enable': 'on', 'disable': 'off' }
  306. if (rename[st]) {
  307. st = rename[st]
  308. }
  309. var color = COLOR[st]
  310. if (color) {
  311. if (isFirefoxExtension()) {
  312. chlorine.pageAction.update(color, location.href)
  313. }
  314. else if (isChromeExtension()) {
  315. chrome.extension.connect({name: "pageActionChannel"}).postMessage(color)
  316. }
  317. else if (isSafariExtension() || isJetpack()) {
  318. }
  319. else {
  320. this.icon.style.background = color
  321. }
  322. }
  323. }
  324.  
  325. AutoPager.prototype.request = function() {
  326. if (!this.requestURL || this.lastRequestURL == this.requestURL) {
  327. return
  328. }
  329. this.lastRequestURL = this.requestURL
  330. var self = this
  331. var mime = 'text/html; charset=' + document.characterSet
  332. var headers = {}
  333.  
  334. if (isSameDomain(this.requestURL)) {
  335. headers.Cookie = document.cookie
  336. }
  337. else {
  338. this.error()
  339. return
  340. }
  341. var opt = {
  342. method: 'get',
  343. url: this.requestURL,
  344. headers: headers,
  345. overrideMimeType: mime,
  346. onerror: function(res) {
  347. self.error()
  348. },
  349. onload: function(res) {
  350. if (res.finalUrl) {
  351. var url_s = res.finalUrl.split(/[\/\?]/)
  352. if (url_s[0] == location.protocol && location.host == url_s[2]) {
  353. self.requestLoad.apply(self, [res])
  354. return
  355. }
  356. }
  357. self.error()
  358. }
  359. }
  360. AutoPager.requestFilters.forEach(function(i) { i(opt) }, this)
  361. if (opt.stop) {
  362. this.requestURL = opt.url
  363. }
  364. else {
  365. this.showLoading(true)
  366. GM_xmlhttpRequest(opt)
  367. }
  368. }
  369.  
  370. AutoPager.prototype.showLoading = function(sw) {
  371. if (sw) {
  372. this.updateIcon('loading')
  373. if (this.messageFrame && settings['display_message_bar']) {
  374. this.messageFrame.style.display = 'block'
  375. }
  376. }
  377. else {
  378. this.updateIcon('enable')
  379. if (this.messageFrame) {
  380. this.messageFrame.style.display = 'none'
  381. }
  382. }
  383. }
  384.  
  385. AutoPager.prototype.requestLoad = function(res) {
  386. AutoPager.responseFilters.forEach(function(i) {
  387. i(res, this.requestURL)
  388. }, this)
  389. var htmlDoc = createHTMLDocumentByString(res.responseText)
  390. AutoPager.documentFilters.forEach(function(i) {
  391. i(htmlDoc, this.requestURL, this.info)
  392. }, this)
  393. try {
  394. var page = getElementsByXPath(this.info.pageElement, htmlDoc)
  395. var url = this.getNextURL(this.info.nextLink, htmlDoc, this.requestURL)
  396. }
  397. catch(e){
  398. log(e)
  399. this.error()
  400. return
  401. }
  402.  
  403. if (!page || page.length < 1 ) {
  404. debug('pageElement not found.' , this.info.pageElement)
  405. this.terminate()
  406. return
  407. }
  408.  
  409. if (this.loadedURLs[this.requestURL]) {
  410. debug('page is already loaded.', this.requestURL, this.info.nextLink)
  411. this.terminate()
  412. return
  413. }
  414.  
  415. this.loadedURLs[this.requestURL] = true
  416. page = this.addPage(htmlDoc, page)
  417. AutoPager.filters.forEach(function(i) {
  418. i(page)
  419. })
  420. this.requestURL = url
  421. this.showLoading(false)
  422. this.onScroll()
  423. if (!url) {
  424. debug('nextLink not found.', this.info.nextLink, htmlDoc)
  425. this.terminate()
  426. }
  427. var ev = document.createEvent('Event')
  428. ev.initEvent('GM_AutoPagerizeNextPageLoaded', true, false)
  429. document.dispatchEvent(ev)
  430. }
  431.  
  432. AutoPager.prototype.addPage = function(htmlDoc, page) {
  433. var HTML_NS = 'http://www.w3.org/1999/xhtml'
  434. var hr = document.createElementNS(HTML_NS, 'hr')
  435. var p = document.createElementNS(HTML_NS, 'p')
  436. hr.setAttribute('class', 'autopagerize_page_separator')
  437. p.setAttribute('class', 'autopagerize_page_info')
  438. var self = this
  439.  
  440. if (page[0] && /tr/i.test(page[0].tagName)) {
  441. var insertParent = this.insertPoint.parentNode
  442. var colNodes = getElementsByXPath('child::tr[1]/child::*[self::td or self::th]', insertParent)
  443.  
  444. var colums = 0
  445. for (var i = 0, l = colNodes.length; i < l; i++) {
  446. var col = colNodes[i].getAttribute('colspan')
  447. colums += parseInt(col, 10) || 1
  448. }
  449. var td = document.createElement('td')
  450. // td.appendChild(hr)
  451. td.appendChild(p)
  452. var tr = document.createElement('tr')
  453. td.setAttribute('colspan', colums)
  454. tr.appendChild(td)
  455. insertParent.insertBefore(tr, this.insertPoint)
  456. }
  457. else {
  458. this.insertPoint.parentNode.insertBefore(hr, this.insertPoint)
  459. this.insertPoint.parentNode.insertBefore(p, this.insertPoint)
  460. }
  461.  
  462. p.innerHTML = 'page: <a class="autopagerize_link" href="' +
  463. this.requestURL.replace(/&/g, '&amp;') + '">' + (++this.pageNum) + '</a>'
  464. return page.map(function(i) {
  465. var pe = document.importNode(i, true)
  466. self.insertPoint.parentNode.insertBefore(pe, self.insertPoint)
  467. var ev = document.createEvent('MutationEvent')
  468. ev.initMutationEvent('AutoPagerize_DOMNodeInserted', true, false,
  469. self.insertPoint.parentNode, null,
  470. self.requestURL, null, null)
  471. pe.dispatchEvent(ev)
  472. return pe
  473. })
  474. }
  475.  
  476. AutoPager.prototype.initIcon = function() {
  477. var div = document.createElement("div")
  478. div.setAttribute('id', 'autopagerize_icon')
  479. with (div.style) {
  480. fontSize = '12px'
  481. position = 'fixed'
  482. top = '3px'
  483. right = '3px'
  484. background = COLOR['on']
  485. color = '#fff'
  486. width = '10px'
  487. height = '10px'
  488. zIndex = '255'
  489. if (this.state != 'enable') {
  490. background = COLOR['off']
  491. }
  492. }
  493. document.body.appendChild(div)
  494. this.icon = div
  495. }
  496.  
  497. AutoPager.prototype.getNextURL = function(xpath, doc, url) {
  498. var nextLink = getFirstElementByXPath(xpath, doc)
  499. if (nextLink) {
  500. var nextValue = nextLink.getAttribute('href') ||
  501. nextLink.getAttribute('action') || nextLink.value
  502. if (nextValue.match(/^http(s)?:/)) {
  503. return nextValue
  504. }
  505. else {
  506. var base = getFirstElementByXPath('//base[@href]', doc)
  507. return resolvePath(nextValue, (base ? base.href : url))
  508. }
  509. }
  510. }
  511.  
  512. AutoPager.prototype.terminate = function() {
  513. window.removeEventListener('scroll', this.scroll, false)
  514. this.updateIcon('terminated')
  515. var self = this
  516. setTimeout(function() {
  517. if (self.icon) {
  518. self.icon.parentNode.removeChild(self.icon)
  519. }
  520. if (isSafariExtension()) {
  521. var mf = self.messageFrame
  522. mf.parentNode.removeChild(mf)
  523. }
  524. }, 1500)
  525. }
  526.  
  527. AutoPager.prototype.error = function() {
  528. this.updateIcon('error')
  529. window.removeEventListener('scroll', this.scroll, false)
  530. if (isSafariExtension() || isChromeExtension() || isJetpack()) {
  531. var mf = this.messageFrame
  532. var u = settings['extension_path'] ?
  533. settings['extension_path'] + 'error.html' :
  534. 'http://autopagerize.net/files/error.html'
  535. mf.src = u
  536. mf.style.display = 'block'
  537. setTimeout(function() {
  538. mf.parentNode.removeChild(mf)
  539. }, 3000)
  540. }
  541. }
  542.  
  543. AutoPager.documentFilters = []
  544. AutoPager.requestFilters = []
  545. AutoPager.responseFilters = []
  546. AutoPager.filters = []
  547.  
  548. var parseInfo = function(str) {
  549. var lines = str.split(/\r\n|\r|\n/)
  550. var re = /(^[^:]*?):(.*)$/
  551. var strip = function(str) {
  552. return str.replace(/^\s*/, '').replace(/\s*$/, '')
  553. }
  554. var info = {}
  555. for (var i = 0; i < lines.length; i++) {
  556. if (lines[i].match(re)) {
  557. info[RegExp.$1] = strip(RegExp.$2)
  558. }
  559. }
  560. var isValid = function(info) {
  561. var infoProp = ['url', 'nextLink', 'pageElement']
  562. for (var i = 0; i < infoProp.length; i++) {
  563. if (!info[infoProp[i]]) {
  564. return false
  565. }
  566. }
  567. return true
  568. }
  569. return isValid(info) ? info : null
  570. }
  571. var launchAutoPager = function(list) {
  572. if (list.length == 0) {
  573. return
  574. }
  575. for (var i = 0; i < list.length; i++) {
  576. try {
  577. if (ap) {
  578. return
  579. }
  580. else if (!location.href.match(list[i].url)) {
  581. }
  582. else if (!getFirstElementByXPath(list[i].nextLink)) {
  583. // FIXME microformats case detection.
  584. // limiting greater than 12 to filter microformats like SITEINFOs.
  585. if (list[i].url.length > 12 ) {
  586. debug("nextLink not found.", list[i].nextLink)
  587. }
  588. }
  589. else if (!getFirstElementByXPath(list[i].pageElement)) {
  590. if (list[i].url.length > 12 ) {
  591. debug("pageElement not found.", list[i].pageElement)
  592. }
  593. }
  594. else {
  595. ap = new AutoPager(list[i])
  596. return
  597. }
  598. }
  599. catch(e) {
  600. log(e)
  601. continue
  602. }
  603. }
  604. }
  605. var clearCache = function() {
  606. GM_setValue('cacheInfo', '')
  607. }
  608. var getCache = function() {
  609. try {
  610. return JSON.parse(GM_getValue('cacheInfo')) || {}
  611. }
  612. catch(e) {
  613. return {}
  614. }
  615. }
  616. var getCacheCallback = function(res, url) {
  617. if (res.status != 200) {
  618. return getCacheErrorCallback(url)
  619. }
  620.  
  621. var info
  622. try {
  623. info = JSON.parse(res.responseText).map(function(i) { return i.data })
  624. }
  625. catch(e) {
  626. info = []
  627. }
  628. if (info.length > 0) {
  629. info = info.filter(function(i) { return ('url' in i) })
  630. info.sort(function(a, b) { return (b.url.length - a.url.length) })
  631.  
  632. var r_keys = ['url', 'nextLink', 'insertBefore', 'pageElement']
  633. info = info.map(function(i) {
  634. var item = {}
  635. r_keys.forEach(function(key) {
  636. if (i[key]) {
  637. item[key] = i[key]
  638. }
  639. })
  640. return item
  641. })
  642.  
  643. cacheInfo[url] = {
  644. url: url,
  645. expire: new Date(new Date().getTime() + CACHE_EXPIRE),
  646. info: info
  647. }
  648. GM_setValue('cacheInfo', JSON.stringify(cacheInfo))
  649. launchAutoPager(info)
  650. }
  651. else {
  652. getCacheErrorCallback(url)
  653. }
  654. }
  655. var getCacheErrorCallback = function(url) {
  656. var expire = new Date(new Date().getTime() + CACHE_EXPIRE)
  657. if (cacheInfo[url]) {
  658. cacheInfo[url].expire = expire
  659. launchAutoPager(cacheInfo[url].info)
  660. }
  661. else {
  662. cacheInfo[url] = {
  663. url: url,
  664. expire: expire,
  665. info: []
  666. }
  667. }
  668. GM_setValue('cacheInfo', cacheInfo.toSource())
  669. }
  670.  
  671. var linkFilter = function(doc, url) {
  672. var base = getFirstElementByXPath('//base[@href]', doc)
  673. var baseUrl = base ? base.href : url
  674. var isSameBase = isSameBaseUrl(location.href, baseUrl)
  675. if (!FORCE_TARGET_WINDOW && isSameBase) {
  676. return
  677. }
  678.  
  679. var anchors = getElementsByXPath('descendant-or-self::a[@href]', doc)
  680. anchors.forEach(function(i) {
  681. var attrHref = i.getAttribute('href')
  682. if (FORCE_TARGET_WINDOW && !attrHref.match(/^#|^javascript:/) &&
  683. i.className.indexOf('autopagerize_link') < 0) {
  684. i.target = '_blank'
  685. }
  686. if (!isSameBase && !attrHref.match(/^#|^\w+:/)) {
  687. i.href = resolvePath(i.getAttribute('href'), baseUrl)
  688. }
  689. })
  690.  
  691. if (!isSameBase) {
  692. var images = getElementsByXPath('descendant-or-self::img', doc)
  693. images.forEach(function(i) {
  694. i.src = resolvePath(i.getAttribute('src'), baseUrl)
  695. })
  696. }
  697. }
  698. AutoPager.documentFilters.push(linkFilter)
  699.  
  700. fixResolvePath()
  701.  
  702. if (typeof(window.AutoPagerize) == 'undefined') {
  703. window.AutoPagerize = {}
  704. window.AutoPagerize.addFilter = function(f) {
  705. AutoPager.filters.push(f)
  706. }
  707. window.AutoPagerize.addDocumentFilter = function(f) {
  708. AutoPager.documentFilters.push(f)
  709. }
  710. window.AutoPagerize.addResponseFilter = function(f) {
  711. AutoPager.responseFilters.push(f)
  712. }
  713. window.AutoPagerize.addRequestFilter = function(f) {
  714. AutoPager.requestFilters.push(f)
  715. }
  716. window.AutoPagerize.launchAutoPager = launchAutoPager
  717.  
  718. var ev = document.createEvent('Event')
  719. ev.initEvent('GM_AutoPagerizeLoaded', true, false)
  720. document.dispatchEvent(ev)
  721. }
  722.  
  723. var settings = {}
  724. var ap = null
  725. if (isChromeExtension()) {
  726. var port = chrome.extension.connect({name: "settingsChannel"})
  727. port.postMessage()
  728. port.onMessage.addListener(function(res) {
  729. settings = res
  730. if (res['exclude_patterns'] && isExclude(res['exclude_patterns'])) {
  731. return
  732. }
  733. launchAutoPager(SITEINFO)
  734. var port_ = chrome.extension.connect({name: "siteinfoChannel"})
  735. port_.postMessage({ url: location.href })
  736. port_.onMessage.addListener(function(res) {
  737. launchAutoPager(res)
  738. chrome.extension.onConnect.addListener(function(port) {
  739. if (port.name == "toggleRequestChannel") {
  740. port.onMessage.addListener(function(msg) {
  741. if (ap) {
  742. ap.toggle()
  743. }
  744. })
  745. }
  746. })
  747. })
  748. })
  749. }
  750. else if (isSafariExtension()) {
  751. var re_exclude = /^(about:|safari-extension:)/
  752. if (!location.href.match(re_exclude)) {
  753. safari.self.addEventListener('message', function(event) {
  754. if (event.name === 'settings') {
  755. settings = event.message
  756. safari.self.tab.dispatchMessage('siteinfoChannel', {url: location.href })
  757. }
  758. else if (event.name === 'siteinfoChannel') {
  759. if (!settings['exclude_patterns'] || !isExclude(settings['exclude_patterns'])) {
  760. launchAutoPager(SITEINFO)
  761. launchAutoPager([MICROFORMAT])
  762. launchAutoPager(event.message)
  763. }
  764. }
  765. else if (event.name === 'toggleRequestChannel') {
  766. if (ap) {
  767. ap.toggle()
  768. }
  769. }
  770. else if (event.name === 'updateSettings') {
  771. settings = event.message
  772. }
  773. }, false)
  774. safari.self.tab.dispatchMessage('settings')
  775. }
  776. }
  777. else if (isJetpack()) {
  778. postMessage({ name: 'settings' })
  779. onMessage = function(message) {
  780. if (message.name == 'siteinfo') {
  781. // launchAutoPager(SITEINFO)
  782. launchAutoPager(message.data)
  783. }
  784. else if (message.name == 'settings') {
  785. settings = message.data
  786. if (settings['exclude_patterns'] && isExclude(settings['exclude_patterns'])) {
  787. // return
  788. }
  789. else {
  790. postMessage({ name: 'siteinfo', url: location.href })
  791. launchAutoPager([MICROFORMAT])
  792. }
  793. }
  794. }
  795. }
  796. else {
  797. launchAutoPager(SITEINFO)
  798. GM_registerMenuCommand('AutoPagerize - clear cache', clearCache)
  799. var cacheInfo = getCache()
  800. var xhrStates = {}
  801. SITEINFO_IMPORT_URLS.forEach(function(i) {
  802. if (!cacheInfo[i] || new Date(cacheInfo[i].expire) < new Date()) {
  803. var opt = {
  804. method: 'get',
  805. url: i,
  806. onload: function(res) {
  807. xhrStates[i] = 'loaded'
  808. getCacheCallback(res, i)
  809. },
  810. onerror: function(res){
  811. xhrStates[i] = 'error'
  812. getCacheErrorCallback(i)
  813. },
  814. }
  815. xhrStates[i] = 'start'
  816. GM_xmlhttpRequest(opt)
  817. setTimeout(function() {
  818. if (xhrStates[i] == 'start') {
  819. getCacheErrorCallback(i)
  820. }
  821. }, XHR_TIMEOUT)
  822. }
  823. else {
  824. launchAutoPager(cacheInfo[i].info)
  825. }
  826. })
  827. launchAutoPager([MICROFORMAT])
  828. }
  829.  
  830.  
  831. // new google search sucks!
  832. if (location.href.match('^http://[^.]+\.google\.(?:[^.]{2,3}\.)?[^./]{2,3}/.*(&fp=)')) {
  833. var to = location.href.replace(/&fp=.*/, '')
  834. // console.log([location.href, to])
  835. location.href = to
  836. }
  837.  
  838.  
  839.  
  840.  
  841. // utility functions.
  842. function createHTMLDocumentByString(str) {
  843. if (document.documentElement.nodeName != 'HTML') {
  844. return new DOMParser().parseFromString(str, 'application/xhtml+xml')
  845. }
  846. var html = strip_html_tag(str)
  847. var htmlDoc
  848. try {
  849. // We have to handle exceptions since Opera 9.6 throws
  850. // a NOT_SUPPORTED_ERR exception for |document.cloneNode(false)|
  851. // against the DOM 3 Core spec.
  852. htmlDoc = document.cloneNode(false)
  853. htmlDoc.appendChild(htmlDoc.importNode(document.documentElement, false))
  854. }
  855. catch(e) {
  856. htmlDoc = document.implementation.createDocument(null, 'html', null)
  857. }
  858. var fragment = createDocumentFragmentByString(html)
  859. try {
  860. fragment = htmlDoc.adoptNode(fragment)
  861. }
  862. catch(e) {
  863. fragment = htmlDoc.importNode(fragment, true)
  864. }
  865. htmlDoc.documentElement.appendChild(fragment)
  866. return htmlDoc
  867. }
  868.  
  869. function getElementsByXPath(xpath, node) {
  870. var nodesSnapshot = getXPathResult(xpath, node,
  871. XPathResult.ORDERED_NODE_SNAPSHOT_TYPE)
  872. var data = []
  873. for (var i = 0; i < nodesSnapshot.snapshotLength; i++) {
  874. data.push(nodesSnapshot.snapshotItem(i))
  875. }
  876. return data
  877. }
  878.  
  879. function getFirstElementByXPath(xpath, node) {
  880. var result = getXPathResult(xpath, node,
  881. XPathResult.FIRST_ORDERED_NODE_TYPE)
  882. return result.singleNodeValue
  883. }
  884.  
  885. function getXPathResult(xpath, node, resultType) {
  886. var node = node || document
  887. var doc = node.ownerDocument || node
  888. var resolver = doc.createNSResolver(node.documentElement || node)
  889. // Use |node.lookupNamespaceURI('')| for Opera 9.5
  890. // A workaround for bugs of Node.lookupNamespaceURI(null)
  891. // https://bugzilla.mozilla.org/show_bug.cgi?id=693615
  892. // https://bugzilla.mozilla.org/show_bug.cgi?id=694754
  893. var defaultNS = null
  894. try {
  895. // This follows the spec: http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespaceURIAlgo
  896. if (node.nodeType == node.DOCUMENT_NODE) {
  897. defaultNS = node.documentElement.lookupNamespaceURI(null)
  898. }
  899. else {
  900. defaultNS = node.lookupNamespaceURI(null)
  901. }
  902. }
  903. catch(e) {}
  904.  
  905. if (defaultNS) {
  906. const defaultPrefix = '__default__'
  907. xpath = addDefaultPrefix(xpath, defaultPrefix)
  908. var defaultResolver = resolver
  909. resolver = function (prefix) {
  910. return (prefix == defaultPrefix)
  911. ? defaultNS : defaultResolver.lookupNamespaceURI(prefix)
  912. }
  913. }
  914. return doc.evaluate(xpath, node, resolver, resultType, null)
  915. }
  916.  
  917. function addDefaultPrefix(xpath, prefix) {
  918. const tokenPattern = /([A-Za-z_\u00c0-\ufffd][\w\-.\u00b7-\ufffd]*|\*)\s*(::?|\()?|(".*?"|'.*?'|\d+(?:\.\d*)?|\.(?:\.|\d+)?|[\)\]])|(\/\/?|!=|[<>]=?|[\(\[|,=+-])|([@$])/g
  919. const TERM = 1, OPERATOR = 2, MODIFIER = 3
  920. var tokenType = OPERATOR
  921. prefix += ':'
  922. function replacer(token, identifier, suffix, term, operator, modifier) {
  923. if (suffix) {
  924. tokenType =
  925. (suffix == ':' || (suffix == '::' &&
  926. (identifier == 'attribute' || identifier == 'namespace')))
  927. ? MODIFIER : OPERATOR
  928. }
  929. else if (identifier) {
  930. if (tokenType == OPERATOR && identifier != '*') {
  931. token = prefix + token
  932. }
  933. tokenType = (tokenType == TERM) ? OPERATOR : TERM
  934. }
  935. else {
  936. tokenType = term ? TERM : operator ? OPERATOR : MODIFIER
  937. }
  938. return token
  939. }
  940. return xpath.replace(tokenPattern, replacer)
  941. }
  942.  
  943. function createDocumentFragmentByString(str) {
  944. var range = document.createRange()
  945. range.setStartAfter(document.body)
  946. return range.createContextualFragment(str)
  947. }
  948.  
  949. function log(message) {
  950. if (typeof console == 'object') {
  951. console.log(message)
  952. }
  953. else {
  954. GM_log(message)
  955. }
  956. }
  957.  
  958. function debug() {
  959. if ( typeof DEBUG != 'undefined' && DEBUG ) {
  960. if (console.log.apply) {
  961. console.log.apply(console, arguments)
  962. }
  963. else {
  964. Function.prototype.apply.apply(console.log, [console, arguments])
  965. }
  966. }
  967. }
  968.  
  969. function getElementPosition(elem) {
  970. var offsetTrail = elem
  971. var offsetLeft = 0
  972. var offsetTop = 0
  973. while (offsetTrail) {
  974. offsetLeft += offsetTrail.offsetLeft
  975. offsetTop += offsetTrail.offsetTop
  976. offsetTrail = offsetTrail.offsetParent
  977. }
  978. offsetTop = offsetTop || null
  979. offsetLeft = offsetLeft || null
  980. return {left: offsetLeft, top: offsetTop}
  981. }
  982.  
  983. function getElementBottom(elem) {
  984. var c_style = document.defaultView.getComputedStyle(elem, '')
  985. var height = 0
  986. var prop = ['height', 'borderTopWidth', 'borderBottomWidth',
  987. 'paddingTop', 'paddingBottom',
  988. 'marginTop', 'marginBottom']
  989. prop.forEach(function(i) {
  990. var h = parseInt(c_style[i])
  991. if (typeof h == 'number') {
  992. height += h
  993. }
  994. })
  995. var top = getElementPosition(elem).top
  996. return top ? (top + height) : null
  997. }
  998.  
  999. function getScrollHeight() {
  1000. return Math.max(document.documentElement.scrollHeight,
  1001. document.body.scrollHeight)
  1002. }
  1003.  
  1004. function isSameDomain(url) {
  1005. if (url.match(/^\w+:/)) {
  1006. var url_s = url.split(/[\/\?]/)
  1007. return url_s[0] == location.protocol && location.host == url_s[2]
  1008. }
  1009. else {
  1010. return true
  1011. }
  1012. }
  1013.  
  1014. function isSameBaseUrl(urlA, urlB) {
  1015. return (urlA.replace(/[^/]+$/, '') == urlB.replace(/[^/]+$/, ''))
  1016. }
  1017.  
  1018. function resolvePath(path, base) {
  1019. if (path.match(/^https?:\/\//)) {
  1020. return path
  1021. }
  1022. if (path.match(/^\?/)) {
  1023. return base.replace(/\?.+$/, '') + path;
  1024. }
  1025. if (path.match(/^[^\/]/)) {
  1026. return base.replace(/[^/]+$/, '') + path
  1027. }
  1028. else {
  1029. return base.replace(/([^/]+:\/\/[^/]+)\/.*/, '\$1') + path
  1030. }
  1031. }
  1032.  
  1033. function fixResolvePath() {
  1034. if (resolvePath('', 'http://resolve.test/') == 'http://resolve.test/') {
  1035. return
  1036. }
  1037. // A workaround for WebKit and Mozilla 1.9.2a1pre,
  1038. // which don't support XML Base in HTML.
  1039. // https://bugs.webkit.org/show_bug.cgi?id=17423
  1040. // https://bugzilla.mozilla.org/show_bug.cgi?id=505783
  1041. var XML_NS = 'http://www.w3.org/XML/1998/namespace'
  1042. var baseElement = document.createElementNS(null, 'base')
  1043. var pathElement = document.createElementNS(null, 'path')
  1044. baseElement.appendChild(pathElement)
  1045. resolvePath = function resolvePath_workaround(path, base) {
  1046. baseElement.setAttributeNS(XML_NS, 'xml:base', base)
  1047. pathElement.setAttributeNS(XML_NS, 'xml:base', path)
  1048. return pathElement.baseURI
  1049. }
  1050. }
  1051.  
  1052. function strip_html_tag(str) {
  1053. var chunks = str.split(/(<html(?:[ \t\r\n][^>]*)?>)/)
  1054. if (chunks.length >= 3) {
  1055. chunks.splice(0, 2)
  1056. }
  1057. str = chunks.join('')
  1058. chunks = str.split(/(<\/html[ \t\r\n]*>)/)
  1059. if (chunks.length >= 3) {
  1060. chunks.splice(chunks.length - 2)
  1061. }
  1062. return chunks.join('')
  1063. }
  1064.  
  1065. function getPref(key, defaultValue) {
  1066. var value = GM_getValue(key)
  1067. return (typeof value == 'undefined') ? defaultValue : value
  1068. }
  1069.  
  1070. function wildcard2regep(str) {
  1071. return '^' + str.replace(/([-()\[\]{}+?.$\^|,:#<!\\])/g, '\\$1').replace(/\x08/g, '\\x08').replace(/\*/g, '.*')
  1072. }
  1073.  
  1074. function isExclude(patterns) {
  1075. var rr = /^\/(.+)\/$/
  1076. var eps = (patterns || '').split(/[\r\n ]+/)
  1077. for (var i = 0; i < eps.length; i++) {
  1078. var reg = null
  1079. if (rr.test(eps[i])) {
  1080. reg = eps[i].match(rr)[1]
  1081. }
  1082. else {
  1083. reg = wildcard2regep(eps[i])
  1084. }
  1085. if (location.href.match(reg)) {
  1086. return true
  1087. }
  1088. }
  1089. return false
  1090. }
  1091. // obsolete
  1092. function isFirefoxExtension() {
  1093. return (typeof chlorine == 'object')
  1094. }
  1095.  
  1096. function isChromeExtension() {
  1097. return (typeof chrome == 'object') &&
  1098. (typeof chrome.extension == 'object')
  1099. }
  1100.  
  1101. function isSafariExtension() {
  1102. return (typeof safari == 'object') &&
  1103. (typeof safari.extension == 'object')
  1104. }
  1105.  
  1106. function isGreasemonkey() {
  1107. return (typeof GM_log == 'function')
  1108. }
  1109.  
  1110. function isJetpack() {
  1111. // isFirefoxExtension is obsolete
  1112. return (!isGreasemonkey() && !isSafariExtension() &&
  1113. !isChromeExtension() && !isFirefoxExtension())
  1114. }
  1115.  
  1116. function gmCompatible() {
  1117. GM_registerMenuCommand = function() {}
  1118. GM_setValue = function() {}
  1119. GM_getValue = function() {}
  1120. GM_addStyle = function() {}
  1121. uneval = function() {}
  1122. fixResolvePath = function() {}
  1123. resolvePath = function (path, base) { return path }
  1124.  
  1125. if (isChromeExtension() || isSafariExtension()) {
  1126. createHTMLDocumentByString = function(str) {
  1127. if (document.documentElement.nodeName != 'HTML') {
  1128. return new DOMParser().parseFromString(str, 'application/xhtml+xml')
  1129. }
  1130. // FIXME
  1131. var html = str.replace(/<script(?:[ \t\r\n][^>]*)?>[\S\s]*?<\/script[ \t\r\n]*>|<\/?(?:i?frame|html|script|object)(?:[ \t\r\n][^<>]*)?>/gi, ' ')
  1132. var htmlDoc = document.implementation.createHTMLDocument ?
  1133. document.implementation.createHTMLDocument('apfc') :
  1134. document.implementation.createDocument(null, 'html', null)
  1135. var range = document.createRange()
  1136. range.selectNodeContents(document.documentElement)
  1137. htmlDoc.documentElement.appendChild(range.createContextualFragment(html))
  1138. return htmlDoc
  1139. }
  1140. }
  1141. return true
  1142. }
Advertisement
Add Comment
Please, Sign In to add comment