Greasy Fork is available in English.

Flickr - Widescreen

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

질문, 리뷰하거나, 이 스크립트를 신고하세요.
// 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);
}