Greasy Fork is available in English.

Show full size image in m.facebook.com for firefox

Show full size image in m.facebook.com.

// ==UserScript==
// @name        Show full size image in m.facebook.com for firefox
// @namespace		Show full size image in m.facebook.com for firefox
// @include     /https\:\/\/m\.facebook\.com\//
// @version     3.7
// @author      zero0evolution
// @description  Show full size image in m.facebook.com.
// ==/UserScript==


// example site:"https://m.facebook.com/photo.php?fbid=...","https://m.facebook.com/.../photos/..."

// 圖片網頁格式
// /^https\:\/\/m\.facebook\.com\/(?:[0-9a-zA-Z\.]+\/photos\/[0-9a-zA-Z\.]+\/\d+|photo\.php\?fbid\=\d+)/


function unicodeToChar(text){
	text = text.replace(
		/\\u[\dA-F]{4}/gi,(match) => {
			// 刪掉\u
			match = match.replace(/\\u/g, '')
			// 16進位轉10進位
			match = parseInt(match, 16)
			// 轉字元
			match = String.fromCharCode(match)
			return(match)
		}
	)
	return(text)
}

async function getHTML(link,encoding="UTF-8",
	requestOptions = {"credentials": "same-origin"}){

	const response = await fetch(
		link,requestOptions
	).then(
		(response)=>{return(response)}
	)

	const arrayBuffer = await response.arrayBuffer().then(
		(arrayBuffer)=>{return(arrayBuffer)}
	)

	const htmlCode = new TextDecoder(encoding).decode(arrayBuffer)

	return(htmlCode)
}

