Structured Data Module Walkthrough in Advantage CSP

Overview

Overview

This walkthrough assumes that you understand the basics of the AdvantageModule/Dialog concepts that provided in Module Walkthrough (Dialog Content).  If please refer to that tutorial, as this walkthrough will build upon previous concepts.  In most cases a module using structured content will still require a dialog in order to provide context for front-end expression.

This sample will use a "Blog" article as the typed data source.

AdvantageModuleRewrite is an ASP.net user-control referred to as a "Rewrite Module" that inherit from the specific class.  These controls provide the front-end expression of content.  When working with tool-based "structured content", the information is supplied to the control based on a tool that is registered with the system.

AdvantageModuleRewrite contains all of the functionality of an AdvantageModule

 

The goal of this walkthrough will be to Create a front-end AdvantageModuleRewrite user-control that can used as both a "Blog List" control (when not rewriten) and a "Blog Artilce" control when it has been rewritten.

 


AdvantageModuleRewrite

  • In rewrite mode the information is retrieved from the "MyObject" property that is typed to the generic <T> in the module definition.




Steps Intro

This guide provides a step-by-step walkthrough for creating an "AdvantageModuleRewrite" with an already designed Tool (structure content) object.

1.Create structured content (Advantage Tool)

This sample will use a predefined "BlogArticle" tool.  For instructions for creating a tool see here.

2. Create a class to store dialog attributes

This class will be used to store multiple attributes in a structured format.

3. Develop a Dialog Control

The first step in the process is to create an admin data entry user-control that inherits from AdvantageAttributeControl.

4. Binding information that needs to be passed from Dialog to Module

  • Using the control.ascx file create the html control elements
  • In the control.ascx.cs file complete the methods "LoadDataFromObject(AdvantageAttributeArgs e)" and "SaveDataToObject()" storing/retrieving the "Attributes" information to be passed to the expression module.

5. Retrieving Information for front-end

  • Using the control.ascx file create the html display elements
  • In the control.ascx.cs retrieve the "Attributes" information to be passed from the dialog module for configuration display
  • Based on if the module has been rewritten, show list mode or show detail mode.

6. Create an AdvantageModuleRewrite user-control

The first step in the process is to create a front-end expression user-control that inherits from AdvantageModule.

5.Register the Module/Dialog

The final step in creating an module  is to register within the system. Registration makes the module available for use, linking it with the system's backend and frontend components.

By following these steps—you can effectively set up an AdvantageModule for managing page content.

 



Storing Data - Attributes

Understanding AdvantageAttributes

methods & properties

Passing data between the administrative portal and the front end expression is used via the AdvantageAttributes. 

  • Storing information is done via the "Add" method.  This method is overloaded allowing for native datatypes, as well as any class object that is serializable.
  • Information is retrieved via the "GetAttribute" method.  This method is overloaded allowing for native datatypes, as well as any class object that is serializable.

Create the BlogAttributes class

 

 

Storage Object (Optional)

The attributes from the dialog may be stored directly, however developers may find it coinvent and easier to code if you store to a class.  The class must be serializable to be used.

.cs

namespace AdvantageClient
{


    /// <summary>
    /// provides the construct for passing data from dialog to module
    /// </summary>
    public class BlogAttributes
    {
        public static string Key { get { return "BlogAttributes"; }
        }
        public string LinkTo { get; set; }
        public string Lister { get; set; }

        public string Layout { get; set; }
        public bool ShowImage { get; set; }
        public bool ShowTags { get; set; }
        public string MaxItems { get; set; }
        public bool ShowFilters { get; set; }
        public string Pagination { get; set; }
        public string PerPage { get; set; }
    }
}



Create A Dialog Control

The dialog control provides the data-entry screen for the AdvantageModule front-end display.

Create new User control that inherits from AdvantageAttributeControl

  Add a html binding in the .ascx file.

 

.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ArticleDialog.ascx.cs" Inherits="AdvantageClient.Modules_BlogArticleDialog" %>

