// 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* // @downloadURL https://update.greasyfork.icu/scripts/10796/Flickr%20-%20Widescreen.user.js // @updateURL https://update.greasyfork.icu/scripts/10796/Flickr%20-%20Widescreen.meta.js // ==/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 = ''; for (var i = 0; i < paAllHeaderCells.snapshotLength; i++) { tmpTableString += buildTableRow(paAllHeaderCells, i, piColumnCount); tmpTableString += buildTableRow(paAllImgCells, i, piColumnCount); i+=piColumnCount; } tmpTableString += "
"; return tmpTableString; } function buildTableRow(paCellContent,piOffset, piColumnCount) { var tmp = ""; while(piColumnCount--) { oTd = paCellContent.snapshotItem(piOffset++); tmp += buildTableCell(oTd); } return tmp + ""; } function buildTableCell(poTd) { if(poTd == null) return "-"; else return "" + poTd.innerHTML + ""; } 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 ='Widescreen'; 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); }