Flickr - Widescreen

Adjusts the appearance of photostream pages depending on the browser's window size.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// Flickr - Widescreen
// Copyright (c) 2010, Patrick Joseph.
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
//
// ==UserScript==
// @name            Flickr - Widescreen
// @namespace       http://userscripts.org/users/isamux
// @description     Adjusts the appearance of photostream pages depending on the browser's window size.
// @version         1.2.2.1
// @date            2011-04-24
// @creator         Patrick Joseph
// @include         http://*.flickr.com/photos/*
// @include         http://*.flickr.com/groups/*/pool*/
// @exclude         http://*.flickr.com/photos/friends*  
// ==/UserScript==

// ==Changelog==
//2011-04-24 v1.2.2:
// * Flickr changed id of photostream's content div from "Main" to "main". Changed it in the script to make it work again.
// * Updated integrated Flickr - TopPager to version 1.0.5.
// 2010-11-21  v1.2.1:
// * experimatal adjustment on photo page: comments are displayed in a column left to the photo.
//   Can be disabled by setting CONF_DISPLAY_COMMENTS_AS_LEFT_COLUMN to false.
// 2010-10-11  v1.2:
// * fixed medium + sets view
// * added logging functionality
// * added widescreen display for sets overview page (Example: http://www.flickr.com/photos/barackobamadotcom/sets/)
// * added @include for group pool 
// 2010-04-23  v1.1:
//  * added top pager functionality (http://userscripts.org/scripts/show/73290).
// 2010-04-22  v1.0.2:
//  * added handling for photostream layout "Medium + sets" (big5).
//  * removed @require dependency from userscript metablock. 
// 2010-04-15  v1.0.1:
//  * some minor adjustments.             
// ==/Changelog==

// ---------------
//  CONFIGURATION
// ---------------
const CONST_ENABLE_FIREBUG_LOGGING = false;

// some "constants" for the script
const CONST_MINIMUM_COLUMN_COUNT = 3; // minimum count of columns in photostream table. Should be at least 1.
const CONST_MAIN_CONTAINER = "Main";  // id of main photostream div
const CONST_CELL_WIDTH = 340;         // width of a single photostream table cell (Used for AUTO ADJUSTMENT)
const CONST_SETS_COLUMNS_WIDTH = 300; // width of the photostream's sets column
const CONST_PHOTOSTREAM_WRAPPER = '//div[@class="PhotosColumn"]'

// if CONF_AUTO_ADJUST is set to false, the values configured below, 
// are used to rearrange the photostream table.
var CONF_AUTO_ADJUST = true;
var CONF_COLUMN_COUNT = 3;              // [AUTO ADJUSTED] count of columns. Cannot be set below CONST_MINIMUM_COLUMN_COUNT;
var CONF_MAIN_CONTAINER_WIDTH = 1800;   // [AUTO ADJUSTED] width of main container. Original width 800.

// config for photostream layout "Medium + sets"
var CONF_MEDIUM_SIZE_STREAM_RESIZE_ENABLED = true;      // allows to disable resize of images in "Medium + sets" layout.
var CONF_MEDIUM_SIZE_STREAM_MINIMUM_IMAGE_WIDTH = 340;  // minimum size for resized images in "Medium + sets" layout.

var CONF_ADD_TOP_PAGER = true;          				// allows to disable top pager.
var CONF_DISPLAY_COMMENTS_AS_LEFT_COLUMN = true;		// experimental: displays comments as left column on photo page   

//  Flickr - TopPager CONFIGURATION (should not be changed)
const CONST_PAGINATED_CONTENT_XPATH_PHOTOSTREAM = '//div[starts-with(@class,"PhotoStream")]';
const CONST_PAGINATED_CONTENT_XPATH_GROUP = '//div[@class="HoldPhotos"]';
const CONST_PAGINATED_CONTENT_ID_FAVORITES = 'favoriteThumbs';
             
