Repository navigation
Expand file tree
/
Copy pathBlogroll.cs
More file actions
386 lines (337 loc) · 12.9 KB
/
Copy pathBlogroll.cs
File metadata and controls
386 lines (337 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
// --------------------------------------------------------------------------------------------------------------------
// <summary>
// Creates and displays a dynamic blogroll.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Xml;
using BlogEngine.Core;
namespace BlogEngineWA.CustomCode.Controls
{
/// <summary>
/// Creates and displays a dynamic blogroll.
/// </summary>
public class Blogroll : Control
{
/// <summary>
/// Initializes a new instance of the <see cref="Blogroll"/> class.
/// </summary>
public Blogroll()
{
this.ShowRssIcon = true;
BlogRollItem.Saved += BlogRollItemSaved;
}
/// <summary>
/// Handles the Saved event of the BlogRollItem control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="BlogEngine.Core.SavedEventArgs"/> instance containing the event data.</param>
private static void BlogRollItemSaved(object sender, SavedEventArgs e)
{
switch (e.Action)
{
case SaveAction.Insert:
AddBlog((BlogRollItem)sender);
break;
case SaveAction.Delete:
var affected = items.FirstOrDefault(req => req.RollItem.Equals(sender));
items.Remove(affected);
break;
}
if (((e.Action == SaveAction.Insert || e.Action == SaveAction.Delete) || e.Action == SaveAction.Update) &&
items.Count > 0)
{
// Re-sort _Items collection in case sorting of blogroll items was changed.
items.Sort((br1, br2) => br1.RollItem.CompareTo(br2.RollItem));
}
}
/// <summary>
/// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"/> object, which writes the content to be rendered on the client.
/// </summary>
/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
protected override void Render(HtmlTextWriter writer)
{
if (this.Page.IsPostBack || this.Page.IsCallback)
{
return;
}
var ul = this.DisplayBlogroll();
using (var sw = new StringWriter())
{
ul.RenderControl(new HtmlTextWriter(sw));
var html = sw.ToString();
writer.WriteLine("<div id=\"blogroll\">");
writer.WriteLine(html);
writer.WriteLine("</div>");
}
}
#region Private fields
/// <summary>
/// The last updated.
/// </summary>
private static DateTime lastUpdated = DateTime.Now;
/// <summary>
/// The items.
/// </summary>
private static List<BlogRequest> items;
#endregion
#region Properties
/// <summary>
/// Determines whether the RSS icon is displayed (default true)
/// </summary>
public bool ShowRssIcon { get; set; }
/// <summary>
/// Display the description of the blog as a tool tip (default false)
/// </summary>
public bool DescriptionToolTip { get; set; }
#endregion
#region Methods
/// <summary>
/// The sync root.
/// </summary>
private static readonly object SyncRoot = new object();
/// <summary>
/// Displays the RSS item collection.
/// </summary>
/// <returns>
/// The output.
/// </returns>
private HtmlGenericControl DisplayBlogroll()
{
if (DateTime.Now > lastUpdated.AddMinutes(BlogSettings.Instance.BlogrollUpdateMinutes) &&
BlogSettings.Instance.BlogrollVisiblePosts > 0)
{
items = null;
lastUpdated = DateTime.Now;
}
if (items == null)
{
lock (SyncRoot)
{
if (items == null)
{
items = new List<BlogRequest>();
foreach (var roll in BlogRollItem.BlogRolls)
{
AddBlog(roll);
}
}
}
}
return this.BindControls();
}
/// <summary>
/// Parses the processed RSS items and returns the HTML
/// </summary>
/// <returns>
/// The output.
/// </returns>
private HtmlGenericControl BindControls()
{
var ul = new HtmlGenericControl("ul");
ul.Attributes.Add("class", "xoxo");
foreach (var item in items)
{
HtmlAnchor feedAnchor = null;
if (this.ShowRssIcon)
{
feedAnchor = new HtmlAnchor { HRef = item.RollItem.FeedUrl.AbsoluteUri };
using (var image = new HtmlImage
{
Src = string.Format("{0}pics/rssButton.png", Utils.RelativeWebRoot), Alt = string.Format("RSS feed for {0}", item.RollItem.Title)
})
{
feedAnchor.Controls.Add(image);
}
}
var webAnchor = new HtmlAnchor
{
HRef = item.RollItem.BlogUrl.AbsoluteUri,
InnerHtml = EnsureLength(item.RollItem.Title)
};
if (this.DescriptionToolTip)
{
webAnchor.Attributes["title"] = item.RollItem.Description;
}
if (!String.IsNullOrEmpty(item.RollItem.Xfn))
{
webAnchor.Attributes["rel"] = item.RollItem.Xfn;
}
using (var li = new HtmlGenericControl("li"))
{
if (null != feedAnchor)
{
li.Controls.Add(feedAnchor);
}
li.Controls.Add(webAnchor);
AddRssChildItems(item, li);
ul.Controls.Add(li);
}
}
return ul;
}
/// <summary>
/// Adds the RSS child items.
/// </summary>
/// <param name="item">The blog request item.</param>
/// <param name="li">The list item.</param>
private static void AddRssChildItems(BlogRequest item, HtmlGenericControl li)
{
if (item.ItemTitles.Count <= 0 || BlogSettings.Instance.BlogrollVisiblePosts <= 0)
{
return;
}
using (var div = new HtmlGenericControl("ul"))
{
for (var i = 0; i < item.ItemTitles.Count; i++)
{
if (i >= BlogSettings.Instance.BlogrollVisiblePosts)
{
break;
}
var subLi = new HtmlGenericControl("li");
using (var a = new HtmlAnchor
{
HRef = item.ItemLinks[i], Title = HttpUtility.HtmlEncode(item.ItemTitles[i]), InnerHtml = EnsureLength(item.ItemTitles[i])
})
{
subLi.Controls.Add(a);
}
div.Controls.Add(subLi);
}
li.Controls.Add(div);
}
}
/// <summary>
/// Ensures that the name is no longer than the MaxLength.
/// </summary>
/// <param name="textToShorten">
/// The text To Shorten.
/// </param>
/// <returns>
/// The ensure length.
/// </returns>
private static string EnsureLength(string textToShorten)
{
return textToShorten.Length > BlogSettings.Instance.BlogrollMaxLength
? string.Format("{0}...", textToShorten.Substring(0, BlogSettings.Instance.BlogrollMaxLength).Trim())
: HttpUtility.HtmlEncode(textToShorten);
}
/// <summary>
/// Adds a blog to the item collection and start retrieving the blogs.
/// </summary>
/// <param name="br">
/// The blogroll item.
/// </param>
private static void AddBlog(BlogRollItem br)
{
var affected = items.FirstOrDefault(r => r.RollItem.Equals(br));
if (affected != null)
{
return;
}
var req = (HttpWebRequest)WebRequest.Create(br.FeedUrl);
req.Credentials = CredentialCache.DefaultNetworkCredentials;
var blogRequest = new BlogRequest(br, req);
items.Add(blogRequest);
req.BeginGetResponse(ProcessResponse, blogRequest);
}
/// <summary>
/// Gets the request and processes the response.
/// </summary>
/// <param name="async">
/// The async result.
/// </param>
private static void ProcessResponse(IAsyncResult async)
{
var blogReq = (BlogRequest)async.AsyncState;
try
{
using (var response = (HttpWebResponse)blogReq.Request.EndGetResponse(async))
{
var doc = new XmlDocument();
var responseStream = response.GetResponseStream();
if (responseStream != null)
{
doc.Load(responseStream);
}
var nodes = doc.SelectNodes("rss/channel/item");
if (nodes != null)
{
foreach (XmlNode node in nodes)
{
var titleNode = node.SelectSingleNode("title");
var linkNode = node.SelectSingleNode("link");
if (titleNode == null || linkNode == null)
{
continue;
}
var title = titleNode.InnerText;
var link = linkNode.InnerText;
// var date = DateTime.Now;
// if (node.SelectSingleNode("pubDate") != null)
// {
// date = DateTime.Parse(node.SelectSingleNode("pubDate").InnerText);
// }
blogReq.ItemTitles.Add(title);
blogReq.ItemLinks.Add(link);
}
}
}
}
catch
{
}
}
#endregion
}
/// <summary>
/// The blog request.
/// </summary>
internal class BlogRequest
{
/// <summary>
/// Gets or sets the roll item.
/// </summary>
/// <value>The roll item.</value>
internal BlogRollItem RollItem { get; set; }
/// <summary>
/// Gets or sets the request.
/// </summary>
/// <value>The request.</value>
internal HttpWebRequest Request { get; set; }
/// <summary>
/// Gets or sets the item titles.
/// </summary>
/// <value>The item titles.</value>
internal List<string> ItemTitles { get; set; }
/// <summary>
/// Gets or sets the item links.
/// </summary>
/// <value>The item links.</value>
internal List<string> ItemLinks { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="BlogRequest"/> class.
/// </summary>
/// <param name="rollItem">
/// The roll item.
/// </param>
/// <param name="request">
/// The request.
/// </param>
internal BlogRequest(BlogRollItem rollItem, HttpWebRequest request)
{
this.ItemTitles = new List<string>();
this.ItemLinks = new List<string>();
this.RollItem = rollItem;
this.Request = request;
}
}
}