Adding and removing linked items using hyperlinks
From VYRE
Contents |
Pre-Requisites
- Unify Item-Edit Using Template Portlet
- Content Templates
- Item link definitions
- Javascript
- XSL
Introduction
Unify by default allows users to link items through dropdown (if linking one item) and select boxes (if linking multiple items) using Item-Edit Portlet and Item-Edit Using Template Portlet. Using this linking mechanism users don’t get much control over the presentation. The linked item/s would just be displayed in either dropdown box or multiple select box. However, Item-Edit Using Template Portlet with the use of Content Templates solves this problem by giving full control to users and letting them display the linked items in the way they want and also allowing them to link in more intuitive way. The following tutorial explains how the process works and code needed to implement this functionality.
Background Work
For the following tutorial let’s assume that we have two stores NEWS (a datastore that holds news that we would like to display on the site) and IMAGES (a filestore that contains images relevant to the news) and there are two link definitions setup between these stores. The first link definition is for linking image of author who produced a news item (we would convert this to ) and through second link definition we will link other news related images. Now if we want to link news to images and vice versa, we need to set up an edit page for news from where we can do so.
Step 1: Setup edit page using Item-Edit Using Template Portlet
In order for us to be able to control the way we link items, the edit page has to be setup using Item-Edit using template portlet and content template. Lets say we are creating a content template that would only allow us to edit name, description and above mentioned item links, the content template would contain the following code:
<jsp:directive.page contentType="text/html;charset=UTF-8"/> <% response.setContentType("text/html;charset=" + vyre.core.Kernel.getEncoding()); %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> <%@ taglib uri="http://www.vyre.com/taglibs/vyre-item-1.0" prefix="vyre-item" %> <div id="validationErrors"> <c:forEach var="error" items="${validationErrors}"> <div class="validationError">${error.messageKey}</div> </c:forEach> </div> <div> <vyre-item:attribute name="name" mode="field" /> </div> <div> <vyre-item:attribute name="description" mode="field" /> </div> <!-- the id of the link definition must be changed to the one being used, the one below is for our example as we will be linking authors image through link definition 1--> <vyre-item:item-link id="1" mode="field" cardinality="one" /> <!-- the id of the link definition must be changed to the one being used, the one below is for our example as we will be linking multiple news related images through link definition 2--> <vyre-item:item-link id="2" mode="field" cardinality="many" /> <div> <input type="button" value="Save" onclick="<vyre-item:action type="createAndActivate" />" /> </div> <c:if test="${item != null}"> <div> <input type="button" value="Delete" onclick="<vyre-item:action type="delete" />" /> </div> </c:if>
The above content template can be added on edit page through Item-Edit using template portlet. As a result of the above code we will see that we will be able to edit name, description and two link definitions. However, the first link definition would appear as a dropdown through which we can link one image (for author), and second one as select box so we can link multiple images (for news related images). Just for testing create a new news item and link an author image (using dropdown) and few more images (using select box) and save the news. Now if you edit the newly created news you will find that the author’s image is being displayed in the dropdown and other images in the select box. But we would like to first of all control the way we display linked images (not seeing them in dropdown and select box) and secondly want more intuitive way of linking.
STEP 2: Changing/Controlling the appearance of linked images
In order to control how linked images are displayed, we will first of all need to create a new XSL in Publishing Module under Files->XSL->Item-List Folder and let’s call it “Linked Image/s to news” with the following code.
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> <!ENTITY copy "©"> <!ENTITY reg "®"> <!ENTITY trade "™"> <!ENTITY mdash "—"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY pound "£"> <!ENTITY yen "¥"> <!ENTITY euro "€"> ]> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="iso-8859-1"/> <xsl:param name="current_path" ></xsl:param> <xsl:param name="context_path" ></xsl:param> <xsl:template match="/"> <!-- The following textarea on the page will contain all the XML being provided by the portlet that we can work on in this XSL--> <textarea><xsl:copy-of select="*" /></textarea> </xsl:template> </xsl:stylesheet>
The above XSL does not contain any clever code and if used by any portlet will only show a text area with all the XML being returned by that portlet. Save this XSL and please note the id of the XSL. You can do so by looking at the list of XSL’s where you have created them and next to each XSL would be a numerical number in ID column.
Now edit the content template created in Step 1 above and change the code that reads
<vyre-item:item-link id="1" mode="field" cardinality="one" />
TO
<div id=”author-image”> <vyre-item:item-link id="1" mode="formatted" xslId=”{id of xsl created above}” elementId=”author-image” /> </div> <input type = "hidden" id = "current_link"/>
After changing this, save the content template and edit the news you created in STEP 1 above. You will notice that instead of a dropdown with linked author’s image (that you linked previously) is a text area with some XML and if you go through this XML you will find that data is about image you linked previously. This means that now the XSL above is controlling how to display items. Now if you want to, you can display the thumbnail or any information of the linked image/s as we have that available in the xml.
Replace the xsl created above with the one as follows (let’s say we call this XSL 1):
<?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="iso-8859-1"/> <xsl:param name="current_path" ></xsl:param> <xsl:param name="context_path" ></xsl:param> <xsl:param name="parent_path" ></xsl:param> <xsl:param name="linkDefinitionId" ></xsl:param> <xsl:param name="link_add_action" ></xsl:param> <xsl:param name="link_remove_functionname"></xsl:param> <xsl:template match="/"> <xsl:variable name="path"><xsl:value-of select="$current_path" /></xsl:variable> <xsl:variable name = "link"><xsl:value-of select = "$linkDefinitionId"/></xsl:variable> <script language="javascript"> // following function opens a popup function open_custom( path,width,height) { window.open(path, 'aWindow',' width=' + width + ', height=' + height + ', menubar=no, location=no, resizable=yes, hotkeys=no, directories=no, scrollbars=yes, toolbar=no, titlebar=no, status=no'); } // following function passes the path of the page that contains a list of images to the function above function choose_images(link) { open_custom('<xsl:value-of select="$context_path" />/admin/add_image/?link_def='+link,504,843); } </script> <table cellpadding="1" cellspacing="0" border="0"> <xsl:apply-templates select="search-results/items/file-item"/> <a href="javascript:choose_images({$link})"> [Link Assets] </a> </table> </xsl:template> <xsl:template match="file-item"> <xsl:if test="position() mod 3 = 1"> <tr> <td> <a href="javascript:open_image({collection-schema/@id},{@id})"> <img src="{derived-files/thumbnail}" border="0" class="item-pic"/> </a> <br/> <h1><xsl:value-of select="name" /></h1> <br/> <a href="javascript:{$link_remove_functionname}('{$linkDefinitionId}','{@id}')">[del]</a> </td> <xsl:if test="following-sibling::file-item[1]"> <td> <a href="javascript:open_image({following-sibling::file-item[1]/collection-schema/@id},{following-sibling::file-item[1]/@id})"> <img src="{following-sibling::file-item[1]/derived-files/thumbnail}" border="0" class="item-pic"/> </a> <br/> <h1><xsl:value-of select="following-sibling::file-item[1]/name" /></h1> <br/> <a href="javascript:{$link_remove_functionname}('{$linkDefinitionId}','{following-sibling::file-item[1]/@id}')">[del]</a> </td> </xsl:if> <xsl:if test="following-sibling::file-item[2]"> <td> <a href="javascript:open_image({following-sibling::file-item[2]/collection-schema/@id},{following-sibling::file-item[2]/@id})"> <img src="{following-sibling::file-item[2]/derived-files/thumbnail}" border="0" class="item-pic"/> </a> <br/> <h1><xsl:value-of select="following-sibling::file-item[2]/name" /></h1> <br/> <a href="javascript:{$link_remove_functionname}('{$linkDefinitionId}','{following-sibling::file-item[2]/@id}')">[del]</a> </td> </xsl:if> </tr> </xsl:if> </xsl:template> </xsl:stylesheet>
STEP 3: Adding a page that will list out all items that need to be linked
Create another page on the site and add a search results portlet using the xsl below (the search results portlet should list all the items from the store you wish to link to the current item – in our case it should be images store):
Let’s say we call this XSL 2
<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> <!ENTITY copy "©"> <!ENTITY reg "®"> <!ENTITY trade "™"> <!ENTITY mdash "—"> <!ENTITY ldquo "“"> <!ENTITY rdquo "”"> <!ENTITY pound "£"> <!ENTITY yen "¥"> <!ENTITY euro "€"> ]> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="iso-8859-1"/> <xsl:param name="current_path" ></xsl:param> <xsl:param name="context_path" ></xsl:param> <xsl:template match="/"> <xsl:variable name="path"><xsl:value-of select="$current_path" /></xsl:variable> <script language="javascript"> <![CDATA[ var parentPluto; var plutoArray = new Array("p474I","p563I") for(i = 0;i<plutoArray.length;i++){ if(window.opener.document.getElementById("form"+plutoArray[i])){ parentPluto = plutoArray[i]; } } var linkid = getURLValue("link_def"); if(linkid.length >0) { window.opener.document.getElementById("current_link").value = linkid; } else { linkid = window.opener.document.getElementById("current_link").value; } function selectItemValues(itemId) { eval("window.opener.addSelectedLink"+parentPluto+"("+linkid+","+ itemId+" );"); } ]]> </script> <table cellspacing="1" cellpadding="0" border="0" width="470"> <xsl:apply-templates select="search-results/items/file-item" /> </table> </xsl:template> <xsl:template match="file-item"> <xsl:if test="position() mod 3 = 1"> <tr> <td> <xsl:choose> <xsl:when test="derived-files/thumbnail"> <img src="{derived-files/thumbnail}" title="{name}" alt="{name}" border="0"/><br/> </xsl:when> <xsl:otherwise> <img src="{$context_path}/other_files/img/no_thumbnail.gif" border="0" alt="No_Thumbnail" title="No_Thumbnail"/><br/> </xsl:otherwise> </xsl:choose> <xsl:value-of select="name" disable-output-escaping="yes"/><br/><a href="javascript:selectItemValues({@id});">[add]</a> </td> <xsl:if test="following-sibling::file-item[1]"> <td> <xsl:choose> <xsl:when test="following-sibling::file-item[1]/derived-files/thumbnail"> <img src="{following-sibling::file-item[1]/derived-files/thumbnail}" title="{following-sibling::file-item[1]/name}" alt="{following-sibling::file-item[1]/name}" border="0"/><br/> </xsl:when> <xsl:otherwise> <img src="{$context_path}/other_files/img/no_thumbnail.gif" border="0" alt="No_Thumbnail" title="No_Thumbnail"/><br/> </xsl:otherwise> </xsl:choose> <xsl:value-of select="following-sibling::file-item[1]/name" disable-output-escaping="yes"/><br/><a href="javascript:selectItemValues({following-sibling::file-item[1]/@id})">[add]</a> </td> </xsl:if> <xsl:if test="following-sibling::file-item[2]"> <td> <xsl:choose> <xsl:when test="following-sibling::file-item[2]/derived-files/thumbnail"> <img src="{following-sibling::file-item[2]/derived-files/thumbnail}" title="{following-sibling::file-item[2]/name}" alt="{following-sibling::file-item[2]/name}" border="0"/><br/> </xsl:when> <xsl:otherwise> <img src="{$context_path}/other_files/img/no_thumbnail.gif" border="0" alt="No_Thumbnail" title="No_Thumbnail"/><br/> </xsl:otherwise> </xsl:choose> <xsl:value-of select="following-sibling::file-item[2]/name" disable-output-escaping="yes"/><br/><a href="javascript:selectItemValues({following-sibling::file-item[2]/@id})">[add]</a> </td> </xsl:if> </tr> </xsl:if> </xsl:template> </xsl:stylesheet>
Please make sure that you put the portlet ID of the Item Edit Using Template portlet in the “plutoArray” in the javascript code is XSL 2 above. For e.g.
var plutoArray = new Array (“{portlet id of item edit using template portlet}”,”{portlet id of another item edit using template portlet if applicable}”);
Also in XSL 1 created in step 1, change the path of parameter passed in “choose_images” function to the path of the page created above in this step. For example
function choose_images(link) { open_image_link_win_big('<xsl:value-of select="$context_path" />/{path to the page created in step 2 above} /?link_def='+link,504,843); }
Create a new script file with the following code and link it to the page created above:
function getURLValue(varname) { // First, we load the URL into a variable var url = window.location.href; // Next, split the url by the ? var qparts = url.split("?"); // Check that there is a querystring, return "" if not if (qparts.length == 0 || url.indexOf("?")== -1) { return ""; } // Then find the querystring, everything after the ? var query = qparts[1]; // Split the query string into variables (separates by &s) var vars = query.split("&"); // Initialize the value with "" as default var value = ""; // Iterate through vars, checking each one for varname for (i=0;i<vars.length;i++) { // Split the variable by =, which splits name and value var parts = vars[i].split("="); // Check if the correct variable if (parts[0] == varname) { // Load value into variable value = parts[1]; // End the loop break; } } // Convert escape code value = unescape(value); // Convert "+"s to " "s value.replace(/\+/g," "); // Return the value return value; }