// ---------------

// ---------------
//  SCRIPT-MAIN
// ---------------

// 0. Prepare everything
// init logging
if(typeof console === "undefined" || !CONST_ENABLE_FIREBUG_LOGGING) {
    
   console = { log: function() { }, 
                info: function() {}, 
               debug: function() { } ,
               warn: function() {},
                error: function() {} };
}

// add top pager
if(CONF_ADD_TOP_PAGER)
  tryAddTopPager();

computeAdjustments(); 	// compute column resize parameters

// I. Adjust main div width
var mainEl = document.getElementById(CONST_MAIN_CONTAINER);
if(mainEl == null)
{
    // on some pages the main-container is named "Main" and on newer ones "main".
    mainEl = document.getElementById(CONST_MAIN_CONTAINER.toLowerCase());  
}
if(mainEl !== null)
{
    mainEl.style.width = CONF_MAIN_CONTAINER_WIDTH + "px";
}

// II.a Rearrange photostream ("Small + sets" layout)
var elPhotoColumn =  getElement(CONST_PHOTOSTREAM_WRAPPER);
if(elPhotoColumn !== null)
{
    elPhotoColumn.style.setProperty("width", (CONF_COLUMN_COUNT * CONST_CELL_WIDTH) + "px","important");
}

// II.b Rearrange photostream ("Big wo sets" layout)
elPhotoColumn =  getElement('//div[@class="PhotosColumn Big5Column Big5NoSets"]');
if(elPhotoColumn !== null)
{
    rearrangeLargeSizeLayoutPhotoStream(elPhotoColumn);
}

// // II.c Rearrange photostream in "Medium + sets" layout
// oMediumSizeImageDivs = getElementSnapshots('//div[starts-with(@class,"StreamView Big5Photo")]');
// if(null != oMediumSizeImageDivs)
// {
    // console.info("PageInfo: Photostream Medium + sets column");
    // rearrangeMediumSizeLayoutPhotoStream(oMediumSizeImageDivs);
// }

// III. Remove width from favorites container, to adjust to new width of CONST_MAIN_CONTAINER.
var oFavoritesContainer = document.getElementById('favoriteThumbs');
if(null != oFavoritesContainer)
{
    console.info("PageInfo: Favorites");
    oFavoritesContainer.style.width = "auto";
}

// IV. Adjust width on set page
var oSetContainer = document.getElementById('ViewSet');
if(null != oSetContainer)
{
    console.info("PageInfo: Single set overview");
    oSetContainer.style.width = "auto";
    var el = getElement('//div[@class="vsThumbs"]');
    el.style.width = (CONF_MAIN_CONTAINER_WIDTH-CONST_SETS_COLUMNS_WIDTH) + "px";
}

// V. Handle Sets-Overview Page
if(isSetsPage(document.URL))
{
    console.info("PageInfo: Set overview");
    oBreaks = getElementSnapshots('//div[@class="Sets"]/following-sibling::br[@clear="all"]');
    if(oBreaks != null)
    {
        for(i = 0; i < oBreaks.snapshotLength-3; i++)
        {
            obreakElement = oBreaks.snapshotItem(i);
            obreakElement.parentNode.removeChild(obreakElement);
        }
    }
}
  

 // VI. Insert Widescreen next to Flickr logo 
 insertLogo();

 // VII. Experimental new photopage adjustment
mainElNewPhotPage = document.getElementById("main");
if(null !== mainElNewPhotPage)
{
	//console.info("PageInfo: New Photopage");
	experimentalNewPhotoPageAdjust(mainElNewPhotPage); 
}

// ===============
//  FUNCTION LIB
// ===============

