PageRenderTime 43ms CodeModel.GetById 1ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/BlogEngine/DotNetSlave.BusinessLogic/Web/Controls/BlogBasePage.cs

#
C# | 472 lines | 268 code | 58 blank | 146 comment | 38 complexity | d9715c2d24ebca3ac7f6aef38f2c4dc3 MD5 | raw file
  1namespace BlogEngine.Core.Web.Controls
  2{
  3    using System;
  4    using System.Globalization;
  5    using System.IO;
  6    using System.Linq;
  7    using System.Text;
  8    using System.Web;
  9    using System.Web.UI;
 10    using System.Web.UI.HtmlControls;
 11
 12    /// <summary>
 13    /// All pages in the custom themes as well as pre-defined pages in the root
 14    ///     must inherit from this class.
 15    /// </summary>
 16    /// <remarks>
 17    /// The class is responsible for assigning the theme to all
 18    ///     derived pages as well as adding RSS, RSD, tracking script
 19    ///     and a whole lot more.
 20    /// </remarks>
 21    public abstract class BlogBasePage : Page
 22    {
 23        #region Constants and Fields
 24
 25        /// <summary>
 26        /// The theme.
 27        /// </summary>
 28        private readonly string theme = BlogSettings.Instance.Theme;
 29
 30        #endregion
 31
 32        #region Public Methods
 33
 34        /// <summary>
 35        /// Adds the generic link to the header.
 36        /// </summary>
 37        /// <param name="relation">
 38        /// The relation string.
 39        /// </param>
 40        /// <param name="title">
 41        /// The title string.
 42        /// </param>
 43        /// <param name="href">
 44        /// The href string.
 45        /// </param>
 46        public virtual void AddGenericLink(string relation, string title, string href)
 47        {
 48            this.AddGenericLink(null, relation, title, href);
 49        }
 50
 51        /// <summary>
 52        /// Adds the generic link to the header.
 53        /// </summary>
 54        /// <param name="type">
 55        /// The type string.
 56        /// </param>
 57        /// <param name="relation">
 58        /// The relation string.
 59        /// </param>
 60        /// <param name="title">
 61        /// The title string.
 62        /// </param>
 63        /// <param name="href">
 64        /// The href string.
 65        /// </param>
 66        public virtual void AddGenericLink(string type, string relation, string title, string href)
 67        {
 68            this.Page.Header.Controls.Add(GetGenericLink(type, relation, title, href));
 69        }
 70
 71        /// <summary>
 72        /// Adds a Stylesheet reference to the HTML head tag.
 73        /// </summary>
 74        /// <param name="url">
 75        /// The relative URL.
 76        /// </param>
 77        /// <param name="insertAtFront">
 78        /// If true, inserts in beginning of HTML head tag.
 79        /// </param>
 80        public virtual void AddStylesheetInclude(string url, bool insertAtFront)
 81        {
 82            var link = new HtmlLink();
 83            link.Attributes["type"] = "text/css";
 84            link.Attributes["href"] = url;
 85            link.Attributes["rel"] = "stylesheet";
 86
 87            if (insertAtFront)
 88            {
 89                this.Page.Header.Controls.AddAt(0, link);
 90            }
 91            else
 92            {
 93                this.Page.Header.Controls.Add(link);
 94            }
 95        }
 96
 97        /// <summary>
 98        /// Adds a Stylesheet reference to the HTML head tag.
 99        /// </summary>
100        /// <param name="url">
101        /// The relative URL.
102        /// </param>
103        public virtual void AddStylesheetInclude(string url)
104        {
105            this.AddStylesheetInclude(url, false);
106        }
107
108        #endregion
109
110        #region Methods
111
112        /// <summary>
113        /// Adds code to the HTML head section.
114        /// </summary>
115        protected virtual void AddCustomCodeToHead()
116        {
117            var code = string.Format(
118                CultureInfo.InvariantCulture,
119                "{0}<!-- Start custom code -->{0}{1}{0}<!-- End custom code -->{0}",
120                Environment.NewLine,
121                BlogSettings.Instance.HtmlHeader);
122            var control = new LiteralControl(code);
123            this.Page.Header.Controls.Add(control);
124        }
125
126        /// <summary>
127        /// Adds the default stylesheet language
128        /// </summary>
129        protected virtual void AddDefaultLanguages()
130        {
131            this.Response.AppendHeader("Content-Style-Type", "text/css");
132            this.Response.AppendHeader("Content-Script-Type", "text/javascript");
133        }
134
135        /// <summary>
136        /// Add global style sheets before any custom css
137        /// </summary>
138        protected virtual void AddGlobalStyles()
139        {
140            // add styles in the ~/Styles folder to the page header
141            var s = Path.Combine(HttpContext.Current.Server.MapPath(Utils.ApplicationRelativeWebRoot), "Styles");
142            var fileEntries = Directory.GetFiles(s);
143            foreach (var fileName in
144                fileEntries.Where(fileName => fileName.EndsWith(".css", StringComparison.OrdinalIgnoreCase)))
145            {
146                this.AddStylesheetInclude(
147                    string.Format("{0}Styles/{1}", Utils.ApplicationRelativeWebRoot, Utils.ExtractFileNameFromPath(fileName)), true);
148            }
149        }
150
151        /// <summary>
152        /// Adds the content-type meta tag to the header.
153        /// </summary>
154        protected virtual void AddMetaContentType()
155        {
156            var meta = new HtmlMeta
157                {
158                    HttpEquiv = "content-type",
159                    Content =
160                        string.Format(
161                            "{0}; charset={1}", this.Response.ContentType, this.Response.ContentEncoding.HeaderName)
162                };
163            this.Page.Header.Controls.Add(meta);
164        }
165
166        /// <summary>
167        /// Add a meta tag to the page's header.
168        /// </summary>
169        /// <param name="name">
170        /// The tag name.
171        /// </param>
172        /// <param name="value">
173        /// The tag value.
174        /// </param>
175        protected virtual void AddMetaTag(string name, string value)
176        {
177            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
178            {
179                return;
180            }
181
182            var meta = new HtmlMeta { Name = name, Content = value };
183            this.Page.Header.Controls.Add(meta);
184        }
185
186        /// <summary>
187        /// Adds a JavaScript to the bottom of the page at runtime.
188        /// </summary>
189        /// <remarks>
190        /// You must add the script tags to the BlogSettings.Instance.TrackingScript.
191        /// </remarks>
192        protected virtual void AddTrackingScript()
193        {
194            var sb = new StringBuilder();
195
196            if (BlogSettings.Instance.ModerationType == BlogSettings.Moderation.Disqus)
197            {
198                sb.Append("<script type=\"text/javascript\"> \n");
199                sb.Append("//<![CDATA[ \n");
200                sb.Append("(function() { ");
201                sb.Append("var links = document.getElementsByTagName('a'); ");
202                sb.Append("var query = '?'; ");
203                sb.Append("for(var i = 0; i < links.length; i++) { ");
204                sb.Append("if(links[i].href.indexOf('#disqus_thread') >= 0) { ");
205                sb.Append("query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&'; ");
206                sb.Append("}}");
207                sb.Append("document.write('<script charset=\"utf-8\" type=\"text/javascript\" src=\"http://disqus.com/forums/");
208                sb.Append(BlogSettings.Instance.DisqusWebsiteName);
209                sb.Append("/get_num_replies.js' + query + '\"></' + 'script>'); ");
210                sb.Append("})(); \n");
211                sb.Append("//]]> \n");
212                sb.Append("</script> \n");
213            }
214
215            if (!string.IsNullOrEmpty(BlogSettings.Instance.TrackingScript))
216            {
217                sb.Append(BlogSettings.Instance.TrackingScript);
218            }
219
220            var s = sb.ToString();
221            if (!string.IsNullOrEmpty(s))
222            {
223                this.ClientScript.RegisterStartupScript(this.GetType(), "tracking", string.Format("\n{0}", s), false);
224            }
225        }
226
227        /// <summary>
228        /// Finds all stylesheets in the header and changes the 
229        ///     path so it points to css.axd which removes the whitespace.
230        /// </summary>
231        protected virtual void CompressCss()
232        {
233            if (this.Request.QueryString["theme"] != null)
234            {
235                return;
236            }
237
238            foreach (Control control in this.Page.Header.Controls)
239            {
240                var c = control as HtmlControl;
241                if (c == null || c.Attributes["type"] == null ||
242                    !c.Attributes["type"].Equals("text/css", StringComparison.OrdinalIgnoreCase))
243                {
244                    continue;
245                }
246
247                // if a CSS filename has ".min.css" in it, it is probably an already
248                // minified CSS file -- skip these.
249                if (c.Attributes["href"].StartsWith("http://") ||
250                    c.Attributes["href"].IndexOf(".min.css", StringComparison.OrdinalIgnoreCase) != -1)
251                {
252                    continue;
253                }
254
255                var url = string.Format("{0}themes/{1}/css.axd?name={2}", Utils.ApplicationRelativeWebRoot, this.theme, c.Attributes["href"]);
256                c.Attributes["href"] = url.Replace(".css", string.Format("{0}.css", BlogSettings.Instance.Version()));
257                c.EnableViewState = false;
258            }
259        }
260
261
262        /// <summary>
263        /// Creates and returns a generic link control.
264        /// </summary>
265        /// <param name="type">
266        /// The HtmlLink's "type" attribute value.
267        /// </param>
268        /// <param name="relation">
269        /// The HtmlLink's "rel" attribute value.
270        /// </param>
271        /// <param name="title">
272        /// The HtmlLink's "title" attribute value.
273        /// </param>
274        /// <param name="href">
275        /// The HtmlLink's "href" attribute value.
276        /// </param>
277        private static HtmlLink GetGenericLink(string type, string relation, string title, string href)
278        {
279            var link = new HtmlLink();
280
281            if (type != null) { link.Attributes["type"] = type; }
282            link.Attributes["rel"] = relation;
283            link.Attributes["title"] = title;
284            link.Attributes["href"] = href;
285            return link;
286        }
287
288        /// <summary>
289        /// Raises the <see cref="E:System.Web.UI.TemplateControl.Error"></see> event.
290        /// </summary>
291        /// <param name="e">
292        /// An <see cref="T:System.EventArgs"></see> that contains the event data.
293        /// </param>
294        protected override void OnError(EventArgs e)
295        {
296            var ctx = HttpContext.Current;
297            var exception = ctx.Server.GetLastError();
298
299            if (exception != null && exception.Message.Contains("callback"))
300            {
301                // This is a robot spam attack so we send it a 404 status to make it go away.
302                ctx.Response.StatusCode = 404;
303                ctx.Server.ClearError();
304                Comment.OnSpamAttack();
305            }
306
307            base.OnError(e);
308        }
309
310        /// <summary>
311        /// Raises the <see cref="E:System.Web.UI.Control.Load"/> event.
312        /// Adds links and javascript to the HTML header tag.
313        /// </summary>
314        /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
315        protected override void OnLoad(EventArgs e)
316        {
317            base.OnLoad(e);
318
319            string relativeWebRoot = Utils.RelativeWebRoot;
320            Uri absoluteWebRoot = Utils.AbsoluteWebRoot;
321            string instanceName = BlogSettings.Instance.Name;
322
323            if (!this.Page.IsCallback)
324            {
325                // Links
326                this.AddGenericLink("contents", "Archive", string.Format("{0}archive.aspx", relativeWebRoot));
327                this.AddGenericLink("start", instanceName, relativeWebRoot);
328                this.AddGenericLink("application/rdf+xml", "meta", "SIOC", string.Format("{0}sioc.axd", absoluteWebRoot));
329                this.AddGenericLink("application/apml+xml", "meta", "APML", string.Format("{0}apml.axd", absoluteWebRoot));
330                this.AddGenericLink("application/rdf+xml", "meta", "FOAF", string.Format("{0}foaf.axd", absoluteWebRoot));
331
332                if (string.IsNullOrEmpty(BlogSettings.Instance.AlternateFeedUrl))
333                {
334                    this.AddGenericLink(
335                        "application/rss+xml",
336                        "alternate",
337                        string.Format("{0} (RSS)", instanceName),
338                        string.Format("{0}?format=rss", Utils.FeedUrl));
339                    this.AddGenericLink(
340                        "application/atom+xml",
341                        "alternate",
342                        string.Format("{0} (ATOM)", instanceName),
343                        string.Format("{0}?format=atom", Utils.FeedUrl));
344                }
345                else
346                {
347                    this.AddGenericLink("application/rss+xml", "alternate", instanceName, Utils.FeedUrl);
348                }
349
350                this.AddGenericLink("application/rsd+xml", "edituri", "RSD", string.Format("{0}rsd.axd", absoluteWebRoot));
351
352                this.AddMetaContentType();
353
354                this.AddDefaultLanguages();
355
356             //   this.AddLocalizationKeys();
357
358                this.AddGlobalStyles();
359
360                Utils.AddFolderJavaScripts(this, "Scripts", true);
361                Utils.AddJavaScriptResourcesToPage(this);
362                Utils.AddFolderJavaScripts(this, string.Format("themes/{0}", this.theme), true);
363
364                if (BlogSettings.Instance.EnableOpenSearch)
365                {
366                    this.AddGenericLink(
367                        "application/opensearchdescription+xml",
368                        "search",
369                        instanceName,
370                        string.Format("{0}opensearch.axd", absoluteWebRoot));
371                }
372
373                if (!string.IsNullOrEmpty(BlogSettings.Instance.HtmlHeader))
374                {
375                    this.AddCustomCodeToHead();
376                }
377
378                this.AddTrackingScript();
379            }
380
381            if (Security.IsAuthorizedTo(Rights.ManageWidgets))
382            {
383                Utils.AddJavaScriptInclude(this, string.Format("{0}admin/widget.js", Utils.ApplicationRelativeWebRoot), true, false, true);
384            }
385
386            if (BlogSettings.Instance.RemoveWhitespaceInStyleSheets)
387            {
388                this.CompressCss();
389            }
390        }
391
392        /// <summary>
393        /// Raises the <see cref="E:System.Web.UI.Page.PreInit"/> event at the beginning of page initialization.
394        /// Assignes the selected theme to the pages.
395        /// </summary>
396        /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
397        protected override void OnPreInit(EventArgs e)
398        {
399            bool allowViewing = false;
400
401            // - To prevent authenticated users from accessing the site, you would assign
402            //   that user to a role that does not have the right to ViewPublicPosts.
403            // - To prevent unauthenticated users from accessing the site, remove
404            //   the ViewPublicPosts from the Anonymous role.
405            // - If the user is authenticated, but hasn't been assigned to any roles, allow
406            //   them to access the site.
407            // - Even though we allow authenticated users without any roles to access the
408            //   site, the user will still usually not be able to view any published posts.
409            //   It is ideal that all users are assigned to a role, even if that role has
410            //   minimal rights such as ViewPublicPosts.
411
412            if (Security.IsAuthorizedTo(Rights.ViewPublicPosts))
413                allowViewing = true;
414            else if (Security.IsAuthenticated && Security.GetCurrentUserRoles().Length == 0)
415                allowViewing = true;
416
417            if (!allowViewing)
418            {
419                this.Response.Redirect(string.Format("{0}Account/login.aspx", Utils.RelativeWebRoot));
420            }
421
422            this.MasterPageFile = string.Format("{0}themes/{1}/site.master", Utils.ApplicationRelativeWebRoot, BlogSettings.Instance.GetThemeWithAdjustments(null));
423
424            base.OnPreInit(e);
425
426            if (this.Page.IsPostBack || string.IsNullOrEmpty(this.Request.QueryString["deletepost"]))
427            {
428                return;
429            }
430
431            var post = Post.GetPost(new Guid(this.Request.QueryString["deletepost"]));
432            if (post == null || !post.CanUserDelete)
433            {
434                return;
435            }
436
437            post.Delete();
438            post.Save();
439            this.Response.Redirect(Utils.RelativeWebRoot);
440        }
441
442        /// <summary>
443        /// Raises the <see cref="E:System.Web.UI.Page.PreRenderComplete"></see> event after 
444        ///     the <see cref="M:System.Web.UI.Page.OnPreRenderComplete(System.EventArgs)"></see> event and before the page is rendered.
445        /// </summary>
446        /// <param name="e">
447        /// An <see cref="T:System.EventArgs"></see> that contains the event data.
448        /// </param>
449        protected override void OnPreRenderComplete(EventArgs e)
450        {
451            base.OnPreRenderComplete(e);
452            if (BlogSettings.Instance.UseBlogNameInPageTitles)
453            {
454                this.Page.Title = string.Format("{0} | {1}", BlogSettings.Instance.Name, this.Page.Title);
455            }
456        }
457
458        /// <summary>
459        /// Initializes the <see cref="T:System.Web.UI.HtmlTextWriter"></see> object and calls on the child
460        ///     controls of the <see cref="T:System.Web.UI.Page"></see> to render.
461        /// </summary>
462        /// <param name="writer">
463        /// The <see cref="T:System.Web.UI.HtmlTextWriter"></see> that receives the page content.
464        /// </param>
465        protected override void Render(HtmlTextWriter writer)
466        {
467            base.Render(new RewriteFormHtmlTextWriter(writer));
468        }
469
470        #endregion
471    }
472}