Customizing ActivityFeed markup

ActivityFeed control uses KnockoutJS framework for client side presentation logic and view rendering.
The control has been designed to allow easy modification of view templates. Below is a snippet ilustrating how various parts of ActivityFeed control markup can be customized. All the templates can use KnockouJS
data binding syntax.

<ow:ActivityFeed runat="server">
    <Template>
         <textarea data-bind="value: newPostText" />
         <button data-bind="command: postUpdate">Post</button>

         <ow:UpdatesPlaceholder runat="server" />

         <button data-bind="command: loadNextPage">Next page</button>
    <Template>

    <UpdateTemplate>
         <ow:UpdateContentPlaceholder runat="server" />

         <ow:CommentsPlaceholder runat="server" />
    </UpdateTemplate>

    <CommentTemplate>
    </CommentTemplate>

    <UpdateContentTemplates>
          <ow:UpdateContentTemplate runat="server" ContentType="post">
          </ow:UpdateContentTemplate>
    </UpdateContentTemplates>
</ow:ActivityFeed>

Template

Template is rendered as a root element of ActivityFeed control. It is bound to ActivityFeedViewModel object.

Default template contains markup to publish new update, refresh updates, search updates and a container for updates list.

<%--Post status updates--%>
<fieldset class="update" 
  data-bind="jQuery: 'fakeInput', css: { disabled: !postUpdate.isInProgress() }">
  <legend class="hidden-visualy">What are you doing?</legend>
  <textarea cols="61" rows="2"
    data-bind="valueExt: newPostText, enable: !postUpdate.isInProgress(), valueUpdate: 'afterkeydown'">
  </textarea>
  <button class="right" data-bind="command: postUpdate">Update</button>
</fieldset>

<%--Refresh updates--%>
<div class="refresh-updates">
  <button data-bind="click: refreshUpdates">Refresh updates</button>
</div>

<%--Search updates--%>
<fieldset class="update search">
  <label for="txtSearch">Search:</label>
  <input id="txtSearch" type="text" class="watermark" 
    data-bind="value: searchTerm, valueUpdate: 'afterkeydown'" 
    title="Write a message...">
  </input>
</fieldset>

<%--Updates placeholder--%>
<af:UpdatesPlaceHolder cssclass="post-list" runat="server"/>

ActivityFeedViewModel is a javascript based object responsible for passing and retrieving data to view.

ActivityFeedViewModel properties:
  • updates - observable array of loaded updates
  • newPostText - text to be posted as a user entered post
  • searchTerm - text to be used for full text filtering of the feed
  • hasMoreUpdates - bool indicating if there is more updates to be loaded (due to page size limit)

ActivityFeedViewModel commands:
  • postUpdate - publish status update
  • loadNextPage - load next package of updates based on pageSize
  • refreshUpdates - refresh list of updates; first page is loaded
  • hasMoreUpdates - used to check if there is more updates on server
  • searchUpdates - filter updates based on searchTerm

UpdatesPlaceholdercontrol - indicates where the list of updates will be rendered. It renders them inside <ul> element.

UpdateTemplate

is used to render each of the updates in UpdatesPlaceholder.

UpdateContentPlaceholder - this is where the update content will be rendered. The template will be selected from UpdateContentTemplates by matching content type.

CommentsPlaceholder

Renders a list of comments for a given update.

<af:CommentsPlaceHolder runat="server" />

CommentTemplate

Renders comment item.

<li>
  <article>
      <footer>
        <figure>
          <img alt="Placeholder image from flickholdr.com" 
            data-bind="attr: { 'src': publisher().profile.photoUrl, 
              'alt': publisher().profile.name }" 
            width="30px" height="30px" />  
        </figure>
         
      </footer>
      <div class="content-wrapper">
      <p><a href="javascript:void(0);" title="palceholder" 
       data-bind='text: publisher().profile.name'></a></p> 
      <p data-bind="text: text"></p>
      </div>
    <div class="utils">
      <ul>
        <!-- ko if: removeComment.isAllowed -->
        <li><a href="javascript:void(0);" title="placeholder" 
          data-bind="command: removeComment, commandConfirm: function () 
                { return confirm('Remove comment?'); }">Delete</a></li>
        <!-- /ko -->
        <li data-bind="attr: { 'title': publishedOn() }">
          <p><time datetime="2012-05-23T12:12+02:00" 
      data-bind="text: moment(publishedOn()).fromNow()"></time></p></li>
      </ul>
        
    </div>
  </article>
</li>  

Update contents templates

Each update content type requires UpdateContentTemplate defined in ActivityFeed control. There is default implementation for 'post' content type.

<af:UpdateContentTemplate runat="server" ID="postTemplate" ContentType="post">
  <div class="content-wrapper postContent">
    <p>
      <a href="javascript:void(0);" title="palceholder" 
          data-bind="text: publisher().profile.name"></a>
    </p>  
    <p data-bind="text: content().text"></p>
  </div>    
</af:UpdateContentTemplate>

To define new update content type template, add new UpdateContentTemplate control as a child of UpdateContentTemplates. UpdateContentTemplate requires ContentType property.

<af:ActivityFeed runat="server" FeedType="Global">
  <UpdateContentTemplates>
    <af:UpdateContentTemplate runat="server" ContentType="contentTypeA">
      ...
    </af:UpdateContentTemplate>
    <af:UpdateContentTemplate runat="server" ContentType="contentTypeShareB">
      ...      
    </af:UpdateContentTemplate>
    <af:UpdateContentTemplate runat="server" ContentType="contentTypeShareC">
      ...      
    </af:UpdateContentTemplate>
  </UpdateContentTemplates>
</af:ActivityFeed>
During rendering ActivityFeed will select update content template based on contentType property of update. When ActivityFeedViewModel will not find content template, then 'Template /Content Type/ not found' text will appear.

Last edited Jul 18, 2012 at 9:59 PM by grzwie, version 26

Comments

No comments yet.