function computeAdjustments()
{
    // 0. auto config
    if(CONF_AUTO_ADJUST)
    {
        // compute count of fitting columns
        CONF_COLUMN_COUNT = Math.floor(window.innerWidth/CONST_CELL_WIDTH);
        
		console.debug("Computed count of columns fitting the window: " + CONF_COLUMN_COUNT);
		
        // by adjusting the width, the main content container on the photostream is moved to the left.
        // Otherwise the table with more columns, would be growing out of the main window to the right.
        CONF_MAIN_CONTAINER_WIDTH = (CONF_COLUMN_COUNT * CONST_CELL_WIDTH); 
        
        // consider sets column. If sets column exists, the CONF_COLUMN_COUNT needs to be reduced by one.
        if(additionalRightColumnExists())
        {
            CONF_COLUMN_COUNT = CONF_COLUMN_COUNT -1;
			console.debug("Additional right column exists. Count of fitting columns was reduced to " + CONF_COLUMN_COUNT);
        }
    }

    // apply minimum column count
    if(CONF_COLUMN_COUNT < CONST_MINIMUM_COLUMN_COUNT)
        CONF_COLUMN_COUNT = CONST_MINIMUM_COLUMN_COUNT
}

function additionalRightColumnExists()
{
	
	return (collectionsColumnExists() || setsColumnExists());
}

function setsColumnExists()
{
    return elementExists('//*[@class="SetsColumn"]');
}

function collectionsColumnExists()
{
	return elementExists('//*[@class="CollectionsColumn"]');
}

function isSetsPage(psUrl)
{
    bResult = false;
    iUrlLength = psUrl.length;
    
    // main sets page wo pagination
    bNoPagination = psUrl.indexOf("/sets/") == iUrlLength-6;
    bResult = bNoPagination;
    console.debug("Is main set overview page: " + bNoPagination);
    
    if(!bNoPagination)
    {
        // is main sets page on a certain page
        iLastEqual = psUrl.lastIndexOf("=");
        sTestForSetsPaginated = "/sets/?&page";
        
        sToTest = psUrl.substr(iLastEqual - sTestForSetsPaginated.length, sTestForSetsPaginated.length);
        bWithPagination = (sToTest == sTestForSetsPaginated);
        console.debug("Is main set overview page on a specific page: " + bWithPagination);
        bResult = bWithPagination;
    }

    return bResult;
}

function getOrignialPhotostreamTableElement()
{
    // get orignal photostream table position
    return getElement('//td[@class="PhotosColumn"]//table');
}

function rearrangeTable(poTableElement, piNewColumnCount)
{
    var allHeaderCells = getAllPhotostreamHeaderCells(poTableElement);
    var allImgCells = getAllPhotostreamImageCells(poTableElement);
    
    // create new table element and replace orginal
    elTable = document.createElement("table");
    elTable.innerHTML = buildTable(allHeaderCells, allImgCells, piNewColumnCount);
    
    return elTable;
}

function getAllPhotostreamHeaderCells(poTable)
{
    return getElementSnapshotsFromContext(poTable, './/tr[@valign="bottom"]//td');
}

function getAllPhotostreamImageCells(poTable)
{
    return getElementSnapshotsFromContext(poTable,'.//tr[@valign="top"]//td');
}
      
function buildTable(paAllHeaderCells, paAllImgCells, piColumnCount)
{
    var tmpTableString = '<table width="100%" cellspacing="0"><tbody>';

    for (var i = 0; i < paAllHeaderCells.snapshotLength; i++)
    {
        tmpTableString += buildTableRow(paAllHeaderCells, i, piColumnCount);
        tmpTableString += buildTableRow(paAllImgCells, i, piColumnCount);
        i+=piColumnCount;
    }

    tmpTableString += "</tbody></table>";

    return tmpTableString;
}

function buildTableRow(paCellContent,piOffset, piColumnCount)
{
    var tmp = "<tr>";
    
    while(piColumnCount--)
    {
        oTd = paCellContent.snapshotItem(piOffset++);
        tmp += buildTableCell(oTd);
    }
   
    return  tmp + "</tr>";
}

