- // ==UserScript==
- // @name AutoPagerize
- // @namespace http://swdyh.yu.to/
- // @description loading next page and inserting into current page.
- // @include http://*
- // @include https://*
- // @exclude https://mail.google.com/*
- // @exclude http://b.hatena.ne.jp/*
- // @exclude http://www.facebook.com/plugins/like.php*
- // @exclude http://api.tweetmeme.com/button.js*
- // @version 0.0.66
- // @icon http://autopagerize.net/img/icons/icon_032.png
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_addStyle
- // @grant GM_log
- // @grant GM_xmlhttpRequest
- // @grant GM_registerMenuCommand
- // ==/UserScript==
- //
- // auther: swdyh http://d.hatena.ne.jp/swdyh/
- // version: 0.0.66 2012-08-31T18:23:34+09:00
- //
- // this script based on
- // GoogleAutoPager(http://la.ma.la/blog/diary_200506231749.htm) and
- // estseek autopager(http://la.ma.la/blog/diary_200601100209.htm).
- // thanks to ma.la.
- //
- // Released under the GPL license
- // http://www.gnu.org/copyleft/gpl.html
- //
-
- if (isGreasemonkey()) {
- var ep = getPref('exclude_patterns')
- if (ep && isExclude(ep)) {
- // FIXME
- // return
- }
- }
- else {
- gmCompatible()
- }
-
- var URL = 'http://autopagerize.net/'
- var VERSION = '0.0.66'
- var DEBUG = false
- var AUTO_START = true
- var CACHE_EXPIRE = 24 * 60 * 60 * 1000
- var BASE_REMAIN_HEIGHT = 400
- var FORCE_TARGET_WINDOW = getPref('force_target_window', true)
- var XHR_TIMEOUT = 30 * 1000
- var SITEINFO_IMPORT_URLS = [
- 'http://wedata.net/databases/AutoPagerize/items.json',
- ]
- var COLOR = {
- on: '#0f0',
- off: '#ccc',
- loading: '#0ff',
- terminated: '#00f',
- error: '#f0f'
- }
- var SITEINFO = [
- /* sample
- {
- url: 'http://(.*).google.+/(search).+',
- nextLink: 'id("navbar")//td[last()]/a',
- pageElement: '//div[@id="res"]/div',
- exampleUrl: 'http://www.google.com/search?q=nsIObserver',
- },
- */
- /* template
- {
- url: '',
- nextLink: '',
- pageElement: '',
- exampleUrl: '',
- },
- */
- ]
- var MICROFORMAT = {
- url: '.*',
- nextLink: '//a[@rel="next"] | //link[@rel="next"]',
- insertBefore: '//*[contains(@class, "autopagerize_insert_before")]',
- pageElement: '//*[contains(@class, "autopagerize_page_element")]',
- }
-
- var AutoPager = function(info) {
- this.pageNum = 1
- this.info = info
- this.state = AUTO_START ? 'enable' : 'disable'
- var self = this
- var url = this.getNextURL(info.nextLink, document, location.href)
-
- if ( !url ) {
- debug("getNextURL returns null.", info.nextLink)
- return
- }
- if (info.insertBefore) {
- this.insertPoint = getFirstElementByXPath(info.insertBefore)
- }
-
- if (!this.insertPoint) {
- var lastPageElement = getElementsByXPath(info.pageElement).pop()
- if (lastPageElement) {
- this.insertPoint = lastPageElement.nextSibling ||
- lastPageElement.parentNode.appendChild(document.createTextNode(' '))
- }
- }
-
- if (!this.insertPoint) {
- debug("insertPoint not found.", lastPageElement, info.pageElement)
- return
- }
-
- this.requestURL = url
- this.loadedURLs = {}
- this.loadedURLs[location.href] = true
- var toggle = function() {self.stateToggle()}
- this.toggle = toggle
- GM_registerMenuCommand('AutoPagerize - on/off', toggle)
- this.scroll= function() { self.onScroll() }
- window.addEventListener("scroll", this.scroll, false)
-
- if (isFirefoxExtension()) {
- var div = document.createElement("div")
- div.setAttribute('id', 'autopagerize_icon')
- div.style.display = 'none'
- document.body.appendChild(div)
- this.icon = div
- }
- else if (isChromeExtension() || isSafariExtension() || isJetpack()) {
- var frame = document.createElement('iframe')
- frame.style.display = 'none'
- frame.style.position = 'fixed'
- frame.style.bottom = '0px'
- frame.style.left = '0px'
- frame.style.height = '25px'
- frame.style.border = '0px'
- frame.style.opacity = '0.8'
- frame.style.zIndex = '1000'
- frame.width = '100%'
- frame.scrolling = 'no'
- this.messageFrame = frame
- var u = settings['extension_path'] ?
- settings['extension_path'] + 'loading.html' :
- 'http://autopagerize.net/files/loading.html'
- this.messageFrame.src = u
- document.body.appendChild(frame)
- if (isSafariExtension()) {
- safari.self.tab.dispatchMessage('launched', {url: location.href })
- }
- else if (isChromeExtension()) {
- chrome.extension.connect({name: "launched"}).postMessage()
- }
- if (isJetpack()) {
- postMessage({name: 'launched', data: location.href })
- }
- }
- else {
- this.initIcon()
- this.initHelp()
- GM_addStyle('@media print{#autopagerize_icon, #autopagerize_help {display: none !important;}}')
- GM_addStyle('hr.autopagerize_page_separator {clear: both;}')
- this.icon.addEventListener("mouseover", function() {
- self.viewHelp()
- }, true)
- }
-
- var scrollHeight = getScrollHeight()
- var bottom = getElementPosition(this.insertPoint).top ||
- this.getPageElementsBottom() ||
- (Math.round(scrollHeight * 0.8))
- this.remainHeight = scrollHeight - bottom + BASE_REMAIN_HEIGHT
- this.onScroll()
-
- var that = this
- document.addEventListener('AutoPagerizeToggleRequest', function() {
- that.toggle()
- }, false)
- document.addEventListener('AutoPagerizeUpdateIconRequest', function() {
- that.updateIcon()
- }, false)
- that.updateIcon()
- }
-
- AutoPager.prototype.getPageElementsBottom = function() {
- try {
- var elem = getElementsByXPath(this.info.pageElement).pop()
- return getElementBottom(elem)
- }
- catch(e) {}
- }
-
- AutoPager.prototype.initHelp = function() {
- var helpDiv = document.createElement('div')
- helpDiv.setAttribute('id', 'autopagerize_help')
- helpDiv.setAttribute('style', 'padding:5px;position:fixed;' +
- 'top:-200px;right:3px;font-size:10px;' +
- 'background:#fff;color:#000;border:1px solid #ccc;' +
- 'z-index:256;text-align:left;font-weight:normal;' +
- 'line-height:120%;font-family:verdana;')
-
- var toggleDiv = document.createElement('div')
- toggleDiv.setAttribute('style', 'margin:0 0 0 50px;')
- var a = document.createElement('a')
- a.setAttribute('class', 'autopagerize_link')
- a.innerHTML = 'on/off'
- a.href = 'javascript:void(0)'
- var self = this
- var toggle = function() {
- self.stateToggle()
- helpDiv.style.top = '-200px'
- }
- a.addEventListener('click', toggle, false)
- toggleDiv.appendChild(a)
-
- var s = '<div style="width:100px; float:left;">'
- for (var i in COLOR) {
- s += '<div style="float:left;width:1em;height:1em;' +
- 'margin:0 3px;background-color:' + COLOR[i] + ';' +
- '"></div><div style="margin:0 3px">' + i + '</div>'
- }
- s += '</div>'
- var colorDiv = document.createElement('div')
- colorDiv.innerHTML = s
- helpDiv.appendChild(colorDiv)
- helpDiv.appendChild(toggleDiv)
-
- var versionDiv = document.createElement('div')
- versionDiv.setAttribute('style', 'clear:both;')
- versionDiv.innerHTML = '<a href="' + URL +
- '">AutoPagerize</a> ver ' + VERSION
- helpDiv.appendChild(versionDiv)
- document.body.appendChild(helpDiv)
-
- var proc = function(e) {
- var c_style = document.defaultView.getComputedStyle(helpDiv, '')
- var s = ['top', 'left', 'height', 'width'].map(function(i) {
- return parseInt(c_style.getPropertyValue(i)) })
- if (e.clientX < s[1] || e.clientX > (s[1] + s[3] + 11) ||
- e.clientY < s[0] || e.clientY > (s[0] + s[2] + 11)) {
- helpDiv.style.top = '-200px'
- }
- }
- helpDiv.addEventListener('mouseout', proc, false)
- this.helpLayer = helpDiv
- GM_addStyle('#autopagerize_help a { color: #0f0; text-decoration: underline;}')
- }
-
- AutoPager.prototype.viewHelp = function() {
- this.helpLayer.style.top = '3px'
- }
-
- AutoPager.prototype.onScroll = function() {
- var scrollHeight = Math.max(document.documentElement.scrollHeight,
- document.body.scrollHeight)
- var remain = scrollHeight - window.innerHeight - window.scrollY
- if (this.state == 'enable' && remain < this.remainHeight) {
- this.request()
- }
- }
-
- AutoPager.prototype.stateToggle = function() {
- if (this.state == 'enable') {
- this.disable()
- }
- else {
- this.enable()
- }
- }
-
- AutoPager.prototype.enable = function() {
- this.state = 'enable'
- this.updateIcon()
- }
-
- AutoPager.prototype.disable = function() {
- this.state = 'disable'
- this.updateIcon()
- }
-
- AutoPager.prototype.updateIcon = function(state) {
- var st = state || this.state
- var rename = {'enable': 'on', 'disable': 'off' }
- if (rename[st]) {
- st = rename[st]
- }
- var color = COLOR[st]
- if (color) {
- if (isFirefoxExtension()) {
- chlorine.pageAction.update(color, location.href)
- }
- else if (isChromeExtension()) {
- chrome.extension.connect({name: "pageActionChannel"}).postMessage(color)
- }
- else if (isSafariExtension() || isJetpack()) {
- }
- else {
- this.icon.style.background = color
- }
- }
- }
-
- AutoPager.prototype.request = function() {
- if (!this.requestURL || this.lastRequestURL == this.requestURL) {
- return
- }
- this.lastRequestURL = this.requestURL
- var self = this
- var mime = 'text/html; charset=' + document.characterSet
- var headers = {}
-
- if (isSameDomain(this.requestURL)) {
- headers.Cookie = document.cookie
- }
- else {
- this.error()
- return
- }
- var opt = {
- method: 'get',
- url: this.requestURL,
- headers: headers,
- overrideMimeType: mime,
- onerror: function(res) {
- self.error()
- },
- onload: function(res) {
- if (res.finalUrl) {
- var url_s = res.finalUrl.split(/[\/\?]/)
- if (url_s[0] == location.protocol && location.host == url_s[2]) {
- self.requestLoad.apply(self, [res])
- return
- }
- }
- self.error()
- }
- }
- AutoPager.requestFilters.forEach(function(i) { i(opt) }, this)
- if (opt.stop) {
- this.requestURL = opt.url
- }
- else {
- this.showLoading(true)
- GM_xmlhttpRequest(opt)
- }
- }
-
- AutoPager.prototype.showLoading = function(sw) {
- if (sw) {
- this.updateIcon('loading')
- if (this.messageFrame && settings['display_message_bar']) {
- this.messageFrame.style.display = 'block'
- }
- }
- else {
- this.updateIcon('enable')
- if (this.messageFrame) {
- this.messageFrame.style.display = 'none'
- }
- }
- }
-
- AutoPager.prototype.requestLoad = function(res) {
- AutoPager.responseFilters.forEach(function(i) {
- i(res, this.requestURL)
- }, this)
- var htmlDoc = createHTMLDocumentByString(res.responseText)
- AutoPager.documentFilters.forEach(function(i) {
- i(htmlDoc, this.requestURL, this.info)
- }, this)
- try {
- var page = getElementsByXPath(this.info.pageElement, htmlDoc)
- var url = this.getNextURL(this.info.nextLink, htmlDoc, this.requestURL)
- }
- catch(e){
- log(e)
- this.error()
- return
- }
-
- if (!page || page.length < 1 ) {
- debug('pageElement not found.' , this.info.pageElement)
- this.terminate()
- return
- }
-
- if (this.loadedURLs[this.requestURL]) {
- debug('page is already loaded.', this.requestURL, this.info.nextLink)
- this.terminate()
- return
- }
-
- this.loadedURLs[this.requestURL] = true
- page = this.addPage(htmlDoc, page)
- AutoPager.filters.forEach(function(i) {
- i(page)
- })
- this.requestURL = url
- this.showLoading(false)
- this.onScroll()
- if (!url) {
- debug('nextLink not found.', this.info.nextLink, htmlDoc)
- this.terminate()
- }
- var ev = document.createEvent('Event')
- ev.initEvent('GM_AutoPagerizeNextPageLoaded', true, false)
- document.dispatchEvent(ev)
- }
-
- AutoPager.prototype.addPage = function(htmlDoc, page) {
- var HTML_NS = 'http://www.w3.org/1999/xhtml'
- var hr = document.createElementNS(HTML_NS, 'hr')
- var p = document.createElementNS(HTML_NS, 'p')
- hr.setAttribute('class', 'autopagerize_page_separator')
- p.setAttribute('class', 'autopagerize_page_info')
- var self = this
-
- if (page[0] && /tr/i.test(page[0].tagName)) {
- var insertParent = this.insertPoint.parentNode
- var colNodes = getElementsByXPath('child::tr[1]/child::*[self::td or self::th]', insertParent)
-
- var colums = 0
- for (var i = 0, l = colNodes.length; i < l; i++) {
- var col = colNodes[i].getAttribute('colspan')
- colums += parseInt(col, 10) || 1
- }
- var td = document.createElement('td')
- // td.appendChild(hr)
- td.appendChild(p)
- var tr = document.createElement('tr')
- td.setAttribute('colspan', colums)
- tr.appendChild(td)
- insertParent.insertBefore(tr, this.insertPoint)
- }
- else {
- this.insertPoint.parentNode.insertBefore(hr, this.insertPoint)
- this.insertPoint.parentNode.insertBefore(p, this.insertPoint)
- }
-
- p.innerHTML = 'page: <a class="autopagerize_link" href="' +
- this.requestURL.replace(/&/g, '&') + '">' + (++this.pageNum) + '</a>'
- return page.map(function(i) {
- var pe = document.importNode(i, true)
- self.insertPoint.parentNode.insertBefore(pe, self.insertPoint)
- var ev = document.createEvent('MutationEvent')
- ev.initMutationEvent('AutoPagerize_DOMNodeInserted', true, false,
- self.insertPoint.parentNode, null,
- self.requestURL, null, null)
- pe.dispatchEvent(ev)
- return pe
- })
- }
-
- AutoPager.prototype.initIcon = function() {
- var div = document.createElement("div")
- div.setAttribute('id', 'autopagerize_icon')
- with (div.style) {
- fontSize = '12px'
- position = 'fixed'
- top = '3px'
- right = '3px'
- background = COLOR['on']
- color = '#fff'
- width = '10px'
- height = '10px'
- zIndex = '255'
- if (this.state != 'enable') {
- background = COLOR['off']
- }
- }
- document.body.appendChild(div)
- this.icon = div
- }
-
- AutoPager.prototype.getNextURL = function(xpath, doc, url) {
- var nextLink = getFirstElementByXPath(xpath, doc)
- if (nextLink) {
- var nextValue = nextLink.getAttribute('href') ||
- nextLink.getAttribute('action') || nextLink.value
- if (nextValue.match(/^http(s)?:/)) {
- return nextValue
- }
- else {
- var base = getFirstElementByXPath('//base[@href]', doc)
- return resolvePath(nextValue, (base ? base.href : url))
- }
- }
- }
-
- AutoPager.prototype.terminate = function() {
- window.removeEventListener('scroll', this.scroll, false)
- this.updateIcon('terminated')
- var self = this
- setTimeout(function() {
- if (self.icon) {
- self.icon.parentNode.removeChild(self.icon)
- }
- if (isSafariExtension()) {
- var mf = self.messageFrame
- mf.parentNode.removeChild(mf)
- }
- }, 1500)
- }
-
- AutoPager.prototype.error = function() {
- this.updateIcon('error')
- window.removeEventListener('scroll', this.scroll, false)
- if (isSafariExtension() || isChromeExtension() || isJetpack()) {
- var mf = this.messageFrame
- var u = settings['extension_path'] ?
- settings['extension_path'] + 'error.html' :
- 'http://autopagerize.net/files/error.html'
- mf.src = u
- mf.style.display = 'block'
- setTimeout(function() {
- mf.parentNode.removeChild(mf)
- }, 3000)
- }
- }
-
- AutoPager.documentFilters = []
- AutoPager.requestFilters = []
- AutoPager.responseFilters = []
- AutoPager.filters = []
-
- var parseInfo = function(str) {
- var lines = str.split(/\r\n|\r|\n/)
- var re = /(^[^:]*?):(.*)$/
- var strip = function(str) {
- return str.replace(/^\s*/, '').replace(/\s*$/, '')
- }
- var info = {}
- for (var i = 0; i < lines.length; i++) {
- if (lines[i].match(re)) {
- info[RegExp.$1] = strip(RegExp.$2)
- }
- }
- var isValid = function(info) {
- var infoProp = ['url', 'nextLink', 'pageElement']
- for (var i = 0; i < infoProp.length; i++) {
- if (!info[infoProp[i]]) {
- return false
- }
- }
- return true
- }
- return isValid(info) ? info : null
- }
- var launchAutoPager = function(list) {
- if (list.length == 0) {
- return
- }
- for (var i = 0; i < list.length; i++) {
- try {
- if (ap) {
- return
- }
- else if (!location.href.match(list[i].url)) {
- }
- else if (!getFirstElementByXPath(list[i].nextLink)) {
- // FIXME microformats case detection.
- // limiting greater than 12 to filter microformats like SITEINFOs.
- if (list[i].url.length > 12 ) {
- debug("nextLink not found.", list[i].nextLink)
- }
- }
- else if (!getFirstElementByXPath(list[i].pageElement)) {
- if (list[i].url.length > 12 ) {
- debug("pageElement not found.", list[i].pageElement)
- }
- }
- else {
- ap = new AutoPager(list[i])
- return
- }
- }
- catch(e) {
- log(e)
- continue
- }
- }
- }
- var clearCache = function() {
- GM_setValue('cacheInfo', '')
- }
- var getCache = function() {
- try {
- return JSON.parse(GM_getValue('cacheInfo')) || {}
- }
- catch(e) {
- return {}
- }
- }
- var getCacheCallback = function(res, url) {
- if (res.status != 200) {
- return getCacheErrorCallback(url)
- }
-
- var info
- try {
- info = JSON.parse(res.responseText).map(function(i) { return i.data })
- }
- catch(e) {
- info = []
- }
- if (info.length > 0) {
- info = info.filter(function(i) { return ('url' in i) })
- info.sort(function(a, b) { return (b.url.length - a.url.length) })
-
- var r_keys = ['url', 'nextLink', 'insertBefore', 'pageElement']
- info = info.map(function(i) {
- var item = {}
- r_keys.forEach(function(key) {
- if (i[key]) {
- item[key] = i[key]
- }
- })
- return item
- })
-
- cacheInfo[url] = {
- url: url,
- expire: new Date(new Date().getTime() + CACHE_EXPIRE),
- info: info
- }
- GM_setValue('cacheInfo', JSON.stringify(cacheInfo))
- launchAutoPager(info)
- }
- else {
- getCacheErrorCallback(url)
- }
- }
- var getCacheErrorCallback = function(url) {
- var expire = new Date(new Date().getTime() + CACHE_EXPIRE)
- if (cacheInfo[url]) {
- cacheInfo[url].expire = expire
- launchAutoPager(cacheInfo[url].info)
- }
- else {
- cacheInfo[url] = {
- url: url,
- expire: expire,
- info: []
- }
- }
- GM_setValue('cacheInfo', cacheInfo.toSource())
- }
-
- var linkFilter = function(doc, url) {
- var base = getFirstElementByXPath('//base[@href]', doc)
- var baseUrl = base ? base.href : url
- var isSameBase = isSameBaseUrl(location.href, baseUrl)
- if (!FORCE_TARGET_WINDOW && isSameBase) {
- return
- }
-
- var anchors = getElementsByXPath('descendant-or-self::a[@href]', doc)
- anchors.forEach(function(i) {
- var attrHref = i.getAttribute('href')
- if (FORCE_TARGET_WINDOW && !attrHref.match(/^#|^javascript:/) &&
- i.className.indexOf('autopagerize_link') < 0) {
- i.target = '_blank'
- }
- if (!isSameBase && !attrHref.match(/^#|^\w+:/)) {
- i.href = resolvePath(i.getAttribute('href'), baseUrl)
- }
- })
-
- if (!isSameBase) {
- var images = getElementsByXPath('descendant-or-self::img', doc)
- images.forEach(function(i) {
- i.src = resolvePath(i.getAttribute('src'), baseUrl)
- })
- }
- }
- AutoPager.documentFilters.push(linkFilter)
-
- fixResolvePath()
-
- if (typeof(window.AutoPagerize) == 'undefined') {
- window.AutoPagerize = {}
- window.AutoPagerize.addFilter = function(f) {
- AutoPager.filters.push(f)
- }
- window.AutoPagerize.addDocumentFilter = function(f) {
- AutoPager.documentFilters.push(f)
- }
- window.AutoPagerize.addResponseFilter = function(f) {
- AutoPager.responseFilters.push(f)
- }
- window.AutoPagerize.addRequestFilter = function(f) {
- AutoPager.requestFilters.push(f)
- }
- window.AutoPagerize.launchAutoPager = launchAutoPager
-
- var ev = document.createEvent('Event')
- ev.initEvent('GM_AutoPagerizeLoaded', true, false)
- document.dispatchEvent(ev)
- }
-
- var settings = {}
- var ap = null
- if (isChromeExtension()) {
- var port = chrome.extension.connect({name: "settingsChannel"})
- port.postMessage()
- port.onMessage.addListener(function(res) {
- settings = res
- if (res['exclude_patterns'] && isExclude(res['exclude_patterns'])) {
- return
- }
- launchAutoPager(SITEINFO)
- var port_ = chrome.extension.connect({name: "siteinfoChannel"})
- port_.postMessage({ url: location.href })
- port_.onMessage.addListener(function(res) {
- launchAutoPager(res)
- chrome.extension.onConnect.addListener(function(port) {
- if (port.name == "toggleRequestChannel") {
- port.onMessage.addListener(function(msg) {
- if (ap) {
- ap.toggle()
- }
- })
- }
- })
- })
- })
- }
- else if (isSafariExtension()) {
- var re_exclude = /^(about:|safari-extension:)/
- if (!location.href.match(re_exclude)) {
- safari.self.addEventListener('message', function(event) {
- if (event.name === 'settings') {
- settings = event.message
- safari.self.tab.dispatchMessage('siteinfoChannel', {url: location.href })
- }
- else if (event.name === 'siteinfoChannel') {
- if (!settings['exclude_patterns'] || !isExclude(settings['exclude_patterns'])) {
- launchAutoPager(SITEINFO)
- launchAutoPager([MICROFORMAT])
- launchAutoPager(event.message)
- }
- }
- else if (event.name === 'toggleRequestChannel') {
- if (ap) {
- ap.toggle()
- }
- }
- else if (event.name === 'updateSettings') {
- settings = event.message
- }
- }, false)
- safari.self.tab.dispatchMessage('settings')
- }
- }
- else if (isJetpack()) {
- postMessage({ name: 'settings' })
- onMessage = function(message) {
- if (message.name == 'siteinfo') {
- // launchAutoPager(SITEINFO)
- launchAutoPager(message.data)
- }
- else if (message.name == 'settings') {
- settings = message.data
- if (settings['exclude_patterns'] && isExclude(settings['exclude_patterns'])) {
- // return
- }
- else {
- postMessage({ name: 'siteinfo', url: location.href })
- launchAutoPager([MICROFORMAT])
- }
- }
- }
- }
- else {
- launchAutoPager(SITEINFO)
- GM_registerMenuCommand('AutoPagerize - clear cache', clearCache)
- var cacheInfo = getCache()
- var xhrStates = {}
- SITEINFO_IMPORT_URLS.forEach(function(i) {
- if (!cacheInfo[i] || new Date(cacheInfo[i].expire) < new Date()) {
- var opt = {
- method: 'get',
- url: i,
- onload: function(res) {
- xhrStates[i] = 'loaded'
- getCacheCallback(res, i)
- },
- onerror: function(res){
- xhrStates[i] = 'error'
- getCacheErrorCallback(i)
- },
- }
- xhrStates[i] = 'start'
- GM_xmlhttpRequest(opt)
- setTimeout(function() {
- if (xhrStates[i] == 'start') {
- getCacheErrorCallback(i)
- }
- }, XHR_TIMEOUT)
- }
- else {
- launchAutoPager(cacheInfo[i].info)
- }
- })
- launchAutoPager([MICROFORMAT])
- }
-
-
- // new google search sucks!
- if (location.href.match('^http://[^.]+\.google\.(?:[^.]{2,3}\.)?[^./]{2,3}/.*(&fp=)')) {
- var to = location.href.replace(/&fp=.*/, '')
- // console.log([location.href, to])
- location.href = to
- }
-
-
-
-
- // utility functions.
- function createHTMLDocumentByString(str) {
- if (document.documentElement.nodeName != 'HTML') {
- return new DOMParser().parseFromString(str, 'application/xhtml+xml')
- }
- var html = strip_html_tag(str)
- var htmlDoc
- try {
- // We have to handle exceptions since Opera 9.6 throws
- // a NOT_SUPPORTED_ERR exception for |document.cloneNode(false)|
- // against the DOM 3 Core spec.
- htmlDoc = document.cloneNode(false)
- htmlDoc.appendChild(htmlDoc.importNode(document.documentElement, false))
- }
- catch(e) {
- htmlDoc = document.implementation.createDocument(null, 'html', null)
- }
- var fragment = createDocumentFragmentByString(html)
- try {
- fragment = htmlDoc.adoptNode(fragment)
- }
- catch(e) {
- fragment = htmlDoc.importNode(fragment, true)
- }
- htmlDoc.documentElement.appendChild(fragment)
- return htmlDoc
- }
-
- function getElementsByXPath(xpath, node) {
- var nodesSnapshot = getXPathResult(xpath, node,
- XPathResult.ORDERED_NODE_SNAPSHOT_TYPE)
- var data = []
- for (var i = 0; i < nodesSnapshot.snapshotLength; i++) {
- data.push(nodesSnapshot.snapshotItem(i))
- }
- return data
- }
-
- function getFirstElementByXPath(xpath, node) {
- var result = getXPathResult(xpath, node,
- XPathResult.FIRST_ORDERED_NODE_TYPE)
- return result.singleNodeValue
- }
-
- function getXPathResult(xpath, node, resultType) {
- var node = node || document
- var doc = node.ownerDocument || node
- var resolver = doc.createNSResolver(node.documentElement || node)
- // Use |node.lookupNamespaceURI('')| for Opera 9.5
- // A workaround for bugs of Node.lookupNamespaceURI(null)
- // https://bugzilla.mozilla.org/show_bug.cgi?id=693615
- // https://bugzilla.mozilla.org/show_bug.cgi?id=694754
- var defaultNS = null
- try {
- // This follows the spec: http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespaceURIAlgo
- if (node.nodeType == node.DOCUMENT_NODE) {
- defaultNS = node.documentElement.lookupNamespaceURI(null)
- }
- else {
- defaultNS = node.lookupNamespaceURI(null)
- }
- }
- catch(e) {}
-
- if (defaultNS) {
- const defaultPrefix = '__default__'
- xpath = addDefaultPrefix(xpath, defaultPrefix)
- var defaultResolver = resolver
- resolver = function (prefix) {
- return (prefix == defaultPrefix)
- ? defaultNS : defaultResolver.lookupNamespaceURI(prefix)
- }
- }
- return doc.evaluate(xpath, node, resolver, resultType, null)
- }
-
- function addDefaultPrefix(xpath, prefix) {
- const tokenPattern = /([A-Za-z_\u00c0-\ufffd][\w\-.\u00b7-\ufffd]*|\*)\s*(::?|\()?|(".*?"|'.*?'|\d+(?:\.\d*)?|\.(?:\.|\d+)?|[\)\]])|(\/\/?|!=|[<>]=?|[\(\[|,=+-])|([@$])/g
- const TERM = 1, OPERATOR = 2, MODIFIER = 3
- var tokenType = OPERATOR
- prefix += ':'
- function replacer(token, identifier, suffix, term, operator, modifier) {
- if (suffix) {
- tokenType =
- (suffix == ':' || (suffix == '::' &&
- (identifier == 'attribute' || identifier == 'namespace')))
- ? MODIFIER : OPERATOR
- }
- else if (identifier) {
- if (tokenType == OPERATOR && identifier != '*') {
- token = prefix + token
- }
- tokenType = (tokenType == TERM) ? OPERATOR : TERM
- }
- else {
- tokenType = term ? TERM : operator ? OPERATOR : MODIFIER
- }
- return token
- }
- return xpath.replace(tokenPattern, replacer)
- }
-
- function createDocumentFragmentByString(str) {
- var range = document.createRange()
- range.setStartAfter(document.body)
- return range.createContextualFragment(str)
- }
-
- function log(message) {
- if (typeof console == 'object') {
- console.log(message)
- }
- else {
- GM_log(message)
- }
- }
-
- function debug() {
- if ( typeof DEBUG != 'undefined' && DEBUG ) {
- if (console.log.apply) {
- console.log.apply(console, arguments)
- }
- else {
- Function.prototype.apply.apply(console.log, [console, arguments])
- }
- }
- }
-
- function getElementPosition(elem) {
- var offsetTrail = elem
- var offsetLeft = 0
- var offsetTop = 0
- while (offsetTrail) {
- offsetLeft += offsetTrail.offsetLeft
- offsetTop += offsetTrail.offsetTop
- offsetTrail = offsetTrail.offsetParent
- }
- offsetTop = offsetTop || null
- offsetLeft = offsetLeft || null
- return {left: offsetLeft, top: offsetTop}
- }
-
- function getElementBottom(elem) {
- var c_style = document.defaultView.getComputedStyle(elem, '')
- var height = 0
- var prop = ['height', 'borderTopWidth', 'borderBottomWidth',
- 'paddingTop', 'paddingBottom',
- 'marginTop', 'marginBottom']
- prop.forEach(function(i) {
- var h = parseInt(c_style[i])
- if (typeof h == 'number') {
- height += h
- }
- })
- var top = getElementPosition(elem).top
- return top ? (top + height) : null
- }
-
- function getScrollHeight() {
- return Math.max(document.documentElement.scrollHeight,
- document.body.scrollHeight)
- }
-
- function isSameDomain(url) {
- if (url.match(/^\w+:/)) {
- var url_s = url.split(/[\/\?]/)
- return url_s[0] == location.protocol && location.host == url_s[2]
- }
- else {
- return true
- }
- }
-
- function isSameBaseUrl(urlA, urlB) {
- return (urlA.replace(/[^/]+$/, '') == urlB.replace(/[^/]+$/, ''))
- }
-
- function resolvePath(path, base) {
- if (path.match(/^https?:\/\//)) {
- return path
- }
- if (path.match(/^\?/)) {
- return base.replace(/\?.+$/, '') + path;
- }
- if (path.match(/^[^\/]/)) {
- return base.replace(/[^/]+$/, '') + path
- }
- else {
- return base.replace(/([^/]+:\/\/[^/]+)\/.*/, '\$1') + path
- }
- }
-
- function fixResolvePath() {
- if (resolvePath('', 'http://resolve.test/') == 'http://resolve.test/') {
- return
- }
- // A workaround for WebKit and Mozilla 1.9.2a1pre,
- // which don't support XML Base in HTML.
- // https://bugs.webkit.org/show_bug.cgi?id=17423
- // https://bugzilla.mozilla.org/show_bug.cgi?id=505783
- var XML_NS = 'http://www.w3.org/XML/1998/namespace'
- var baseElement = document.createElementNS(null, 'base')
- var pathElement = document.createElementNS(null, 'path')
- baseElement.appendChild(pathElement)
- resolvePath = function resolvePath_workaround(path, base) {
- baseElement.setAttributeNS(XML_NS, 'xml:base', base)
- pathElement.setAttributeNS(XML_NS, 'xml:base', path)
- return pathElement.baseURI
- }
- }
-
- function strip_html_tag(str) {
- var chunks = str.split(/(<html(?:[ \t\r\n][^>]*)?>)/)
- if (chunks.length >= 3) {
- chunks.splice(0, 2)
- }
- str = chunks.join('')
- chunks = str.split(/(<\/html[ \t\r\n]*>)/)
- if (chunks.length >= 3) {
- chunks.splice(chunks.length - 2)
- }
- return chunks.join('')
- }
-
- function getPref(key, defaultValue) {
- var value = GM_getValue(key)
- return (typeof value == 'undefined') ? defaultValue : value
- }
-
- function wildcard2regep(str) {
- return '^' + str.replace(/([-()\[\]{}+?.$\^|,:#<!\\])/g, '\\$1').replace(/\x08/g, '\\x08').replace(/\*/g, '.*')
- }
-
- function isExclude(patterns) {
- var rr = /^\/(.+)\/$/
- var eps = (patterns || '').split(/[\r\n ]+/)
- for (var i = 0; i < eps.length; i++) {
- var reg = null
- if (rr.test(eps[i])) {
- reg = eps[i].match(rr)[1]
- }
- else {
- reg = wildcard2regep(eps[i])
- }
- if (location.href.match(reg)) {
- return true
- }
- }
- return false
- }
- // obsolete
- function isFirefoxExtension() {
- return (typeof chlorine == 'object')
- }
-
- function isChromeExtension() {
- return (typeof chrome == 'object') &&
- (typeof chrome.extension == 'object')
- }
-
- function isSafariExtension() {
- return (typeof safari == 'object') &&
- (typeof safari.extension == 'object')
- }
-
- function isGreasemonkey() {
- return (typeof GM_log == 'function')
- }
-
- function isJetpack() {
- // isFirefoxExtension is obsolete
- return (!isGreasemonkey() && !isSafariExtension() &&
- !isChromeExtension() && !isFirefoxExtension())
- }
-
- function gmCompatible() {
- GM_registerMenuCommand = function() {}
- GM_setValue = function() {}
- GM_getValue = function() {}
- GM_addStyle = function() {}
- uneval = function() {}
- fixResolvePath = function() {}
- resolvePath = function (path, base) { return path }
-
- if (isChromeExtension() || isSafariExtension()) {
- createHTMLDocumentByString = function(str) {
- if (document.documentElement.nodeName != 'HTML') {
- return new DOMParser().parseFromString(str, 'application/xhtml+xml')
- }
- // FIXME
- var html = str.replace(/<script(?:[ \t\r\n][^>]*)?>[\S\s]*?<\/script[ \t\r\n]*>|<\/?(?:i?frame|html|script|object)(?:[ \t\r\n][^<>]*)?>/gi, ' ')
- var htmlDoc = document.implementation.createHTMLDocument ?
- document.implementation.createHTMLDocument('apfc') :
- document.implementation.createDocument(null, 'html', null)
- var range = document.createRange()
- range.selectNodeContents(document.documentElement)
- htmlDoc.documentElement.appendChild(range.createContextualFragment(html))
- return htmlDoc
- }
- }
- return true
- }