RES Twitter Fix

Fixes RES Twitter expandos in Firefox

当前为 2018-04-20 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 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 )