function buildTableCell(poTd)
{
    if(poTd == null)
        return "<td>-</td>";
    else
        return "<td>" + poTd.innerHTML + "</td>";
}


function rearrangeLargeSizeLayoutPhotoStream(poPhotoColumn)
{
    poPhotoColumn.style.setProperty("width", (CONF_COLUMN_COUNT * CONST_CELL_WIDTH) + "px","important");
    poPhotoColumn.style.setProperty("padding-left", "10px","important");
    poPhotoColumn.style.setProperty("padding-right", "10px","important");

    var oPhotoItemSnapsthots = getElementSnapshots('//div[@class="photo-display-item"]');
    for(i = 0; i < oPhotoItemSnapsthots.snapshotLength; i++)
    {
        oPhotoItem = oPhotoItemSnapsthots.snapshotItem(i);
        oPhotoItem.style.setProperty("float", "left","important");
        oPhotoItem.style.setProperty("margin-left", "15px","important");
    }

}

function rearrangeMediumSizeLayoutPhotoStream(paImageDivs)
{
    iMargin = 15;
    bRightColumnExists = additionalRightColumnExists();
    
    if(!bRightColumnExists)
    {
        oContainerElement = getElement('//td[contains(@class,"Big5NoSets")]');
        oContainerElement.style.setProperty("padding-left", 0, "important");
    }
    
    iWidth = computeAvailableColumnsWidthForMediumSizeLayout(iMargin, bRightColumnExists);
    sPhotItemWidth = iWidth + iMargin + "px";
    sSubItemWidth = iWidth+ "px";
     
    for (var i = 0; i < paImageDivs.snapshotLength; i++)
    {
        paImageDivs.snapshotItem(i).style.cssFloat="left";
 
        // resize images
        if(CONF_MEDIUM_SIZE_STREAM_RESIZE_ENABLED)
        {
            oImage = getElementFromContext(paImageDivs.snapshotItem(i),'.//img[@class="pc_img"]');
            
            // resize image container
            paImageDivs.snapshotItem(i).style.setProperty("width",  sPhotItemWidth , "important");
           
            // resize image
            oImage.style.height="auto";
            oImage.style.width=sSubItemWidth;
            
            // resize description
            oDescription = getElementFromContext(paImageDivs.snapshotItem(i),'.//p[@class="Desc"]');
            if(oDescription != null)
             oDescription.style.setProperty("width", sSubItemWidth, "important");

             // resize caption
             oCaption = getElementFromContext(paImageDivs.snapshotItem(i),'.//h4')
             if(oCaption != null)
                oCaption.style.setProperty("width", sSubItemWidth, "important");
      
        }
    }
}

function computeAvailableColumnsWidthForMediumSizeLayout(piMargin, pbSetsColumnExists)
{
    iColumns = 5;
    iTotalMargin = piMargin*iColumns;
    iAvailableColumnWidth = CONF_MAIN_CONTAINER_WIDTH-iTotalMargin;
    
    if(pbSetsColumnExists)
    {
        iAvailableColumnWidth = iAvailableColumnWidth - CONST_SETS_COLUMNS_WIDTH-iTotalMargin;
    }

    iWidth = iAvailableColumnWidth/iColumns;
    
    if(CONF_MEDIUM_SIZE_STREAM_MINIMUM_IMAGE_WIDTH > iWidth)
    { 
        iWidth = CONF_MEDIUM_SIZE_STREAM_MINIMUM_IMAGE_WIDTH;
    }  

     return iWidth;
}

function insertLogo()
{
    widescreenLogo = createLogo();
	
    // get flickr logo
    logo = document.getElementById('FlickrLogo');
    if(logo == null)
    {
        logo = document.getElementById('head-logo');
    }
	
	// insert widescreen logo
    logo.parentNode.insertBefore(widescreenLogo,logo);
}

