zoukankan      html  css  js  c++  java
  • Customizing the HTML code of a Content Query Web Part

    I’m learning all about SharePoint branding as part of my new job at Synteractive, so this post started out as a reference file and notes on the steps I was taking. It ended up being an insanely long blog draft and I decided to throw it out there to see if more experienced SharePoint superstars can give me some tips on how I could have done this more easily or maybe to help other newbie SharePoint developers.

    Some facts and disclaimers:

    • I’m working with a SharePoint 2010 Publishing site and using SharePoint Designer 2010 for modifying some of the site files.
    • I’m not going to go into CSS in this article, so I won’t talk about how I style the web part. This article is really just about getting the HTML I want to be generated from a customized Content Query Web Part.
    • At this point, I’m literally just under three weeks into learning about SharePoint branding, customizing master pages, working with XSL, etc. I have a lot to learn.

    Here is the challenge that I had:

    First, here’s a screenshot of my custom query web part:

    • The CQWP pulls from a list of publishing pages and displays the title, a description, an image, and links to the page.
    • Of the three dummy data items there, #1 only has a title and link, #2 has a title, description, image, and link, and #3 only has the title, description, and link.
    • The CQWP is set up to use the “image on left” Item Style.

    If you view the HTML source, there is a TON of HTML code that goes into the above; there are several nested tables and stuff for allowing you to click on the header to edit it. Here is just a small sampling…

    <table class="s4-wpTopTable" border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td><table border="0" cellpadding="0" cellspacing="0" width="100%"><tr class="ms-WPHeader"><td align="left" class="ms-wpTdSpace"> </td><td title="Recent News - Displays a dynamic view of content from your site." id="WebPartTitleWPQ2" class="ms-WPHeaderTd"><h3 style="text-align:justify;" class="ms-standardheader ms-WPTitle"><nobr><span>Recent News</span><span id="WebPartCaptionWPQ2"></span></nobr></h3></td>

    The actual data part – the list of news items – has HTML code that looks like this:

    <ul class="dfwp-column dfwp-list" style="100%" ><li class="dfwp-item"><div class="item"><div class="link-item"><a href="#" title="">New SPDevWiki site released!</a><div class="description"></div></div></div></li><li class="dfwp-item"><div class="item"><div class="link-item"><a href="#" title="">SharePoint 2010 SDK released</a><div class="description">SharePoint 2010 SDK released for RTM</div></div></div></li><li class="dfwp-item"><div class="item"><div class="link-item"><a href="#" title="">Announcing Community Kit for SharePoint</a><div class="description">CodePlex projects teams get together to release CKS:Dev!</div></div></div></li></ul>

    There are plenty of classes to work with… but if I were to modify the .dfwp-xxx classes, those would affect all of the web parts using that type of display, and in my specific situation, I couldn’t throw the web part into my own custom <div> with an ID or class that would allow me to target only that web part.

    But I’m getting ahead of myself. Let me show you what I was shooting for. Here’s my HTML that I would ideally want:

    <div class="blogfeed-wrapper"><div class="blogfeed"><h2>Recent News</h2><ul><li><p class="date">Jun 5, 2010</p><p class="image"><img src="images/pic.png" alt="image" width="50" height="50" /></p><h3><a href="#">Article title</a></h3><p class="blurb">Article blurb</p></li><!-- repeat LI for each data item --></ul></div></div>

    To accomplish this, I would have to:

    1. Figure out how to wrap the DIVs and UL around the repeated list items, along with the H2 heading
    2. Modify the code for the repeated list items to use the HTML code I want (and to show the additional “article date” field)

    I looked around for information about customizing the Content Query Web Part and found this article, “Display Content Query Web Part Results in a Grid/Table” by Paul Galvin which seemed like it might do the trick. He references Heather Solomon’s blog post, “Customizing the Content Query Web Part and Custom Item Styles.” Here are the step-by-steps of what I did:

    1. I followed Heather Solomon’s article, steps 5-11, and Paul Galvin’s step 4 to create a test item style in ItemStyle.xsl in order to list out the data already being pulled into the web part. I named my custom style “TestList” – I’ll keep it around for testing other web parts.
      1. In SharePoint Designer 2010, open Style Library/XSL Style Sheets/ItemStyle.xsl. Note that this file is only available in a root or top-level SharePoint site, not in subsites.
      2. Click the “Edit” link (in the “Customization” section).
      3. In ItemStyle.xsl, you’ll see a few <xsl:variable /> tags at the top, followed by sections of <xsl:template /> code. Each <xsl:template /> has a name associated with it which corresponds to the Item Style dropdown in the Web Part editor.
      4. Here’s the code I added – just to keep it easy to find, I put it under the “Default” template section. Also notice that the value for name and @Style must be identical.
        <xsl:template name="Default" match="*" mode="itemstyle">....</xsl:template><!-- custom item style template for listing out fields --><xsl:template name="TestList" match="Row[@Style='TestList']" mode="itemstyle"><xsl:for-each select="@*"><xsl:value-of select="name()" /><br /></xsl:for-each></xsl:template>
      5. Back in the browser, click to edit the web part. In the web part editor, under Presentation > Styles, pick the new “TestList” from the list of Item Styles:
      6. Here’s what I ended up with:
      7. If you want, copy and paste the list into a text editor for reference just in case.
    2. Now, following steps 12-13 in Heather’s article, I went to find the specific column “Internal Names” for fields that I wanted to add to the web part.
      1. Go to Site Settings > Site Administration: Site Libraries and Lists. This page shows a list of the various types of lists and libraries in your site.
      2. I picked the “Pages” list because that’s what my Content Query Web Part is pulling, but you’ll want to go to whichever list you’re trying to pull data from. This takes you to the List Information page.
      3. Scroll down to the Columns section to view all the columns that are available for that type of content.
      4. Hover or click on the link for the columns that you want to add to the Content Query Web Part results. I’m primarily interested in the “Article Date” column. At the very end of the link is the “Field” parameter, followed by the internal column name. In my case, the Article Date column’s internal name is ArticleStartDate.
    3. Following steps 16-18 in Heather’s article, I export the CQWP, modify the code to include the extra column(s), then import it back in as a new web part.
      1. Back on the web site, expand the edit menu and choose “Export.”
      2. Save the .WEBPART file to your computer, then open it in a text editor.
      3. Look for “CommonViewFields” and you’ll see something like this:
        <property name="CommonViewFields" type="string" />
      4. Following Heather’s instructions, I modify the tag to include my additional ArticleStartDate column.
        <property name="CommonViewFields" type="string">ArticleStartDate, DateTime</property>

        Note: From this MSDN article, “How to Display Custom Fields in a Content by Query Web Part,” there’s an additional step (Step 4) to map the new column to existing/available fields in the web part. This only works if your custom field can replace the Title, Description, LinkURL, or ImageURL web part fields – which could save you a few steps if, say, you wanted to show a different text column in place of the “description” field. In this case, though, since I want to display the article date, I’m going to have to do some actual customization to the XSL files, described below.

      5. Save the file. Back in the browser, click the “Edit” button to edit the page so that you can add more web parts to the page.
      6. Click “Add a Web Part”, then click “Upload a Web Part” and browse to your .WEBPART file, then click Upload.
      7. You’ll have to click “Add a Web Part” again, but this time you’ll see an additional folder for “Imported Web Parts” with your new web part listed. Add this to your page. (Mine is called “Recent News” because it exported my original Content Query Web Part, which had “Recent News” as the title.)
      8. The new web part will show up on the page. Notice that the new column is included with the other data:
      9. Delete the original web part just to get it off the page.
    4. Now, I wanted to figure out how to modify the HTML to display what I wanted: Some outer wrapper DIVs for styling, an H2 heading for the “Recent News” title, a wrapper UL for the list items, and then using a simple LI for each list item. Bear with me as I explain the overall approach:
      1. First – I’m going to get rid of the existing “Recent News” heading by changing the Chrome of the web part to hide the current title and ONLY show the list itself. This will allow me to get rid of the funky tables and code that are really difficult to style. (I’m going to be inserting my own heading in the HTML instead.)
      2. Then – I’m going to do the “easy” part, which is to edit ItemStyle.xsl with my HTML for each list item (the <LI> and everything in between from the top of this page in my “ideal” HTML code). This will allow me to get rid of the various DIVs from the default “Image on Left” code, remove displayed fields that I don’t need, and add in the additional fields that I want to display (in this example, ArticleStartDate). Both Paul and Heather’s articles cover this part. Note: As mentioned in Heather’s article, ItemStyle.xsl “repeats” itself for each data item, which is why I would only put in the <LI> code. If I added <UL>, I would get a separate UL list for each item.
      3. Finally – the “hard” part, which is to edit ContentQueryMain.xsl to put in my wrapper DIVs, H2 heading, and UL, which will go around the stuff being generated in ItemStyle.xsl and make everything look pretty. This is where I turned to Paul’s article.
    5. Here we go! Starting with 4a: Hide the web part title bar by editing the web part and changing the Chrome Type to “None.”

      Note: If you were to save/close or check in the page, you’ll just see the list of data fields without the title bar.

      If you’re like me, you may freak out initially: “What have I done?! Now I can’t edit the web part!” No worries – as soon as you click “Edit page,” you’ll see your web part zones and the title bar will reappear for editing.
    6. Pulling from Heather’s article (steps 19-24), I open ItemStyle.xsl (again) in SharePoint Designer for editing.
      1. At this point, I already have an idea of the Item Style that I want to start from – the “Image on Left” style, because it already will contain the code I need for the image, title, and description, so all I need to do is move things around and add the date. You will need to figure out which Item Style you want to start with and find the corresponding code.
      2. In this case, “Image on Left” happens to be the same as the “default” template, so I find the 60 or so lines of code that make up the Default template, copy, and paste it under my TestList template.
        <xsl:template name="Default" match="*" mode="itemstyle">....</xsl:template>
      3. My first step is to replace <xsl:template name=”Default” match=”*” mode=”itemstyle”> with something that looks more like my TestList template line, but with yet another custom Item Style name. I’ll call mine “News”:
        <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">

        In other words, replace name=”YourCustomStyleName” and match=”Row[@Style='YourCustomStyleName']” in your <xsl:template> tag.

      4. Now, each xsl:template section has some variables or parameters at the top, followed by recognizable HTML code mixed in with various xsl tags for testing conditionals or displaying data. I copy the “ideal HTML” that I want to have and paste it into the top of that section to start me off.
        <li><p class="date">Jun 5, 2010</p><p class="image"><img src="images/pic.png" alt="image" width="50" height="50" /></p><h3><a href="#">Article title</a></h3><p class="blurb">Article text</p></li>
      5. Then, start moving the relevant XSL code into your HTML tags.You can see what I did below. I had to add the ArticleStartDate field (see Step 20 in Heather’s blog) and formatted it by following the steps at Josh Gaffey’s blog for Custom Date Formats in SharePoint so that the date is displayed as m/d/yyyy. (Note that I put stuff I don’t really care about… or don’t understand what they do… in a comment tag to hide them.)
        <!-- custom item style template for recent news --><xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">    <xsl:variable name="SafeLinkUrl">        <xsl:call-template name="OuterTemplate.GetSafeLink">            <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>        </xsl:call-template>    </xsl:variable>    <xsl:variable name="SafeImageUrl">        <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">            <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>        </xsl:call-template>    </xsl:variable>    <xsl:variable name="DisplayTitle">        <xsl:call-template name="OuterTemplate.GetTitle">            <xsl:with-param name="Title" select="@Title"/>            <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>        </xsl:call-template>    </xsl:variable><li><!-- Here is where I add in my ArticleStartDate field. It would typically look like<xsl:value-of select="@ArticleStartDate" />but the extra stuff is to format the date. --><p class="date"><xsl:value-of select="ddwrt:FormatDate(@ArticleStartDate,1033,1)" /></p><xsl:if test="string-length($SafeImageUrl) != 0">            <p class="image">                <a href="{$SafeLinkUrl}">                  <xsl:if test="$ItemsHaveStreams = 'True'">                    <xsl:attribute name="onclick">                      <xsl:value-of select="@OnClickForWebRendering"/>                    </xsl:attribute>                  </xsl:if>                  <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">                    <xsl:attribute name="onclick">                      <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>                    </xsl:attribute>                  </xsl:if>                  <img class="image" src="{$SafeImageUrl}" title="{@ImageUrlAltText}">                    <xsl:if test="$ImageWidth != ''">                      <xsl:attribute name="width">                        <xsl:value-of select="$ImageWidth" />                      </xsl:attribute>                    </xsl:if>                    <xsl:if test="$ImageHeight != ''">                      <xsl:attribute name="height">                        <xsl:value-of select="$ImageHeight" />                      </xsl:attribute>                    </xsl:if>                  </img>                </a>            </p>        </xsl:if><h3><a href="{$SafeLinkUrl}" title="{@LinkToolTip}"><xsl:value-of select="$DisplayTitle"/></a></h3><p class="blurb"><xsl:value-of select="@Description" /></p><!--<xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>            <a href="{$SafeLinkUrl}" title="{@LinkToolTip}">              <xsl:if test="$ItemsHaveStreams = 'True'">                <xsl:attribute name="onclick">                  <xsl:value-of select="@OnClickForWebRendering"/>                </xsl:attribute>              </xsl:if>              <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">                <xsl:attribute name="onclick">                  <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>                </xsl:attribute>              </xsl:if>            </a>            --></li></xsl:template>
      6. When you’re done, go back into the browser to edit the web part. You should see your new custom item style in the Item Style select box. In the screenshot below, you can see that “News” (the name of my custom Item Style) showed up properly, so I was able to pick it and apply it. Of course, I’m still missing the wrapper HTML code (for the UL, etc.) so I moved on to the next step…
    7. Now I want to get the wrapper HTML code (below) around the LIs.
      <div class="blogfeed-wrapper"><div class="blogfeed"><h2>Recent News</h2><ul>...</ul></div></div>

      At first glance, Paul’s article seems perfect for what I need to do. His method is to edit ContentQueryMain.xsl to pass in parameters that identify the “current position” and “last row” so that ItemStyle.xsl can put in special code at the start of the list (when current position = 0) and the end of the list (current position = last row). Unfortunately, after following his detailed and clear instructions, I found that it didn’t work for me. I’m not sure if it’s because of a difference in SharePoint 2007 and 2010, but basically what was going on was that the .dfwp-xxxx UL and LIs were still being wrapped around my code. So while Paul’s technique “worked” in the sense that the wrapper code showed up before the first item and after the last item, the other stuff was getting in the way and creating havoc with the code:

      <ul class="dfwp-column dfwp-list" style="100%" ><li class="dfwp-item"><div class="blogfeed-wrapper"><div class="blogfeed"><h2>Recent News</h2><ul><li>...</li></li><li class="dfwp-item"><li>...</li></li><li class="dfwp-item"><li>...</li></ul></div></div></li></ul>

      Diving deep into the ContentQueryMain.xsl file, I was able to locate various variable definitions that hold the HTML code for the UL and LI tags. There were some variables near the top of the file and more inside the OuterTemplate.Body template.

      <xsl:variable name="BeginList" select="string('&lt;ul class=&quot;dfwp-list&quot;&gt;')" /><xsl:variable name="EndList" select="string('&lt;/ul&gt;')" /><xsl:variable name="BeginListItem" select="string('&lt;li class=&quot;dfwp-item&quot;&gt;')" /><xsl:variable name="EndListItem" select="string('&lt;/li&gt;')" /><xsl:template name="OuterTemplate.Body">...<xsl:variable name="BeginColumn1" select="string('&lt;ul class=&quot;dfwp-column dfwp-list&quot; style=&quot;')" /><xsl:variable name="BeginColumn2" select="string('%&quot; &gt;')" /><xsl:variable name="BeginColumn" select="concat($BeginColumn1, $cbq_columnwidth, $BeginColumn2)" /><xsl:variable name="EndColumn" select="string('&lt;/ul&gt;')" />

      If you do a quick search in the code for $BeginList, $EndList, etc., you’ll see that those variables are printed out several times in different places. Not being at all an expert, though, it was pretty hard for me to figure out what was going on, so I resorted to an elegant solution to find the places to target. And by “elegant,” I mean “amateurish and hackish.” If you aren’t too embarrassed to follow my example, here’s what you do…

    8. Go through all of the code, looked for all the instances where those variables are printed out, and add test text before them that will print out in the HTML and show which conditionals were being fulfilled. Here’s one example:
      TEST1<xsl:value of disable-output-escaping="yes" select="$BeginColumn" />

      You’ll want to repeat that for each time you see an <xsl:value /> tag for $BeginList, $EndList, $BeginListItem, $EndListItem, $BeginColumn, and $EndColumn.

      When I saved and refreshed my browser, this is what I saw:

    9. Now you can go through the code, find the places where your test code was added, and replace them with your custom code. Below are the steps that I took, but you’ll need to figure out what will work for you.
      1. My first step was to set up my own custom variables for the wrapper. Inside the OuterTemplate.Body, under the existing variable definitions for BeginColumn1, BeginColumn2, etc., I added this custom code below. Since I didn’t feel like dealing with lots of &lt; and &gt;, I put my HTML code inside a CDATA section:
        <!-- my custom variables for the news section --><xsl:variable name="newsStart"><![CDATA[<div class="blogfeed-wrapper"><div class="blogfeed"><h2>Recent News</h2><ul>]]></xsl:variable><xsl:variable name="newsEnd"><![CDATA[</ul></div></div>]]></xsl:variable>
      2. Okay, NOW I’m ready to replace my “TEST#” stuff with actual useful code. I looked for TEST1 (start of list), TEST9 (start of list item), TEST10 (end of list item), and TEST6 (end of list) in the ContentQueryMain.xsl file. I added <xsl:choose /> and <xsl:when /> statements to put in my custom variables when the Item Style = “News” (the name of my custom item style).Here is the original code (with the first TEST1 stuck in there):
        <xsl:choose>    <xsl:when test="$cbq_isgrouping != 'True'">        <xsl:if test="$CurPosition = $FirstRow">TEST1<xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />        </xsl:if>    </xsl:when>

        And here’s my edited code:

        <xsl:choose>    <xsl:when test="$cbq_isgrouping != 'True'">        <xsl:if test="$CurPosition = $FirstRow">        <!-- customized stuff --><xsl:choose>        <xsl:when test="@Style='News'">        <xsl:value-of disable-output-escaping="yes" select="$newsStart" /></xsl:when><xsl:otherwise><!-- this was the original code --><xsl:value-of disable-output-escaping="yes" select="$BeginColumn" /></xsl:otherwise>        </xsl:choose>        <!-- end customized stuff -->        </xsl:if>    </xsl:when>
      3. I repeated the process for the other sections. Because my <li> and </li> is inside the ItemStyle.xsl file, I didn’t need to define variables for those and left those “when” statements empty.
        <!-- customized stuff --><xsl:choose><xsl:when test="@Style='News'"><xsl:value-of disable-output-escaping="yes" select="$newsEnd" /></xsl:when><xsl:otherwise><!-- this was the original code --><xsl:value-of disable-output-escaping="yes" select="$EndColumn" /></xsl:otherwise></xsl:choose><!-- end customized stuff -->...<xsl:template name="OuterTemplate.CallItemTemplate">    <xsl:param name="CurPosition" />    <xsl:param name="LastRow" />    <!-- customized stuff --><xsl:choose>    <xsl:when test="@Style='News'" /><xsl:otherwise><!-- this was the original code --><xsl:value-of disable-output-escaping="yes" select="$BeginListItem" /></xsl:otherwise>    </xsl:choose>    <!-- end customized stuff -->...<!-- customized stuff --><xsl:choose><xsl:when test="@Style='News'" /><xsl:otherwise><!-- this was the original code --><xsl:value-of disable-output-escaping="yes" select="$EndListItem" /></xsl:otherwise></xsl:choose><!-- end customized stuff -->
      4. And after saving the page, going back to the browser, and refreshing, I finally have my desired result! (Note that the colors and layout are all part of my stylesheet, which I’m not delving into for this article.)

        Here is what the HTML looks like (I took out the URLs and added line breaks for legibility). It’s much cleaner than the original generated HTML and includes the classes that I need to hook in my CSS!
        <div class="blogfeed-wrapper"><div class="blogfeed"><h2>Recent News</h2><ul><li xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"><p class="date"></p><h3><a href="..." title="">New SPDevWiki site released!</a></h3><p class="blurb"></p></li><li xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"><p class="date">8/3/2010</p><p class="image"><a href="..."><img class="image" src=".../image.png" title="" /></a></p><h3><a href="..." title="">SharePoint 2010 SDK released</a></h3><p class="blurb">SharePoint 2010 SDK released for RTM</p></li><li xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"><p class="date">6/4/2010</p><h3><a href="..." title="">Announcing Community Kit for SharePoint</a></h3><p class="blurb">CodePlex projects teams get together to release CKS:Dev!</p></li></ul></div></div>

    Whew! That was really long. Here’s a summary of the steps that I took:

    1. Created a custom “test” Item Style to list out the fields being passed to the web part, which also helped after Step 3 to see if the new fields were added in properly or not.
    2. Figured out the internal column name(s) for the additional field(s) to add to the web part.
    3. Exported the Custom Query Web Part that was on the page, modified the code to add the fields, and imported the modified web part back in and added it to the page.
    4. Changed the Chrome type to “none” to hide the title bar.
    5. Created a custom “News” Item Style and modified the code to get the HTML that I wanted to display for each item.
    6. Hacked ContentQueryMain.xsl to figure out where to modify the code, then added custom code specific to the “News” Item Style for my wrap-around code.

    I definitely appreciate any comments that more experienced SharePoint developers have about how to modify the ContentQueryMain.xsl file more elegantly or other ways to accomplish this! If you have questions, please feel free to post them but remember that I’m new to this as well and may not be able to answer them. ;)

    References and acknowledgements

  • 相关阅读:
    BZOJ 4032: [HEOI2015]最短不公共子串 (dp*3 + SAM)
    后缀自动机详解!
    BZOJ 3926: [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机 多串)
    BZOJ 3938 Robot
    [JSOI2008]Blue Mary开公司
    [ZJOI2017]树状数组
    [JSOI2015]非诚勿扰
    [HNOI2011]任务调度
    BZOJ 3680 吊打XXX
    POJ 3318 Matrix Multiplication
  • 原文地址:https://www.cnblogs.com/frankzye/p/1833422.html
Copyright © 2011-2022 走看看