async function getOriginLink(link){
	const htmlCode = await getHTML(link)
	const matchImgLinkObj = htmlCode.match(/document\.location\.href\=\"(.*?)\"/)
	if(matchImgLinkObj){
		const originLink = matchImgLinkObj[1].replace(/\\\//img,"/")
		console.log("得到新的圖片連結:",originLink)
		return(originLink)
	}
}

function loadImg(link){
	return(
		new Promise(
			(resolve,reject)=>{
				let tempImg
				if(typeof(link) === "string"){
					tempImg = document.createElement("img")
					tempImg.src = link
				}
				else if(link instanceof Element && link.matches("img")){
					tempImg = link
				}
				else{
					reject("no img link or img elem")
				}
				tempImg.onload = async(event)=>{
					resolve(tempImg)
				}
			}
		)
	)
}

async function imgViewFullSize(targetImg,link){
	targetImg.style.maxWidth = "100%"
	// targetImg.style.maxHeight = "100vh"
	targetImg.style.height = "auto"
	targetImg.style.width = "auto"

	targetImg.removeAttribute("width")
	targetImg.removeAttribute("height")

	let elem = targetImg.parentElement

	while(elem.style.width || elem.style.height){

		elem.style.removeProperty("width")
		elem.style.removeProperty("height")

		const elemStyle = getComputedStyle(elem)
		if(elemStyle.position.match(/^(absolute|fixed)$/)){
			elem.style.position = "static"
		}
		elem = elem.parentElement
	}

	// check if link is not png,jpg, need redirect
	if(!link.match(/.*\/(.*?\.(?:png|jpg))(?:\?.*)?$/)){
		link = await getOriginLink(link)
	}

	if(targetImg.matches("img")){

		await loadImg(link)

		targetImg.src = link
		return(targetImg)
	}
	else if(targetImg.matches("i.img")){
		const parent = targetImg.parentElement

		targetImg.remove()
		const tempElem = document.createElement("div")
		tempElem.innerHTML = `<img src=${link} style="max-width:100%">`
		const newTargetImg = tempElem.firstElementChild
		parent.appendChild(newTargetImg)
		await loadImg(newTargetImg)
		
		return(newTargetImg)
	}

	
}

function replaceLinkElem(linkElem){
	const newElem = document.createElement("span")
	newElem.dataset.link = linkElem.href
	newElem.textContent = linkElem.textContent
	linkElem.parentElement.insertBefore(newElem,linkElem)
	linkElem.remove()
	return(newElem)
}

function moveElemFunc(moveElem,targetElem){
	if(targetElem.parentElement instanceof Element){
		targetElem.parentElement.insertBefore(moveElem,targetElem.nextSibling)
		return(moveElem)
	}
}

function moveElemsFunc(moveElems,targetElem){
	for(let i=moveElems.length-1;i>=0;i--){
		moveElemFunc(moveElems[i],targetElem)
	}
}


async function showFullFunc(linkElem){

	const originHref = linkElem.getAttribute("href")

	if(!originHref){
		// console.warn(linkElem)
		return(null)
	}

	const viewFullSizeTextPattern = /^(?:全尺寸檢視|view full size)$/i

	if(
		linkElem.textContent.match(viewFullSizeTextPattern) && 
		linkElem.matches("#viewport #rootcontainer a[href]")
	){
		

		let targetElem = document.querySelector("#viewport #rootcontainer i.img[role='img'][data-store][style^='background-image: url']")
		if(targetElem instanceof Element){
			// const parent = targetElem.parentElement

			// const tempElem = document.createElement("div")
			// tempElem.innerHTML = `<img src=${linkElem.href} style="max-width:100%">`
			// parent.appendChild(tempElem.firstElementChild)
			// targetElem.remove()

			targetElem = await imgViewFullSize(targetElem,linkElem.getAttribute("href"))
		}
	}

	const photoLinkPattern = /^\/?(?:photo\.php\?fbid\=|[0-9a-z\.\-\_]+\/photos\/)/i
	const photoLinkPattern2 = /^\/[0-9a-zA-Z\.]+\/photos\/[0-9a-zA-Z\.]+\/[0-9]+/i

	const photoLinkPattern3 = /^\/photos\/viewer\/\?/
	

	if(
		originHref.match(photoLinkPattern) || 
		originHref.match(photoLinkPattern2) ||
		originHref.match(photoLinkPattern3)
	){

		
		let targetImg = linkElem.querySelector(
			"i.img[role='img'][style*='background-image:']")
		if(targetImg instanceof Element){

			// console.log(linkElem.href)

			linkElem.parentElement.align = "center"
			linkElem.parentElement.style.width = "100%"
			linkElem.parentElement.style.removeProperty("height")
			linkElem.parentElement.style.display = "inline-block"
			linkElem.style.removeProperty("left")
			linkElem.style.removeProperty("top")
			linkElem.style.removeProperty("width")
			linkElem.style.removeProperty("height")
			linkElem.style.maxWidth = "100%"
			linkElem.style.height = "auto"
			linkElem.style.position = "relative"

			let nextLinkElem = linkElem.nextElementSibling

			const htmlCode = await getHTML(linkElem.href)
			const matches = htmlCode.match(/\<a\s.*?\<\/a\>/img)
			// console.log(matches)
			for(const match of matches){
				const tempElem = document.createElement("div")
				tempElem.innerHTML = match
				const fullSizeLinkElem = tempElem.firstElementChild
				if(fullSizeLinkElem.textContent.match(viewFullSizeTextPattern)){

					let fullImgLink = fullSizeLinkElem.getAttribute("href")
					if(!fullImgLink.match(/.*\/(.*?\.(?:png|jpg))(?:\?.*)?$/)){
						fullImgLink = await getOriginLink(fullImgLink)
					}
					linkElem.innerHTML = `<img src="${fullImgLink}" style="max-width:100%;height:auto;">`
					// console.log(linkElem.innerHTML)
					// targetImg = await imgViewFullSize(targetImg,fullSizeLinkElem.href)

					linkElem.parentElement.insertBefore(document.createElement("br"),linkElem.nextElementSibling)
					break
				}
			}

			

			if(
				(!(nextLinkElem instanceof Element)) || 
				(!(nextLinkElem.matches("a[href]")))
			){
				// console.log("最後一個linkElem:",linkElem)
				// 找下一張連結
				for(const match of matches){
					const tempElem = document.createElement("div")
					tempElem.innerHTML = match
					nextLinkElem = tempElem.firstElementChild
					if(!nextLinkElem.matches("a.touchable[href]")){
						continue
					}
					if(!nextLinkElem.textContent.match(/^(Next|繼續)$/i)){
						continue
					}
					const nextLink = nextLinkElem.getAttribute("href")
					// 建立按鈕且功能為加入下一張圖片
					const button = document.createElement("button")
					button.textContent = "Next"
					linkElem.parentElement.insertBefore(button,linkElem.nextElementSibling.nextElementSibling)

					button.dataset.link = nextLink

					button.addEventListener("click",function(event){
						const button = event.currentTarget
						const link = button.dataset.link
						
						const tempElem = document.createElement("div")
						tempElem.innerHTML = `
							<a href="${link}">
								<i class="img" role="img" style="background-image:none;"></i>
							</a>
						`
						const nextLinkElem = tempElem.firstElementChild

						button.parentElement.insertBefore(
							nextLinkElem,button.nextElementSibling)

						button.remove()
					})
				}
			}
		}
	}

	
	// 新增影片
	const videoLinkPattern = /^\/?video\_redirect\/\?src\=/i
	if(originHref.match(videoLinkPattern)){
		const videoLink = decodeURIComponent(originHref.replace(videoLinkPattern,""))
		const videoElem = document.createElement("video")
		videoElem.src = videoLink
		videoElem.controls = true
		// videoElem.style.maxWidth = "100%"
		videoElem.style.width = "100%"
		videoElem.style.minHeight = "60vh"
		videoElem.style.maxHeight = "100vh"

		linkElem.parentElement.insertBefore(videoElem,linkElem.nextSibling)
		linkElem.remove()
		// videoElem.parentElement.align = "center"
	}
	
}


// 挑出所有的連結
// const selectorText = "a[href]"
async function filterFunc(topElem){
	if(topElem.matches("a[href]")){
		await showFullFunc(topElem).catch((err)=>{console.warn(err)})
	}
	for(const linkElem of topElem.querySelectorAll("a[href]")){
		await showFullFunc(linkElem).catch((err)=>{console.warn(err)})
	}
}

filterFunc(document.documentElement)

const observerObj = new MutationObserver(
	function (mutationObjs){
		for(const eachMutationObj of mutationObjs){
			for(const eachAddNode of eachMutationObj.addedNodes){
				if(eachAddNode.nodeType === 1){
					filterFunc(eachAddNode)
				}
			}
		}
	}
)

observerObj.observe(
	document.documentElement,{
		childList:true,
		subtree:true,
	}
)


// 顯示更多
// 查看更多動態
// video