<%@ Register Assembly="AdvantageCMS.Web.UI" TagPrefix="Advantage" Namespace="AdvantageCMS.Web.UI" %>
<style>
    .blog-layout-choice { list-style:none; float: left; }
    .blog-layout-choice li {width: 93px; float: left; margin: 0 4px 0 4px; } 
    .blog-layout-choice li input { margin: .5em 0 0 0; }
    .blog-layout-choice li label { margin: 0 0 0 .2em; width: 5em !important; margin-top: 0.4em !important; margin-left: .5em !important; }

    .blog-layout-choice li:first-child { margin-left: 0; }
    .blog-layout-choice li .tile { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUMAAAA2CAYAAABdq/vBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3FpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzI3RTBEMkExQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzI3RTBEMjkxQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmJlMWVhNzQ0LWU4MjUtZTY0My05NTc4LTFkNzJjYzE5MTEzMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4IsgBOAAAE/UlEQVR42uydT0gUURzHnyEF/TMMJC9pUJfKoot1yEPQpRSSOgQWYXYqOnSLLqVdskO3sFNlhEKBQaB1CQzyUpci86SQ7kUxjLY0qIvNb3S22XVmd2bn7czO7OcDi+ub55ud73vzm9/v/db3qpSNracfHjR+bFNg8enni0tpebO8vOxaqaqqCg3RMFIN0U/DGFwV75Txox8BHek2hOwpdCOjIRpGqSH6aRiDhoANYjkRMC/t6aGul24Ha848QkM0jFRD9As+BtcZr04ELMi1AsfREA2j1hD9Ao7BdegDAIAxBADAGAIAYAwBADCGAAAYQwAAjCEAAMYQAABjCACAMQQAyEu19aapsVbduXgYRWwMjk6qwbdTnuujIRpGrSH6Fa9fxhjWbFqvWvbXo5yNsYk5X/XREA2j1hD9itePMBkAAGMIAJATJtv5/HVBjXxIBW786L4dji77nWcfM+87ju1WDXVbPJcLl9v2qm2bNjiec2B0UqXmF9ec30u50Nq8Ux3YtT3wtf9Y+qMGR6dUeulvaJ1p1ywJyDiUECdMDaPE7X5Bw3A0dDSGNx6/9z3X4zh/sXG9Sj09n/n93ZdZ84OOTcxmGZ//sX3h8vGv31c+49lDWeeStpt21RrHF9T49EqdnXWbbX9XuFyMopxr5PbJwNd+5f47LQ8UPzwYnsjSO8503H0Tun7lgCRAxu61o2EEGlaX8kOlf2c/jdpuvVbpoS5XY+OlvPXmK8c60vZwzwnV23XE8biXcvFA7YY30LVH8CTO1bvmzCN9bRv9Fuq1VIgnk4v1YEbD8DWsjtuF6vDa3FjxNg8xeVJG6DTCOh8OkDyqkQBDAgAhG0MdN6dMCMt3qXITBTranpn/ZYYWOhIo5UCcw2S8OQib2H21RpI7kqUtBdKutA8AeIYlxcoml6ptySa7feWGMJlrwMuEsvEMJeNbyratr90AAJS1Z6gDssmVBd4cJNIzBADAM1RkkwEAz1BfKEs2GQDibgwl41vKtmVxBACAsjeGZJMBoFwhm2wPwckmA+AZAgDgGYYE2WQAwDPUFcqSTQaAuHuGfcMTpuclK02fO7bHLJMssLWqtpdyN4bfz2QWdbRWwRZPz244C5XHHVlZHOhDNCxOQ0dj2FHA8Hglt52UYYTEYDUt1Sq1eiz1bTGzurSX8tbmBnOfgzUh+O+/tlWqV4ybGN7slavzl0u79i0BgiB71/Y+/xjqasOXW/clZkD3XW0xl6yXfqqc/TvqzX1s0DAaDR2NoXhh5zQZRDtOS++7ncut/Eqb8w3vVF/m/pyyz27lOlfUkXMMXj/OY7pIZE5Y+tqtvwENdUM2GQDAzTNMwgrJAJUO97EGYwh6sBJGgt/9of2We0kyoeHacrf26T88Q7w5jdgnrv3uD+23/KiqR8Miy53aT0L/cR8TJpcNbgmUIPtG5ytP4tYHpdYwX5Ir7v3HfewPEiglQgb2wOhkqOdM2mIVUWgYJSw2Qpic0PBuzgyDmAdCw6jgPsYzBADQ4xlCcCQ7aP7nDJ5ArDTEk8MYgmbM0I7wDg0hfmFyan6RZfNzGJ9e8FUfDfVoWKm4bV3hR0PGYPFjUDzDfuPVLQsjNFwYQDln+j0cR0NNGrJXclEaMgYDjkHxDGeMVyc65RXwSYE6aIiGUWuIfgHHoDVnKJXeGq9GNMtienWQeQEN0TBqDdEvgH7/BBgAFqwscR94x34AAAAASUVORK5CYII=) no-repeat 0 0; width: 75px; height: 55px; display: inline-block; }
    .blog-layout-choice li .listing { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUMAAAA2CAYAAABdq/vBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3FpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzI3RTBEMkExQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzI3RTBEMjkxQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmJlMWVhNzQ0LWU4MjUtZTY0My05NTc4LTFkNzJjYzE5MTEzMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4IsgBOAAAE/UlEQVR42uydT0gUURzHnyEF/TMMJC9pUJfKoot1yEPQpRSSOgQWYXYqOnSLLqVdskO3sFNlhEKBQaB1CQzyUpci86SQ7kUxjLY0qIvNb3S22XVmd2bn7czO7OcDi+ub55ud73vzm9/v/db3qpSNracfHjR+bFNg8enni0tpebO8vOxaqaqqCg3RMFIN0U/DGFwV75Txox8BHek2hOwpdCOjIRpGqSH6aRiDhoANYjkRMC/t6aGul24Ha848QkM0jFRD9As+BtcZr04ELMi1AsfREA2j1hD9Ao7BdegDAIAxBADAGAIAYAwBADCGAAAYQwAAjCEAAMYQAABjCACAMQQAyEu19aapsVbduXgYRWwMjk6qwbdTnuujIRpGrSH6Fa9fxhjWbFqvWvbXo5yNsYk5X/XREA2j1hD9itePMBkAAGMIAJATJtv5/HVBjXxIBW786L4dji77nWcfM+87ju1WDXVbPJcLl9v2qm2bNjiec2B0UqXmF9ec30u50Nq8Ux3YtT3wtf9Y+qMGR6dUeulvaJ1p1ywJyDiUECdMDaPE7X5Bw3A0dDSGNx6/9z3X4zh/sXG9Sj09n/n93ZdZ84OOTcxmGZ//sX3h8vGv31c+49lDWeeStpt21RrHF9T49EqdnXWbbX9XuFyMopxr5PbJwNd+5f47LQ8UPzwYnsjSO8503H0Tun7lgCRAxu61o2EEGlaX8kOlf2c/jdpuvVbpoS5XY+OlvPXmK8c60vZwzwnV23XE8biXcvFA7YY30LVH8CTO1bvmzCN9bRv9Fuq1VIgnk4v1YEbD8DWsjtuF6vDa3FjxNg8xeVJG6DTCOh8OkDyqkQBDAgAhG0MdN6dMCMt3qXITBTranpn/ZYYWOhIo5UCcw2S8OQib2H21RpI7kqUtBdKutA8AeIYlxcoml6ptySa7feWGMJlrwMuEsvEMJeNbyratr90AAJS1Z6gDssmVBd4cJNIzBADAM1RkkwEAz1BfKEs2GQDibgwl41vKtmVxBACAsjeGZJMBoFwhm2wPwckmA+AZAgDgGYYE2WQAwDPUFcqSTQaAuHuGfcMTpuclK02fO7bHLJMssLWqtpdyN4bfz2QWdbRWwRZPz244C5XHHVlZHOhDNCxOQ0dj2FHA8Hglt52UYYTEYDUt1Sq1eiz1bTGzurSX8tbmBnOfgzUh+O+/tlWqV4ybGN7slavzl0u79i0BgiB71/Y+/xjqasOXW/clZkD3XW0xl6yXfqqc/TvqzX1s0DAaDR2NoXhh5zQZRDtOS++7ncut/Eqb8w3vVF/m/pyyz27lOlfUkXMMXj/OY7pIZE5Y+tqtvwENdUM2GQDAzTNMwgrJAJUO97EGYwh6sBJGgt/9of2We0kyoeHacrf26T88Q7w5jdgnrv3uD+23/KiqR8Miy53aT0L/cR8TJpcNbgmUIPtG5ytP4tYHpdYwX5Ir7v3HfewPEiglQgb2wOhkqOdM2mIVUWgYJSw2Qpic0PBuzgyDmAdCw6jgPsYzBADQ4xlCcCQ7aP7nDJ5ArDTEk8MYgmbM0I7wDg0hfmFyan6RZfNzGJ9e8FUfDfVoWKm4bV3hR0PGYPFjUDzDfuPVLQsjNFwYQDln+j0cR0NNGrJXclEaMgYDjkHxDGeMVyc65RXwSYE6aIiGUWuIfgHHoDVnKJXeGq9GNMtienWQeQEN0TBqDdEvgH7/BBgAFqwscR94x34AAAAASUVORK5CYII=) no-repeat -81px 0; width: 75px; height: 55px; display: inline-block; }
    .blog-layout-choice li .image-tile { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUMAAAA2CAYAAABdq/vBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3FpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzI3RTBEMkExQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzI3RTBEMjkxQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmJlMWVhNzQ0LWU4MjUtZTY0My05NTc4LTFkNzJjYzE5MTEzMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4IsgBOAAAE/UlEQVR42uydT0gUURzHnyEF/TMMJC9pUJfKoot1yEPQpRSSOgQWYXYqOnSLLqVdskO3sFNlhEKBQaB1CQzyUpci86SQ7kUxjLY0qIvNb3S22XVmd2bn7czO7OcDi+ub55ud73vzm9/v/db3qpSNracfHjR+bFNg8enni0tpebO8vOxaqaqqCg3RMFIN0U/DGFwV75Txox8BHek2hOwpdCOjIRpGqSH6aRiDhoANYjkRMC/t6aGul24Ha848QkM0jFRD9As+BtcZr04ELMi1AsfREA2j1hD9Ao7BdegDAIAxBADAGAIAYAwBADCGAAAYQwAAjCEAAMYQAABjCACAMQQAyEu19aapsVbduXgYRWwMjk6qwbdTnuujIRpGrSH6Fa9fxhjWbFqvWvbXo5yNsYk5X/XREA2j1hD9itePMBkAAGMIAJATJtv5/HVBjXxIBW786L4dji77nWcfM+87ju1WDXVbPJcLl9v2qm2bNjiec2B0UqXmF9ec30u50Nq8Ux3YtT3wtf9Y+qMGR6dUeulvaJ1p1ywJyDiUECdMDaPE7X5Bw3A0dDSGNx6/9z3X4zh/sXG9Sj09n/n93ZdZ84OOTcxmGZ//sX3h8vGv31c+49lDWeeStpt21RrHF9T49EqdnXWbbX9XuFyMopxr5PbJwNd+5f47LQ8UPzwYnsjSO8503H0Tun7lgCRAxu61o2EEGlaX8kOlf2c/jdpuvVbpoS5XY+OlvPXmK8c60vZwzwnV23XE8biXcvFA7YY30LVH8CTO1bvmzCN9bRv9Fuq1VIgnk4v1YEbD8DWsjtuF6vDa3FjxNg8xeVJG6DTCOh8OkDyqkQBDAgAhG0MdN6dMCMt3qXITBTranpn/ZYYWOhIo5UCcw2S8OQib2H21RpI7kqUtBdKutA8AeIYlxcoml6ptySa7feWGMJlrwMuEsvEMJeNbyratr90AAJS1Z6gDssmVBd4cJNIzBADAM1RkkwEAz1BfKEs2GQDibgwl41vKtmVxBACAsjeGZJMBoFwhm2wPwckmA+AZAgDgGYYE2WQAwDPUFcqSTQaAuHuGfcMTpuclK02fO7bHLJMssLWqtpdyN4bfz2QWdbRWwRZPz244C5XHHVlZHOhDNCxOQ0dj2FHA8Hglt52UYYTEYDUt1Sq1eiz1bTGzurSX8tbmBnOfgzUh+O+/tlWqV4ybGN7slavzl0u79i0BgiB71/Y+/xjqasOXW/clZkD3XW0xl6yXfqqc/TvqzX1s0DAaDR2NoXhh5zQZRDtOS++7ncut/Eqb8w3vVF/m/pyyz27lOlfUkXMMXj/OY7pIZE5Y+tqtvwENdUM2GQDAzTNMwgrJAJUO97EGYwh6sBJGgt/9of2We0kyoeHacrf26T88Q7w5jdgnrv3uD+23/KiqR8Miy53aT0L/cR8TJpcNbgmUIPtG5ytP4tYHpdYwX5Ir7v3HfewPEiglQgb2wOhkqOdM2mIVUWgYJSw2Qpic0PBuzgyDmAdCw6jgPsYzBADQ4xlCcCQ7aP7nDJ5ArDTEk8MYgmbM0I7wDg0hfmFyan6RZfNzGJ9e8FUfDfVoWKm4bV3hR0PGYPFjUDzDfuPVLQsjNFwYQDln+j0cR0NNGrJXclEaMgYDjkHxDGeMVyc65RXwSYE6aIiGUWuIfgHHoDVnKJXeGq9GNMtienWQeQEN0TBqDdEvgH7/BBgAFqwscR94x34AAAAASUVORK5CYII=) no-repeat -162px 0; width: 75px; height: 55px; display: inline-block;}
    .blog-layout-choice li .full { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUMAAAA2CAYAAABdq/vBAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3FpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzI3RTBEMkExQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzI3RTBEMjkxQjc5MTFFNjg1MjFGQTBBQkIxRDFBN0QiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOmJlMWVhNzQ0LWU4MjUtZTY0My05NTc4LTFkNzJjYzE5MTEzMCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo2MWJjZmRhOS04NWRmLTZhNDQtYmJmMy01YjQ5YWY1MTRmZjQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4IsgBOAAAE/UlEQVR42uydT0gUURzHnyEF/TMMJC9pUJfKoot1yEPQpRSSOgQWYXYqOnSLLqVdskO3sFNlhEKBQaB1CQzyUpci86SQ7kUxjLY0qIvNb3S22XVmd2bn7czO7OcDi+ub55ud73vzm9/v/db3qpSNracfHjR+bFNg8enni0tpebO8vOxaqaqqCg3RMFIN0U/DGFwV75Txox8BHek2hOwpdCOjIRpGqSH6aRiDhoANYjkRMC/t6aGul24Ha848QkM0jFRD9As+BtcZr04ELMi1AsfREA2j1hD9Ao7BdegDAIAxBADAGAIAYAwBADCGAAAYQwAAjCEAAMYQAABjCACAMQQAyEu19aapsVbduXgYRWwMjk6qwbdTnuujIRpGrSH6Fa9fxhjWbFqvWvbXo5yNsYk5X/XREA2j1hD9itePMBkAAGMIAJATJtv5/HVBjXxIBW786L4dji77nWcfM+87ju1WDXVbPJcLl9v2qm2bNjiec2B0UqXmF9ec30u50Nq8Ux3YtT3wtf9Y+qMGR6dUeulvaJ1p1ywJyDiUECdMDaPE7X5Bw3A0dDSGNx6/9z3X4zh/sXG9Sj09n/n93ZdZ84OOTcxmGZ//sX3h8vGv31c+49lDWeeStpt21RrHF9T49EqdnXWbbX9XuFyMopxr5PbJwNd+5f47LQ8UPzwYnsjSO8503H0Tun7lgCRAxu61o2EEGlaX8kOlf2c/jdpuvVbpoS5XY+OlvPXmK8c60vZwzwnV23XE8biXcvFA7YY30LVH8CTO1bvmzCN9bRv9Fuq1VIgnk4v1YEbD8DWsjtuF6vDa3FjxNg8xeVJG6DTCOh8OkDyqkQBDAgAhG0MdN6dMCMt3qXITBTranpn/ZYYWOhIo5UCcw2S8OQib2H21RpI7kqUtBdKutA8AeIYlxcoml6ptySa7feWGMJlrwMuEsvEMJeNbyratr90AAJS1Z6gDssmVBd4cJNIzBADAM1RkkwEAz1BfKEs2GQDibgwl41vKtmVxBACAsjeGZJMBoFwhm2wPwckmA+AZAgDgGYYE2WQAwDPUFcqSTQaAuHuGfcMTpuclK02fO7bHLJMssLWqtpdyN4bfz2QWdbRWwRZPz244C5XHHVlZHOhDNCxOQ0dj2FHA8Hglt52UYYTEYDUt1Sq1eiz1bTGzurSX8tbmBnOfgzUh+O+/tlWqV4ybGN7slavzl0u79i0BgiB71/Y+/xjqasOXW/clZkD3XW0xl6yXfqqc/TvqzX1s0DAaDR2NoXhh5zQZRDtOS++7ncut/Eqb8w3vVF/m/pyyz27lOlfUkXMMXj/OY7pIZE5Y+tqtvwENdUM2GQDAzTNMwgrJAJUO97EGYwh6sBJGgt/9of2We0kyoeHacrf26T88Q7w5jdgnrv3uD+23/KiqR8Miy53aT0L/cR8TJpcNbgmUIPtG5ytP4tYHpdYwX5Ir7v3HfewPEiglQgb2wOhkqOdM2mIVUWgYJSw2Qpic0PBuzgyDmAdCw6jgPsYzBADQ4xlCcCQ7aP7nDJ5ArDTEk8MYgmbM0I7wDg0hfmFyan6RZfNzGJ9e8FUfDfVoWKm4bV3hR0PGYPFjUDzDfuPVLQsjNFwYQDln+j0cR0NNGrJXclEaMgYDjkHxDGeMVyc65RXwSYE6aIiGUWuIfgHHoDVnKJXeGq9GNMtienWQeQEN0TBqDdEvgH7/BBgAFqwscR94x34AAAAASUVORK5CYII=) no-repeat -243px 0; width: 75px; height: 55px; display: inline-block; }
</style>



    <fieldset>
        <legend>Paths</legend>

        <div class="form-row">                               
            <label>Detail Page</label>
            <telerik:RadTextBox runat="server" ID="tbLink" />                           
            <p class="no-label control">(leave blank to link to self)</p>
        </div>


        <div class="form-row">                      
            <label>List Page</label>
            <telerik:RadTextBox runat="server" ID="tbLister" />            
            <p class="no-label control">(leave blank to link to self)</p>            
        </div>
    </fieldset>

    <fieldset>
        <legend>List Settings</legend>
    
        <div class="form-row checkedLabels">
            <label>Layout</label>                
            <asp:RadioButtonList ID="rblLayout" runat="server"  RepeatLayout="UnorderedList" CssClass="blog-layout-choice">
                <asp:ListItem Text="Tile" Value="tile" Title="Tile layout"><span class="tile"></span></asp:ListItem>
                <asp:ListItem Text="Listing" Value="listing" Title="Listing layout"><span class="listing"></span></asp:ListItem>
                <asp:ListItem Text="Image Tile" Value="image-tile" Title="Full image tile layout"><span class="image-tile"></span></asp:ListItem>
                <asp:ListItem Text="Full" Value="full" Title="Full width listing layout"><span class="full"></span></asp:ListItem>
            </asp:RadioButtonList>
        </div>        


        <div class="form-row">
            <label>Show Image</label>                 
            <Advantage:AdvantageCheckBox runat="server" id="cbImage" />                
        </div>

        <div class="form-row">
            <label>Show Tags</label>
            <Advantage:AdvantageCheckBox runat="server" id="cbTags" />
        </div>

        <div class="form-row">
            <label>Show Applied Filters</label>
            <Advantage:AdvantageCheckBox runat="server" id="cbFilters" />
        </div>
        
        <div class="form-row">
                                
            <label>Max Items To Show</label>
            <telerik:RadDropDownList ID="ddlMaxItems" runat="server">
                <Items>
                    <telerik:DropDownListItem Text="All" />
                    <telerik:DropDownListItem Text="3" Value="3" />
                    <telerik:DropDownListItem Text="5" Value="5" />
                    <telerik:DropDownListItem Text="10" Value="10" />
                    <telerik:DropDownListItem Text="20" Value="20" />
                    <telerik:DropDownListItem Text="50" Value="50" />
                </Items>
            </telerik:RadDropDownList>            
        </div>
     </fieldset>   

    <fieldset>
        <legend>Pagination Settings</legend>

        <div class="form-row">
            <label>Scrolling or Paging</label>
            <asp:RadioButtonList runat="server" ID="rdPagination" AutoPostBack="true">
                <asp:ListItem Text="Infinite Scroll" Value="infinite" />
                <asp:ListItem Text="Paging" Value="paging"  />
            </asp:RadioButtonList>                            
        </div>
               
        <asp:PlaceHolder runat="server" ID="phPaginationEntries">
            <div class="form-row">                
                <label>Entries Per Page</label>
                <telerik:RadDropDownList ID="ddlPerPage" runat="server">
                    <Items>
                        <telerik:DropDownListItem Text="All" />
                        <telerik:DropDownListItem Text="3" Value="3" />
                        <telerik:DropDownListItem Text="5" Value="5" />
                        <telerik:DropDownListItem Text="10" Value="10" />
                        <telerik:DropDownListItem Text="20" Value="20" />
                        <telerik:DropDownListItem Text="50" Value="50" />
                    </Items>
                </telerik:RadDropDownList>            
            </div>        
        </asp:PlaceHolder>
   </fieldset>

Bind html control content to the attributes.

.ascx.cs

namespace AdvantageClient
{

    public partial class Modules_BlogArticleDialog : AdvantageAttributeControl
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            rdPagination.SelectedIndexChanged += RdPagination_SelectedIndexChanged;
        }

        private void RdPagination_SelectedIndexChanged(object sender, EventArgs e)
        {
            phPaginationEntries.Visible = rdPagination.SelectedValue == "paging";
        }

        protected override void SaveDataToObject()
        { 
           //save to attributes/content...
           var attribs = new BlogAttributes();
           attribs.LinkTo= tbLink.Text;
           attribs.Lister=tbLister.Text;

           attribs.layout=rblLayout.SelectedValue;
           attribs.ShowImage=cbImage.Checked;
           attribs.ShowTags=cbTags.Checked;
           attribs.MaxItems=ddlMaxItems.SelectedValue;
           attribs.ShowFilters=cbFilters.Checked;


           attribs.Pagination=rdPagination.SelectedValue;
           attribs.PerPage=ddlPerPage.SelectedValue;
           Attributes.Add(BlogAttributes.Key, attribs);



        }

        protected override void LoadDataFromObject(AdvantageAttributeArgs e)
        {

            //Load or initialize the Attributes storage class
            var attribs = Attributes.GetAttribute<BlogAttributes>(BlogAttributes.Key);
            if (attribs == null) attribs = new BlogAttributes();

            
            //load screen with attributes/content.....

            tbLink.Text = attribs.LinkTo;
            tbLister.Text = attribs.Lister;

            rblLayout.SelectedValue = attribs.layout;
            cbImage.Checked = attribs.ShowImage;
            cbTags.Checked = attribs.ShowTags;
            cbFilters.Checked = attribs.ShowFilters;
            try
            {
                ddlPerPage.SelectedValue = attribs.PerPage;
            }
            catch
            {
                ddlPerPage.SelectedIndex = 0;
            }

            try
            {
                ddlMaxItems.SelectedValue = attribs.MaxItems;
            }
            catch
            {
                ddlMaxItems.SelectedIndex = 0;
            }

            try
            {
                rdPagination.SelectedValue = attribs.Pagination;
                phPaginationEntries.Visible = rdPagination.SelectedValue == "paging";
            }
            catch
            {
                rdPagination.SelectedValue = "paging";
                phPaginationEntries.Visible = true;
            }
        }

    }
}





Create AdvantageModuleRewrite

The module control retrieves data set in the dialog and provides the front-end display.

Create new User control that inherits from AdvantageModuleRewrite

This control has dual modes. 

  • When the system detects that it has been "rewritten" based on the url SEOName, it will display the single article view panel.
  • When it has not been rewritten, it will display the list view of articles.  The list view uses an associated usercontrol that formats the tile.  

 

 

ascx file

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Article.ascx.cs" Inherits="AdvantageClient.Modules_BlogArticle" %>

<!--Control that formats the listing article -->
<%@ Register Src="BlogArticleListing.ascx" TagPrefix="advantage" TagName="BlogArticleListing" %>


<asp:Panel CssClass="blog " runat="server" id="pnlBlog"> <!-- To change layout, use different classes next to .blog: tile, image-tile, listing -->

    <!-- When this control has NOT been rewritten, it will be a Blog Listing -->
    <asp:PlaceHolder runat="server" ID="phListing">
    
        <asp:Literal runat="server" ID="litFilter"></asp:Literal>
        <asp:Literal runat="server" ID="litNoPosts"></asp:Literal>

        <asp:UpdatePanel runat="server" ID="upBlogPosts" ChildrenAsTriggers="true" UpdateMode="Conditional">
             <ContentTemplate>
                 
                <%-- Listing View --%>
                 <asp:Repeater runat="server" ID="rptBlogList">                
                    <ItemTemplate>
						<article class="listing">
                        	<advantage:BlogArticleListing runat="server" 
                                Article='<%# (BlogArticle)Container.DataItem %>' 
                                ListPath='<%# ObjectAttributes.Lister%>' 
                                DetailPath='<%# ObjectAttributes.LinkTo %>' 
                                ShowComments='False'
                                ShowImage='<%# ObjectAttributes.ShowImage %>'    
                            />
						</article>
                    </ItemTemplate>                             
                </asp:Repeater>
                 <asp:HiddenField runat="server" ID="hdnMaxPage" Value="1" />
                <asp:HiddenField runat="server" ID="hdnCurrentPage" Value="1" />
                <asp:HiddenField runat="server" ID="hdnPageCount" Value="1" />
                <div style="display: none">
                    <asp:Button runat="server" ID="btnPaging" />
                </div>
            </ContentTemplate>
        </asp:UpdatePanel>

        <!-- Pager -->
        <asp:PlaceHolder ID="plcPager" runat="server" Visible="false">
            <asp:Repeater ID="rptPager" runat="server" OnItemDataBound="rptPager_ItemDataBound">

                <HeaderTemplate>
                    <ul class="pagination clearfix">
                        <li>
                            <asp:HyperLink Text="Prev" ID="hlPrev" CssClass="prev collapse" runat="server" NavigateUrl="javascript:void(0);" onclick="lnkPrev();" />
                        </li>
                </HeaderTemplate>

                <ItemTemplate>                
                    <asp:PlaceHolder ID="plc" runat="server" Visible='<%# Container.ItemIndex % PageSize == 0 %>'>
                        <li>
                            <asp:HyperLink ID="hlLink" runat="server" NavigateUrl="javascript:void(0);" />
                        </li>
                    </asp:PlaceHolder>
                </ItemTemplate>

                <FooterTemplate>                
                        <li>
                            <asp:HyperLink Text="Next" CssClass="next" ID="hlNext" onclick="lnkNext();" runat="server" NavigateUrl="javascript:void(0);" />
                        </li>
                    </ul>								    
                </FooterTemplate>
            </asp:Repeater>
        </asp:PlaceHolder>
    </asp:PlaceHolder>
    
    <!-- When this control HAS been rewritten, Detail View -->
    <asp:PlaceHolder runat="server" ID="phSinglePost" Visible="false">
        <asp:HyperLink runat="server" ID ="hlURL">Return</asp:HyperLink> 
        
        <article class="detail">
            
            <advantage:AdvantageDisplayImage runat="server" ID="picDetail" DefaultImage="Detail" />

            <section class="main">
                <h1><%= MyObject.Title %></h1>

                <time><%= MyObject.ArticleDate %></time>

                <div class="category">
                    <asp:HyperLink runat="server" ID="hlCategory"></asp:HyperLink>
                </div>
		
                <asp:PlaceHolder ID="phSummary" runat="server">
                    <p><%= MyObject.Summary %></p>
                </asp:PlaceHolder>

                <asp:PlaceHolder ID="phContent" runat="server">
                    <%= MyObject.Content %>
                </asp:PlaceHolder>
            </section>

            <asp:Repeater runat="server" ID="rptTags">
                <HeaderTemplate>
                    <section class="tags">
                        <ul>
                </HeaderTemplate>

                <ItemTemplate>
                            <a href='<%# CurrentNavigationPage.FullUrl + "?tag=" + System.Net.WebUtility.UrlEncode(Container.DataItem.ToString()) %>'>#<%# Container.DataItem %></a>
                </ItemTemplate>

                <FooterTemplate>
                        </ul>
                    </section>
                </FooterTemplate>
            </asp:Repeater>

        </article>
    </asp:PlaceHolder>
</asp:Panel>

<!--Registering bottom scripts -->
<asp:PlaceHolder id="phBottomJavascriptBlog" runat="server">
    <script>

        $(window).load(function () {
            blogLoadResize();
        });
        // this function is also called from the resize event in base-function.js

        blogLoadResize = function () {            
            equalHeight('.blog.tile div article');
        };


        function lnkClick(i) {
            $('.pagination li a').removeClass('current');
            $('.pagination li a[data-index=' + i + ']').addClass('current');

            $('.next').removeClass("collapse");
            $('.prev').removeClass("collapse");

            $('#<%= hdnCurrentPage.ClientID %>').val(i);

            if (parseInt($('#<%= hdnCurrentPage.ClientID %>').val()) >= parseInt($('#<%= hdnPageCount.ClientID %>').val())) {
                $('.next').addClass("collapse");
            }
            if (parseInt($('#<%= hdnCurrentPage.ClientID %>').val()) <= 1) {
                $('.prev').addClass("collapse");
            }
            

            $('#<%= btnPaging.ClientID %>').click();
        }

        function lnkPrev() {

            var prev = parseInt($('#<%= hdnCurrentPage.ClientID %>').val()) - 1;

            if (prev > 0) lnkClick(prev);
            else lnkClick(0);
        }

        function lnkNext() {
            var next = parseInt($('#<%= hdnCurrentPage.ClientID %>').val()) + 1;
            lnkClick(next);
        }
    </script>
    
    <!--Allow for infinit scrolling -->
    <asp:PlaceHolder id="phInfiniteScroll" runat="server" Visible="false">
    <script type="text/javascript">    
        function pageLoad(sender, args) {
            
            if ($('#<%= hdnCurrentPage.ClientID %>').val() <= $('#<%= hdnMaxPage.ClientID %>').val()) {
            if ($(document).height() <= $(window).height()) {                                
                    __doPostBack('<%= upBlogPosts.UniqueID %>', "ScrollOn");
                }            
            }

            $(window).scroll(function () {            
                if ($(window).scrollTop() == $(document).height() - $(window).height()) {
                
                    if ($('#<%= hdnCurrentPage.ClientID %>').val() <= $('#<%= hdnMaxPage.ClientID %>').val()) {
                        __doPostBack('<%= upBlogPosts.UniqueID %>', "ScrollOn");
                    }            
                }
            });

            blogLoadResize();
        };
    </script>
    </asp:PlaceHolder>
</asp:PlaceHolder>       



Bind  attributes to the html control content.

ascx.cs file

namespace AdvantageClient
{

    public partial class Modules_BlogArticle : AdvantageModuleRewrite<BlogArticle>
    {
        #region Properties

        protected BlogAttributes ObjectAttributes;
        protected int PageSize = 10;
        private readonly List<string> filters = new();

        private List<BlogArticle> blogPosts;

        protected List<BlogArticle> BlogPosts
        {
            get
            {
                //If null, get list from cache.
                blogPosts ??= ModuleEngine.WebCache_Get<List<BlogArticle>>("BlogArticleList");

                //If still null, get list from database and cache it for 30 minutes.
                if (blogPosts == null)
                {
                    blogPosts = ModuleEngine.GetAllPublishedObjects<BlogArticle>().OrderByDescending(o => o.ArticleDate)
                        .ToList();
                    ModuleEngine.WebCache_Store("BlogArticleList", "Blog", blogPosts, 30, HttpContext.Current);
                }

                //There are no posts, return empty list
                if (blogPosts == null)
                {
                    blogPosts = new List<BlogArticle>();
                    return blogPosts;
                }

                //Apply any filters
                blogPosts = ApplyFilters(blogPosts);

                return blogPosts;
            }
        }

        private List<BlogArticle> ApplyFilters(List<BlogArticle> blogPosts)
        {
            //If there is a max items attribute, take that many items
            if (ObjectAttributes.MaxItems.ToInteger(0) > 0)
                blogPosts = blogPosts.Take(int.Parse(ObjectAttributes.MaxItems)).ToList();


            if (Request.QueryString["year"] != null)
            {
                filters.Add("Year");
                var year = WebUtility.UrlDecode(Request.QueryString["year"]);
                blogPosts = blogPosts.Where(p => p.ArticleDate.Year.Equals(Convert.ToInt16(year))).ToList();
            }


            if (Request.QueryString["month"] != null)
            {
                filters.Add("Month");
                var month = WebUtility.UrlDecode(Request.QueryString["month"]);
                blogPosts = blogPosts.Where(p => p.ArticleDate.Month.Equals(Convert.ToInt16(month))).ToList();
            }


            if (Request.QueryString["tag"] != null)
            {
                filters.Add("Tag");
                var tag = WebUtility.UrlDecode(Request.QueryString["tag"]);
                blogPosts = blogPosts.Where(p => p.Tags.Contains(tag)).ToList();
            }

            if (Request.QueryString["cat"] != null)
            {
                filters.Add("Category");
                var cat = WebUtility.UrlDecode(Request.QueryString["cat"]);

                var bc = ModuleEngine
                    .GetPublishedObjectsBykey<BlogCategory>("SEOName",
                        eComparison.Equals, cat).FirstOrDefault();

                if (bc != null) blogPosts = blogPosts.Where(p => p.Category.Equals(bc.MasterID)).ToList();
            }

            return blogPosts;
        }

        #endregion

        #region Page Events

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            btnPaging.Click += btnPaging_Click;
            //Load or initialize the object attribute
            ObjectAttributes = Attributes.GetAttribute<BlogAttributes>(BlogAttributes.Key)
                               ?? new BlogAttributes();
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            InjectJavascriptIntoContentPlaceHolder();

            if (IsReWrite)
            {
                //single article view
                phListing.Visible = false;
                phSinglePost.Visible = true;

                setOpenGraphTags();

                hlURL.NavigateUrl = !string.IsNullOrWhiteSpace(ObjectAttributes.Lister)
                    ? ObjectAttributes.Lister
                    : CurrentNavigationPage.FullUrl;

                picDetail.AdvantageImage = MyObject.ArticleImage;

                if (ObjectAttributes.ShowTags)
                {
                    rptTags.DataSource = MyObject.Tags;
                    rptTags.DataBind();
                }
            }
            else
            {
                //lister view
                pnlBlog.CssClass += $" {ObjectAttributes.Layout}";

                var itemsPerPage = ObjectAttributes.PerPage;
                if (string.IsNullOrWhiteSpace(itemsPerPage) || itemsPerPage == "ALL") PageSize = 10;
                else PageSize = Convert.ToInt32(itemsPerPage);


                hdnPageCount.Value = (BlogPosts.Count / PageSize + 1).ToString();

                if (!IsPostBack)
                {
                    rebindPosts();
                }
                else
                {
                    //infinite scroll
                    var passedArgument = Request.Params.Get("__EVENTARGUMENT");
                    if (passedArgument == "ScrollOn")
                    {
                        ScrollOn();
                        upBlogPosts.Update();
                    }
                }

                //display the applied filters
                if (filters.Count > 0 && ObjectAttributes.ShowFilters)
                    litFilter.Text = string.Format("<p>You are currently filtering by : {0}</p>",
                        string.Join(", ", filters.ToArray()));
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            //set the page title on single article 
            if (IsReWrite) Page.Title = string.Format("{0} | {1}", Page.Title, MyObject.Title);

            base.OnPreRender(e);
        }

        #endregion

        #region Events

        private void btnPaging_Click(object sender, EventArgs e)
        {
            var t = Convert.ToInt32(hdnCurrentPage.Value);

            if (t > 0) t = t - 1;

            rptBlogList.DataSource = BlogPosts.Skip(t * PageSize).Take(PageSize);
            rptBlogList.DataBind();
            upBlogPosts.Update();
        }

        public void rptPager_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if ((e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) &&
                e.Item.ItemIndex % PageSize == 0)
            {
                var hlLink = (HyperLink) e.Item.FindControl("hlLink");
                hlLink.Text = string.Format("{0:0}", Math.Floor(e.Item.ItemIndex / (double) PageSize) + 1);
                hlLink.Attributes.Add("data-index",
                    (Math.Floor(e.Item.ItemIndex / (double) PageSize) + 1).ToString());


                if (hlLink.Text == "1")
                    hlLink.CssClass = "paging" + e.Item.ItemIndex + hlLink.Text + " current";
                else
                    hlLink.CssClass = "paging" + e.Item.ItemIndex + hlLink.Text;

                hlLink.Attributes["onclick"] = string.Format("lnkClick({0:0})",
                    Math.Floor(e.Item.ItemIndex / (double) PageSize) + 1);
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        ///     Open Graph tags for Social  Share. When shared site will scrape these details for the share text
        /// </summary>
        private void setOpenGraphTags()
        {
            var ogTitle = new HtmlMeta();
            ogTitle.Attributes["property"] = "og:title";
            ogTitle.Attributes["content"] = string.Format("{0}", MyObject.Title);

            var ogType = new HtmlMeta();
            ogType.Attributes["property"] = "og:type";
            ogType.Attributes["content"] = "website";

            //don't add an image tag if it is not set or errors
            try
            {
                var ogImage = new HtmlMeta();
                ogImage.Attributes["property"] = "og:image";

                if (!string.IsNullOrEmpty(MyObject.ArticleImage.GetImageElementByName("Thumbnail").ImageUrl))
                {
                    ogImage.Attributes["content"] = string.Format("http://{0}{1}", Request.Url.Host,
                        MyObject.ArticleImage.GetImageElementByName("Thumbnail").ImageUrl);
                    Page.Header.Controls.Add(ogImage);
                }
                else if (!string.IsNullOrEmpty(MyObject.ArticleImage.GetImageElementByName("Desktop").ImageUrl))
                {
                    ogImage.Attributes["content"] = string.Format("http://{0}{1}", Request.Url.Host,
                        MyObject.ArticleImage.GetImageElementByName("Thumbnail").ImageUrl);
                    Page.Header.Controls.Add(ogImage);
                }
            }
            catch
            {
                //don't add an image tag
            }

            var ogUrl = new HtmlMeta();
            ogUrl.Attributes["property"] = "og:url";
            ogUrl.Attributes["content"] = string.Format("http://{0}{1}", Request.Url.Host, Request.RawUrl);

            var ogDescription = new HtmlMeta();
            ogDescription.Attributes["property"] = "og:description";
            if (!string.IsNullOrEmpty(MyObject.Summary))
                ogDescription.Attributes["content"] = MyObject.Summary.Replace('\n', ' ').Replace('\r', ' ');

            Page.Header.Controls.Add(ogTitle);
            Page.Header.Controls.Add(ogType);

            Page.Header.Controls.Add(ogUrl);
            Page.Header.Controls.Add(ogDescription);
        }

        private void rebindPosts()
        {
            if (BlogPosts != null && BlogPosts.Count > 0)
            {
                rptBlogList.DataSource = BlogPosts.Take(PageSize);
                rptBlogList.DataBind();

                rptPager.DataSource = BlogPosts;
                rptPager.ItemDataBound += rptPager_ItemDataBound;


                hdnMaxPage.Value = (BlogPosts.Count() / PageSize).ToString();

                if (!IsPostBack)
                {
                    rptPager.DataBind();

                    if (ObjectAttributes.Pagination != "infinite")
                    {
                        if (BlogPosts.ToList().Count() / (double) PageSize > 1)
                            plcPager.Visible = true;
                    }
                    else
                    {
                        phInfiniteScroll.Visible = true;
                    }
                }
            }
            else
            {
                litNoPosts.Text =
                    string.Format("<p>No posts found matching the selected criteria. <a href='{0}'>Return</a></p>",
                        CurrentNavigationPage.FullUrl);
            }
        }

        private void ScrollOn()
        {
            try
            {
                var currentPage = hdnCurrentPage.Value;
                hdnCurrentPage.Value = (Convert.ToInt16(currentPage) + 1).ToString();
                var take = 0;
                if (PageSize * (Convert.ToInt16(currentPage) + 1) < BlogPosts.Count())
                    take = PageSize * (Convert.ToInt16(currentPage) + 1);
                else
                    take = BlogPosts.Count();

                rptBlogList.DataSource = BlogPosts.Take(take);
                rptBlogList.DataBind();
            }
            catch
            {
            }
        }

        private void InjectJavascriptIntoContentPlaceHolder()
        {
            RegisterBottomScript(phBottomJavascriptBlog);
        }

        #endregion
    }
}

 

Tile view control

This sample uses a separate control to provide the html markup for the individual listview items.  Although not required, it simplifies the html markup in the BlogArticle control.

BlogArticleListing View

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="BlogArticleListing.ascx.cs" Inherits="AdvantageClient.Modules_BlogArticleListing" %>



    <asp:PlaceHolder runat="server" ID="phTitle">
        <img src='<%# Article.ArticleImage.GetImageElementByName("Medium").ImageUrl %>' alt='<%# Article.ArticleImage.AltText %>' />        
    </asp:PlaceHolder>

    <section class="main">
        <h2><%# Article.Title %></h2>

        <time><%# "Posted on: " + Article.ArticleDate.ToString("dd MMMM yyyy") %></time>

        
        <%# GetCategory(Article.Category) %>
        
        		
        <p><%# Article.Summary %></p>   
        
        <p><%# Article.Author %></p>     
    </section>

    <asp:Repeater runat="server" ID="rptTags">
        <HeaderTemplate>
            <section class="tags">
                <ul>
        </HeaderTemplate>

        <ItemTemplate>
                    <li>
                        <a href='<%# CurrentNavigationPage.FullUrl + "?tag=" + System.Net.WebUtility.UrlEncode(Container.DataItem.ToString()) %>'>#<%# Container.DataItem %></a>
                    </li>
        </ItemTemplate>

        <FooterTemplate>
                </ul>
            </section>
        </FooterTemplate>
    </asp:Repeater>

    <footer>
        <div class="meta" style="display:none;">xxx comments</div>
        
        <ul class="controls">
            <asp:PlaceHolder runat="server" ID="phReadMore">
                <li>
                    <a title='<%# Article.Title %>' href='<%#$"/{DetailPath}{Article.SEOName}" %>'>
						Read More
					</a>
                </li>
            </asp:PlaceHolder>



        </ul>

    </footer>

namespace AdvantageClient
{
    public partial class Modules_BlogArticleListing : AdvantageModule
    {
        public BlogArticle Article { get; set; }

        public string ListPath { get; set; }

        public string DetailPath { get; set; }

        public bool ShowComments { get; set; }

        public bool ShowImage { get; set; }

        public bool ShowTags { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            phTitle.Visible = ShowImage;

            if (ShowTags)
            {
                rptTags.DataSource = Article.Tags;
                rptTags.DataBind();
            }
        }

        protected string GetCategory(Guid masterId)
        {
            string retVal = string.Empty;
            BlogCategory category = ModuleEngine.GetPublishedObjectByMasterId<BlogCategory>(masterId);


            if (category != null)
            {
                string href = string.Format("/{0}?cat={1}", ListPath, category.SEOName);

                retVal = @"<div class=""category"">
                        <a href=""{0}"">{1}</a>
                    </div>";

                retVal = String.Format(retVal, href, category.Name);
            }

            return retVal;
        }
    }
}




Register the module

How to register a Module in Advantage CSP

  1. Go to Sytem Administrator > Modules > Modules

The module should be available in your widgets list inside the page manager.

Back to Top Button