RES Twitter Fix

Fixes RES Twitter expandos in Firefox

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

// ==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 )