function createLogo()
{
	el = document.createElement("div");
    el.innerHTML ='<a style="font-size:10px;" href="http://userscripts.org/scripts/show/73305" target="_blank" title="Widescreen-ed by Flickr-Widescreen">Widescreen</a>';
    el.style.setProperty("font-size","10px","");
    el.style.setProperty("float","left","");
    el.style.setProperty("position","relative","");
    el.style.setProperty("top","0px","");
    el.style.setProperty("left","188px","");
    el.style.setProperty("padding","1px","");
    el.style.setProperty("border","1px solid #7B0099","");
    el.style.setProperty("background-color","#FFBFE1","");
    el.style.setProperty("-moz-border-radius","3px","");
    el.style.setProperty("text-align","center","");
    el.style.setProperty("width","65px","");
	
	return el;
}


function experimentalNewPhotoPageAdjust(pMainElNewPhotPage)
{
	if(pMainElNewPhotPage == null) 
		return;
	
	
	primCol =  document.getElementById("primary-column"); 
    if(primCol ===  null)
        return;
    
	if(CONF_DISPLAY_COMMENTS_AS_LEFT_COLUMN && window.innerWidth > 1800)
	{
		// display comments in left column
		console.info("Widescreening: Inserting comments as left column");

		primCol.style.setProperty("clear","right","");

		comments =  document.getElementById("comments"); 
		comments.style.setProperty("float","left","");
		comments.style.setProperty("margin-left","25px","");
		comments.style.setProperty("width","370px","");
		document.body.insertBefore(comments,pMainElNewPhotPage)  
		document.getElementById("message").style.width="300px";
	}
}

// --------------------
//  TOP PAGER (v1.0.5)
// --------------------
function tryAddTopPager()
{
    // get paginator
    oPaginator = getPaginator();
    if(oPaginator !== null)
    {
        // get element before which the top pager will be inserted.
        oPaginatedContent = getPaginatedContent();
        
        // insert top page paginator
        if(oPaginatedContent != null)
        {
            oPaginatorClone = oPaginator.cloneNode(true);
            oPaginatedContent.parentNode.insertBefore(oPaginatorClone, oPaginatedContent);
        }
    }
}

function getPaginatedContent()
{
	// try get that element on photostream pages, ...
	oTmpFound =  getElement(CONST_PAGINATED_CONTENT_XPATH_PHOTOSTREAM);

	if(oTmpFound == null)
	{
		//...then on groups pages
		oTmpFound = getElement(CONST_PAGINATED_CONTENT_XPATH_GROUP);
	}

	if(oTmpFound == null)
	{
		//...and finally on favorites pages.
		oTmpFound = document.getElementById(CONST_PAGINATED_CONTENT_ID_FAVORITES);
	}

	return oTmpFound;
}

function getPaginator()
{
    return getElement('//div[@class="Pages"]');
}



// ===============
//  BASE LIB
// ===============

// returns result of xpath query
function getElementSnapshots(xpathExp)
{
    oResult = document.evaluate(
        xpathExp,
        document,
        null,
        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
        null);
        
    return (oResult.snapshotLength > 0)? oResult : null;
}

// returns result of xpath query below a given node
function getElementSnapshotsFromContext(contextNode, xpathExp)
{
        return document.evaluate(
        xpathExp,
        contextNode,
        null,
        XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
        null);
}

// returns a single dom element by xpath expression
function getElement(xpathExp)
{
    oResult = getElementSnapshots(xpathExp);
    return (oResult == null)?null:oResult.snapshotItem(0);
}

function getElementFromContext(contextNode, xpathExp)
{
    oResult = getElementSnapshotsFromContext(contextNode, xpathExp);
    return (oResult == null)?null:oResult.snapshotItem(0);
}

function elementExists(xpathExp)
{
    return (getElement(xpathExp) != null);
}

function replaceElement(oldElement, newElement)
{
    oldElement.parentNode.insertBefore(newElement, oldElement);
    
    // remove original table 
    oldElement.parentNode.removeChild(oldElement);
}