RES Twitter Fix

Fixes RES Twitter expandos in Firefox

目前為 2018-04-20 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        RES Twitter Fix
// @namespace   com.res-twitter-fix
// @description Fixes RES Twitter expandos in Firefox
// @match       https://*.reddit.com/*
// @run-at      document-end
// @grant				none
// @version     2.0
// ==/UserScript==

"use strict"

function copyExpando( el )
{
	// copy expando contents from iframe to div & replace
	// this is necessary to circumvent the iframe losing all its content
	// whenever the user collapses it (why does twitter use iframes?!)
	
	console.log( 'copying expando' )
	const doc = el.contentDocument.documentElement

	const html = doc.innerHTML
	const styles = el.style.cssText
	
	const div = document.createElement( 'div' )
	div.className = doc.className
	div.innerHTML = html
	el.parentNode.appendChild( div )
	div.style.cssText = styles
	div.style.position = 'relative'
	div.style.visibility = 'visible'
	
	el.parentNode.removeChild( el )
}

function wait()
{
	// async spin lock?
	// let's try and get this done as fast as possible--as soon as it loads!
	setTimeout( () => { waitForExpandos() }, 10 )
}

function waitForExpandos()
{
	// wait for expandos to be loaded as iframes
	console.log( 'waiting for expandos...' )
	const expandos = document.querySelectorAll( 'iframe.twitter-tweet' )
	if ( expandos.length === 0 )
		return wait()
	else
	{
		// iframes are present, but make sure they're valid & fully loaded
		// sometimes they aren't 100% ready yet and some properties are still uninitialized
		//  - contentDocument and documentElement may be null
		//  - body may be null or empty (not yet populated)
		for ( const el of expandos )
		{
			const cont = el.contentDocument
			if ( !cont )
				return wait()

			const doc = el.contentDocument.documentElement
			if ( !doc )
				return wait()

			const body = doc.querySelector( 'body' )
			if ( !body || body.innerHTML === '' )
				return wait()
		}
	}

	// everything is fully initialized
	console.log( 'expandos populated' )
	for ( const el of expandos )
	{
		// if necessary, wait until everything inside the iframe is done loading
		if ( el.contentDocument.readyState === 'complete' )
			copyExpando( el )
		else
			el.contentWindow.onload = () => { copyExpando( el ) }		
	}
}

function injectTwitterScript()
{
	// inject twitter script to convert blockquotes to pretty twitter displays
	console.log( 'injecting twitter script' )
	const script = document.createElement( 'script' )
	script.src = 'https://platform.twitter.com/widgets.js'
	document.body.appendChild( script )

	waitForExpandos()
}

function fixExpandos()
{
	// look for twitter expandos and proceed if any are found
	console.log( 'looking for expandos' )
	const expandos = document.querySelectorAll( '.twitter-tweet' )
	if ( expandos.length > 0 )
		injectTwitterScript()
}

function onClick( e )
{
	// check if we've clicked an expando button
	if ( e.target.className.includes( 'expando-button' ) )
	{
		// fix expandos on click
		fixExpandos()

		// also attempt to fix auto-expanded expandos
		// perhaps this is not the most reliable way to do it, as there's
		// no way to know exactly how long it'll take RES to auto-expand
		setTimeout( () => { fixExpandos() }, 1000 )
	}
}
document.addEventListener( 'click', onClick, false )