1838 lines
66 KiB
C#
1838 lines
66 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="WmlMobileTextWriter.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Specialized;
|
||
|
using System.Globalization;
|
||
|
using System.IO;
|
||
|
using System.Web.Mobile;
|
||
|
using System.Web.UI.MobileControls;
|
||
|
using System.Text.RegularExpressions;
|
||
|
using System.Diagnostics;
|
||
|
using System.Web.Security;
|
||
|
using System.Security.Permissions;
|
||
|
|
||
|
using SR=System.Web.UI.MobileControls.Adapters.SR;
|
||
|
|
||
|
#if COMPILING_FOR_SHIPPED_SOURCE
|
||
|
using Adapters=System.Web.UI.MobileControls.ShippedAdapterSource;
|
||
|
namespace System.Web.UI.MobileControls.ShippedAdapterSource
|
||
|
#else
|
||
|
using Adapters=System.Web.UI.MobileControls.Adapters;
|
||
|
namespace System.Web.UI.MobileControls.Adapters
|
||
|
#endif
|
||
|
|
||
|
{
|
||
|
/*
|
||
|
* WmlMobileTextWriter class.
|
||
|
*
|
||
|
* Copyright (c) 2000 Microsoft Corporation
|
||
|
*/
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter"]/*' />
|
||
|
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
||
|
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
||
|
[Obsolete("The System.Web.Mobile.dll assembly has been deprecated and should no longer be used. For information about how to develop ASP.NET mobile applications, see http://go.microsoft.com/fwlink/?LinkId=157231.")]
|
||
|
public class WmlMobileTextWriter : MobileTextWriter
|
||
|
{
|
||
|
private TextWriter _realInnerWriter;
|
||
|
private EmptyTextWriter _analyzeWriter;
|
||
|
private bool _analyzeMode = false;
|
||
|
private MobilePage _page;
|
||
|
private Form _currentForm;
|
||
|
private bool[] _usingPostBackType = new bool[] { false, false };
|
||
|
private bool[] _writtenPostBackType = new bool[] { false, false };
|
||
|
private int _numberOfPostBacks;
|
||
|
private bool _postBackCardsEfficient = false;
|
||
|
private IDictionary _formVariables = null;
|
||
|
private IDictionary _controlShortNames = null;
|
||
|
private Stack _layoutStack = new Stack();
|
||
|
private Stack _formatStack = new Stack();
|
||
|
private WmlLayout _currentWrittenLayout = null;
|
||
|
private WmlFormat _currentWrittenFormat = null;
|
||
|
private bool _pendingBreak = false;
|
||
|
private bool _inAnchor = false;
|
||
|
private int _numberOfSoftkeys;
|
||
|
private bool _provideBackButton = false;
|
||
|
private bool _writtenFormVariables = false;
|
||
|
private bool _alwaysScrambleClientIDs = false;
|
||
|
|
||
|
private const String _largeTag = "big";
|
||
|
private const String _smallTag = "small";
|
||
|
private const String _boldTag = "b";
|
||
|
private const String _italicTag = "i";
|
||
|
internal const String _postBackCardPrefix = "__pbc";
|
||
|
private const String _postBackWithVarsCardId = "__pbc1";
|
||
|
private const String _postBackWithoutVarsCardId = "__pbc2";
|
||
|
internal const String _postBackEventTargetVarName = "mcsvt";
|
||
|
internal const String _postBackEventArgumentVarName = "mcsva";
|
||
|
private const String _shortNamePrefix = "mcsv";
|
||
|
private const int _maxShortNameLength = 16;
|
||
|
private static Random _random = new Random();
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WmlMobileTextWriter"]/*' />
|
||
|
public WmlMobileTextWriter(TextWriter writer, MobileCapabilities device, MobilePage page)
|
||
|
: base(writer, device)
|
||
|
{
|
||
|
_realInnerWriter = writer;
|
||
|
_page = page;
|
||
|
|
||
|
_numberOfSoftkeys = Device.NumberOfSoftkeys;
|
||
|
if (_numberOfSoftkeys > 2)
|
||
|
{
|
||
|
_numberOfSoftkeys = 2;
|
||
|
}
|
||
|
|
||
|
// For phones that don't have a back button, assign a softkey.
|
||
|
|
||
|
if (_numberOfSoftkeys == 2 && !Device.HasBackButton)
|
||
|
{
|
||
|
_numberOfSoftkeys = 1;
|
||
|
_provideBackButton = true;
|
||
|
_alwaysScrambleClientIDs = _provideBackButton &&
|
||
|
!device.CanRenderOneventAndPrevElementsTogether;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// AnalyzeMode is set to true during first analysis pass of rendering.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.AnalyzeMode"]/*' />
|
||
|
public bool AnalyzeMode
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _analyzeMode;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_analyzeMode = value;
|
||
|
if (value)
|
||
|
{
|
||
|
_analyzeWriter = new EmptyTextWriter();
|
||
|
InnerWriter = _analyzeWriter;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
InnerWriter = _realInnerWriter;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool HasFormVariables
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _writtenFormVariables;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.EnterLayout"]/*' />
|
||
|
public override void EnterLayout(Style style)
|
||
|
{
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WmlLayout newLayout = new WmlLayout(style, CurrentLayout);
|
||
|
_layoutStack.Push(newLayout);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.ExitLayout"]/*' />
|
||
|
public override void ExitLayout(Style style, bool breakAfter)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
if (breakAfter)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
_layoutStack.Pop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.EnterFormat"]/*' />
|
||
|
public override void EnterFormat(Style style)
|
||
|
{
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
WmlFormat newFormat = new WmlFormat(style, CurrentFormat);
|
||
|
_formatStack.Push(newFormat);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.ExitFormat"]/*' />
|
||
|
public override void ExitFormat(Style style)
|
||
|
{
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
_formatStack.Pop();
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.BeginForm"]/*' />
|
||
|
public virtual void BeginForm(Form form)
|
||
|
{
|
||
|
_cachedFormQueryString = null;
|
||
|
_currentForm = form;
|
||
|
|
||
|
_writtenFormVariables = false;
|
||
|
|
||
|
// To keep track of postbacks which submit form variables,
|
||
|
// and postbacks that don't. Used for postback cards
|
||
|
// (see UsePostBackCards)
|
||
|
|
||
|
_usingPostBackType[0] = _usingPostBackType[1] = false;
|
||
|
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
_numberOfPostBacks = 0;
|
||
|
_postBackCardsEfficient = false;
|
||
|
_controlShortNames = null;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PendingBreak = false;
|
||
|
_currentWrittenLayout = null;
|
||
|
_currentWrittenFormat = null;
|
||
|
|
||
|
RenderBeginForm(form);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.EndForm"]/*' />
|
||
|
public virtual void EndForm()
|
||
|
{
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
// Analyze form when done.
|
||
|
PostAnalyzeForm();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RenderEndForm();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Single parameter - used for rendering ordinary inline text
|
||
|
// (with encoding but without breaks).
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderText"]/*' />
|
||
|
public void RenderText(String text)
|
||
|
{
|
||
|
RenderText(text, false, true);
|
||
|
}
|
||
|
|
||
|
// Two parameters - used for rendering encoded text with or without breaks)
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderText1"]/*' />
|
||
|
public void RenderText(String text, bool breakAfter)
|
||
|
{
|
||
|
RenderText(text, breakAfter, true);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderText2"]/*' />
|
||
|
public virtual void RenderText(String text, bool breakAfter, bool encodeText)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
EnsureLayout();
|
||
|
|
||
|
// Don't use formatting tags inside anchor.
|
||
|
if (!_inAnchor)
|
||
|
{
|
||
|
EnsureFormat();
|
||
|
}
|
||
|
|
||
|
WriteText(text, encodeText);
|
||
|
if (breakAfter)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Escape '&' in XML if it hasn't been
|
||
|
internal String EscapeAmpersand(String url)
|
||
|
{
|
||
|
const char ampersand = '&';
|
||
|
const String ampEscaped = "amp;";
|
||
|
|
||
|
if (url == null)
|
||
|
{
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
int ampPos = url.IndexOf(ampersand);
|
||
|
while (ampPos != -1)
|
||
|
{
|
||
|
if (url.Length - ampPos <= ampEscaped.Length ||
|
||
|
url.Substring(ampPos + 1, ampEscaped.Length) != ampEscaped)
|
||
|
{
|
||
|
url = url.Insert(ampPos + 1, ampEscaped);
|
||
|
}
|
||
|
ampPos = url.IndexOf(ampersand, ampPos + ampEscaped.Length + 1);
|
||
|
}
|
||
|
|
||
|
return url;
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderBeginHyperlink"]/*' />
|
||
|
public virtual void RenderBeginHyperlink(String targetUrl,
|
||
|
bool encodeUrl,
|
||
|
String softkeyLabel,
|
||
|
bool implicitSoftkeyLabel,
|
||
|
bool mapToSoftkey)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
EnsureLayout();
|
||
|
EnsureFormat();
|
||
|
|
||
|
WriteBeginTag("a");
|
||
|
Write(" href=\"");
|
||
|
if (encodeUrl)
|
||
|
{
|
||
|
WriteEncodedUrl(targetUrl);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Write(EscapeAmpersand(targetUrl));
|
||
|
}
|
||
|
Write("\"");
|
||
|
if (softkeyLabel != null && softkeyLabel.Length > 0 && !RequiresNoSoftkeyLabels())
|
||
|
{
|
||
|
WriteTextEncodedAttribute("title", softkeyLabel);
|
||
|
}
|
||
|
Write(">");
|
||
|
_inAnchor = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderEndHyperlink"]/*' />
|
||
|
public virtual void RenderEndHyperlink(bool breakAfter)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
WriteEndTag("a");
|
||
|
if (breakAfter)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
_inAnchor = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderTextBox"]/*' />
|
||
|
public virtual void RenderTextBox(String id,
|
||
|
String value,
|
||
|
String format,
|
||
|
String title,
|
||
|
bool password,
|
||
|
int size,
|
||
|
int maxLength,
|
||
|
bool generateRandomID,
|
||
|
bool breakAfter)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
// Input tags cannot appear inside character formatting tags,
|
||
|
// so close any character formatting.
|
||
|
|
||
|
CloseCharacterFormat();
|
||
|
|
||
|
// Certain devices always render a break before a <select>. If
|
||
|
// we're on such a device, cancel any pending breaks so as not
|
||
|
// to get an extra line of whitespace.
|
||
|
if (Device.RendersBreakBeforeWmlSelectAndInput)
|
||
|
{
|
||
|
PendingBreak = false;
|
||
|
}
|
||
|
|
||
|
EnsureLayout();
|
||
|
WriteBeginTag("input");
|
||
|
// Map the client ID to a short name. See
|
||
|
// MapClientIDToShortName for details.
|
||
|
WriteAttribute("name", MapClientIDToShortName(id, generateRandomID));
|
||
|
if (password)
|
||
|
{
|
||
|
WriteAttribute("type", "password");
|
||
|
}
|
||
|
if (format != null && format.Length > 0)
|
||
|
{
|
||
|
WriteAttribute("format", format);
|
||
|
}
|
||
|
if (title != null && title.Length > 0)
|
||
|
{
|
||
|
WriteTextEncodedAttribute("title", title);
|
||
|
}
|
||
|
if (size > 0)
|
||
|
{
|
||
|
WriteAttribute("size", size.ToString(CultureInfo.InvariantCulture));
|
||
|
}
|
||
|
if (maxLength > 0)
|
||
|
{
|
||
|
WriteAttribute("maxlength", maxLength.ToString(CultureInfo.InvariantCulture));
|
||
|
}
|
||
|
if ((!_writtenFormVariables || ((WmlPageAdapter) Page.Adapter).RequiresValueAttributeInInputTag()) &&
|
||
|
value != null &&
|
||
|
(value.Length > 0 || password))
|
||
|
{
|
||
|
WriteTextEncodedAttribute("value", value);
|
||
|
}
|
||
|
WriteLine(" />");
|
||
|
if (breakAfter && !Device.RendersBreaksAfterWmlInput)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderImage"]/*' />
|
||
|
public virtual void RenderImage(String source,
|
||
|
String localSource,
|
||
|
String alternateText,
|
||
|
bool breakAfter)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
EnsureLayout();
|
||
|
|
||
|
WriteBeginTag("img");
|
||
|
WriteAttribute("src", source, true /*encode*/);
|
||
|
if (localSource != null)
|
||
|
{
|
||
|
WriteAttribute("localsrc", localSource, true /*encode*/);
|
||
|
}
|
||
|
WriteTextEncodedAttribute("alt", alternateText != null ? alternateText : String.Empty);
|
||
|
Write(" />");
|
||
|
if (breakAfter)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderBeginPostBack"]/*' />
|
||
|
public virtual void RenderBeginPostBack(String softkeyLabel,
|
||
|
bool implicitSoftkeyLabel,
|
||
|
bool mapToSoftkey)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
EnsureLayout();
|
||
|
EnsureFormat();
|
||
|
|
||
|
WriteBeginTag("anchor");
|
||
|
if (softkeyLabel != null && softkeyLabel.Length > 0 && !RequiresNoSoftkeyLabels())
|
||
|
{
|
||
|
WriteTextEncodedAttribute("title", softkeyLabel);
|
||
|
}
|
||
|
Write(">");
|
||
|
_inAnchor = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderEndPostBack"]/*' />
|
||
|
public virtual void RenderEndPostBack(String target,
|
||
|
String argument,
|
||
|
WmlPostFieldType postBackType,
|
||
|
bool includeVariables,
|
||
|
bool breakAfter)
|
||
|
{
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
// Analyze postbacks to see if postback cards should
|
||
|
// be rendered.
|
||
|
|
||
|
AnalyzePostBack(includeVariables, postBackType);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RenderGoAction(target, argument, postBackType, includeVariables);
|
||
|
|
||
|
WriteEndTag("anchor");
|
||
|
if (breakAfter)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
_inAnchor = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderBeginSelect"]/*' />
|
||
|
public virtual void RenderBeginSelect(String name, String iname, String ivalue, String title, bool multiSelect)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
|
||
|
// Select tags cannot appear inside character formatting tags,
|
||
|
// so close any character formatting.
|
||
|
CloseCharacterFormat();
|
||
|
|
||
|
// Certain devices always render a break before a <select>. If
|
||
|
// we're on such a device, cancel any pending breaks so as not
|
||
|
// to get an extra line of whitespace.
|
||
|
if (Device.RendersBreakBeforeWmlSelectAndInput)
|
||
|
{
|
||
|
PendingBreak = false;
|
||
|
}
|
||
|
|
||
|
EnsureLayout();
|
||
|
WriteBeginTag("select");
|
||
|
if (name != null && name.Length > 0)
|
||
|
{
|
||
|
// Map the client ID to a short name. See
|
||
|
// MapClientIDToShortName for details.
|
||
|
WriteAttribute("name", MapClientIDToShortName(name, false));
|
||
|
}
|
||
|
if (iname != null && iname.Length > 0)
|
||
|
{
|
||
|
// Map the client ID to a short name. See
|
||
|
// MapClientIDToShortName for details.
|
||
|
WriteAttribute("iname", MapClientIDToShortName(iname, false));
|
||
|
}
|
||
|
if (!_writtenFormVariables && ivalue != null && ivalue.Length > 0)
|
||
|
{
|
||
|
WriteTextEncodedAttribute("ivalue", ivalue);
|
||
|
}
|
||
|
if (title != null && title.Length >0)
|
||
|
{
|
||
|
WriteTextEncodedAttribute("title", title);
|
||
|
}
|
||
|
if (multiSelect)
|
||
|
{
|
||
|
WriteAttribute("multiple", "true");
|
||
|
}
|
||
|
Write(">");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderEndSelect"]/*' />
|
||
|
public virtual void RenderEndSelect(bool breakAfter)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
WriteEndTag("select");
|
||
|
if (breakAfter && !Device.RendersBreaksAfterWmlInput)
|
||
|
{
|
||
|
PendingBreak = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderSelectOption"]/*' />
|
||
|
public virtual void RenderSelectOption(String text)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
WriteFullBeginTag("option");
|
||
|
WriteEncodedText(text);
|
||
|
WriteEndTag("option");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderSelectOption1"]/*' />
|
||
|
public virtual void RenderSelectOption(String text, String value)
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
WriteBeginTag("option");
|
||
|
WriteAttribute("value", value, true);
|
||
|
Write(">");
|
||
|
WriteEncodedText(text);
|
||
|
WriteEndTag("option");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.BeginCustomMarkup"]/*' />
|
||
|
public virtual void BeginCustomMarkup()
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
EnsureLayout();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.EndCustomMarkup"]/*' />
|
||
|
public virtual void EndCustomMarkup()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.AddFormVariable"]/*' />
|
||
|
public void AddFormVariable(String clientID, String value, bool generateRandomID)
|
||
|
{
|
||
|
// On first (analyze) pass, form variables are added to
|
||
|
// an array. On second pass, they are rendered. This ensures
|
||
|
// that only visible controls generate variables.
|
||
|
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
if (_formVariables == null)
|
||
|
{
|
||
|
_formVariables = new ListDictionary();
|
||
|
}
|
||
|
|
||
|
// Map the client ID to a short name. See
|
||
|
// MapClientIDToShortName for details.
|
||
|
_formVariables[MapClientIDToShortName(clientID, generateRandomID)] = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Call to reset formatting state before outputting custom stuff.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.ResetFormattingState"]/*' />
|
||
|
public virtual void ResetFormattingState()
|
||
|
{
|
||
|
if (!AnalyzeMode)
|
||
|
{
|
||
|
CloseCharacterFormat();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderExtraCards"]/*' />
|
||
|
public virtual void RenderExtraCards()
|
||
|
{
|
||
|
RenderPostBackCards();
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.IsValidSoftkeyLabel"]/*' />
|
||
|
public virtual bool IsValidSoftkeyLabel(String label)
|
||
|
{
|
||
|
return label != null &&
|
||
|
label.Length > 0 &&
|
||
|
label.Length <= Device.MaximumSoftkeyLabelLength;
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderGoAction"]/*' />
|
||
|
public virtual void RenderGoAction(String target,
|
||
|
String argument,
|
||
|
WmlPostFieldType postBackType,
|
||
|
bool includeVariables)
|
||
|
{
|
||
|
|
||
|
WriteBeginTag("go");
|
||
|
Write(" href=\"");
|
||
|
|
||
|
IDictionary postBackVariables = null;
|
||
|
if (includeVariables)
|
||
|
{
|
||
|
postBackVariables = ((WmlFormAdapter)CurrentForm.Adapter).CalculatePostBackVariables();
|
||
|
if (postBackVariables == null || postBackVariables.Count == 0)
|
||
|
{
|
||
|
includeVariables = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool externalSubmit;
|
||
|
if (postBackType == WmlPostFieldType.Submit)
|
||
|
{
|
||
|
externalSubmit = CurrentForm.Action.Length > 0;
|
||
|
postBackType = WmlPostFieldType.Normal;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
externalSubmit = false;
|
||
|
}
|
||
|
|
||
|
if (target != null && !externalSubmit && UsePostBackCard(includeVariables))
|
||
|
{
|
||
|
_writtenPostBackType[includeVariables ? 0 : 1] = true;
|
||
|
|
||
|
// If using postback cards, render a go action to the given
|
||
|
// postback card, along with setvars setting the target and
|
||
|
// argument.
|
||
|
|
||
|
Write("#");
|
||
|
Write(includeVariables ? _postBackWithVarsCardId : _postBackWithoutVarsCardId);
|
||
|
Write("\">");
|
||
|
WriteBeginTag("setvar");
|
||
|
WriteAttribute("name", _postBackEventTargetVarName);
|
||
|
WriteAttribute("value", target);
|
||
|
Write("/>");
|
||
|
WriteBeginTag("setvar");
|
||
|
WriteAttribute("name", _postBackEventArgumentVarName);
|
||
|
Write(" value=\"");
|
||
|
if (argument != null)
|
||
|
{
|
||
|
if (postBackType == WmlPostFieldType.Variable)
|
||
|
{
|
||
|
Write("$(");
|
||
|
Write(argument);
|
||
|
Write(")");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WriteEncodedText(argument);
|
||
|
}
|
||
|
}
|
||
|
Write("\"/>");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This is the real postback.
|
||
|
|
||
|
bool encode = false;
|
||
|
String url = CalculateFormPostBackUrl(externalSubmit, ref encode);
|
||
|
FormMethod method = CurrentForm.Method;
|
||
|
String queryString = CalculateFormQueryString();
|
||
|
|
||
|
if (encode)
|
||
|
{
|
||
|
WriteEncodedUrl(url);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Write(url);
|
||
|
}
|
||
|
|
||
|
if(externalSubmit && queryString != null && queryString.Length > 0)
|
||
|
{
|
||
|
if(Device.RequiresUniqueFilePathSuffix)
|
||
|
{
|
||
|
int loc = queryString.IndexOf('&');
|
||
|
if(loc != -1)
|
||
|
{
|
||
|
queryString = queryString.Substring(0, loc);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
queryString = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add any query string.
|
||
|
if (queryString != null && queryString.Length > 0)
|
||
|
{
|
||
|
if(externalSubmit && (url.IndexOf('?') != -1))
|
||
|
{
|
||
|
Write("&");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Write("?");
|
||
|
}
|
||
|
if (queryString.IndexOf('$') != -1)
|
||
|
{
|
||
|
queryString = queryString.Replace("$", "$$");
|
||
|
}
|
||
|
if(Page.Adapter.PersistCookielessData && Device.CanRenderOneventAndPrevElementsTogether)
|
||
|
{
|
||
|
queryString = ReplaceFormsCookieWithVariable(queryString);
|
||
|
}
|
||
|
base.WriteEncodedText(queryString);
|
||
|
}
|
||
|
Write("\"");
|
||
|
|
||
|
// Method defaults to get in WML, so write it if it's not.
|
||
|
if (method == FormMethod.Post)
|
||
|
{
|
||
|
WriteAttribute("method", "post");
|
||
|
}
|
||
|
Write(">");
|
||
|
|
||
|
// Write the view state as a postfield.
|
||
|
if (!externalSubmit)
|
||
|
{
|
||
|
String pageState = Page.ClientViewState;
|
||
|
if (pageState != null)
|
||
|
{
|
||
|
if (Device.RequiresSpecialViewStateEncoding)
|
||
|
{
|
||
|
pageState =
|
||
|
((WmlPageAdapter) Page.Adapter).EncodeSpecialViewState(pageState);
|
||
|
}
|
||
|
WritePostField(MobilePage.ViewStateID, pageState);
|
||
|
}
|
||
|
|
||
|
// Write the event target.
|
||
|
if (target != null)
|
||
|
{
|
||
|
WritePostField(MobilePage.HiddenPostEventSourceId, target);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Target is null when the action is generated from a postback
|
||
|
// card itself. In this case, set the event target to whatever
|
||
|
// the original event target was.
|
||
|
|
||
|
WritePostFieldVariable(MobilePage.HiddenPostEventSourceId, _postBackEventTargetVarName);
|
||
|
}
|
||
|
|
||
|
// Write the event argument, if valid.
|
||
|
|
||
|
if (argument != null)
|
||
|
{
|
||
|
WritePostField(MobilePage.HiddenPostEventArgumentId, argument, postBackType);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Write postfields for form variables, if desired. Commands, for example,
|
||
|
// include form variables. Links do not.
|
||
|
|
||
|
if (includeVariables)
|
||
|
{
|
||
|
if (postBackVariables != null)
|
||
|
{
|
||
|
foreach (DictionaryEntry entry in postBackVariables)
|
||
|
{
|
||
|
Control ctl = (Control)entry.Key;
|
||
|
Object value = entry.Value;
|
||
|
|
||
|
if (value == null)
|
||
|
{
|
||
|
// Dynamic value.
|
||
|
// Map the client ID to a short name. See
|
||
|
// MapClientIDToShortName for details.
|
||
|
// Note: Because this is called on the second pass,
|
||
|
// we can just pass false as the second parameter
|
||
|
WritePostFieldVariable(ctl.UniqueID, MapClientIDToShortName(ctl.ClientID, false));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Static value.
|
||
|
WritePostField(ctl.UniqueID, (String)value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Always include page hidden variables.
|
||
|
|
||
|
if (Page.HasHiddenVariables())
|
||
|
{
|
||
|
String hiddenVariablePrefix = MobilePage.HiddenVariablePrefix;
|
||
|
foreach (DictionaryEntry entry in Page.HiddenVariables)
|
||
|
{
|
||
|
if (entry.Value != null)
|
||
|
{
|
||
|
WritePostField(hiddenVariablePrefix + (String)entry.Key, (String)entry.Value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
WriteEndTag("go");
|
||
|
}
|
||
|
|
||
|
// Called after form is completed to analyze.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.PostAnalyzeForm"]/*' />
|
||
|
protected virtual void PostAnalyzeForm()
|
||
|
{
|
||
|
// Use postback cards if the number of postbacks exceeds the number
|
||
|
// of required postback cards.
|
||
|
//
|
||
|
|
||
|
|
||
|
int numberOfCardsRequired = (_usingPostBackType[0] ? 1 : 0) +
|
||
|
(_usingPostBackType[1] ? 1 : 0);
|
||
|
if (_numberOfPostBacks > numberOfCardsRequired)
|
||
|
{
|
||
|
_postBackCardsEfficient = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Calculates the URL to output for the postback. Other writers may
|
||
|
// override.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.CalculateFormPostBackUrl"]/*' />
|
||
|
protected virtual String CalculateFormPostBackUrl(bool externalSubmit, ref bool encode)
|
||
|
{
|
||
|
String url = CurrentForm.Action;
|
||
|
if (externalSubmit && url.Length > 0)
|
||
|
{
|
||
|
url = CurrentForm.ResolveUrl(url);
|
||
|
encode = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
url = Page.RelativeFilePath;
|
||
|
encode = true;
|
||
|
}
|
||
|
return url;
|
||
|
}
|
||
|
|
||
|
// Calculates the query string to output for the postback. Other
|
||
|
// writers may override.
|
||
|
|
||
|
internal String ReplaceFormsCookieWithVariable(String queryString)
|
||
|
{
|
||
|
String formsAuthCookieName = FormsAuthentication.FormsCookieName;
|
||
|
if(!String.IsNullOrEmpty(formsAuthCookieName))
|
||
|
{
|
||
|
int index = queryString.IndexOf(formsAuthCookieName + "=", StringComparison.Ordinal);
|
||
|
if(index != -1)
|
||
|
{
|
||
|
int valueStart = index + formsAuthCookieName.Length + 1;
|
||
|
int valueEnd = queryString.IndexOf('&', valueStart);
|
||
|
if(valueStart < queryString.Length)
|
||
|
{
|
||
|
int length = ((valueEnd != -1) ? valueEnd : queryString.Length) - valueStart;
|
||
|
queryString = queryString.Remove(valueStart, length);
|
||
|
queryString = queryString.Insert(valueStart, "$(" + MapClientIDToShortName("__facn", false) + ")");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return queryString;
|
||
|
}
|
||
|
|
||
|
private String _cachedFormQueryString;
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.CalculateFormQueryString"]/*' />
|
||
|
protected virtual String CalculateFormQueryString()
|
||
|
{
|
||
|
if (_cachedFormQueryString != null)
|
||
|
{
|
||
|
return _cachedFormQueryString;
|
||
|
}
|
||
|
|
||
|
String queryString = null;
|
||
|
if (CurrentForm.Method != FormMethod.Get)
|
||
|
{
|
||
|
queryString = Page.QueryStringText;
|
||
|
}
|
||
|
|
||
|
if (Device.RequiresUniqueFilePathSuffix)
|
||
|
{
|
||
|
String ufps = Page.UniqueFilePathSuffix;
|
||
|
if (queryString != null && queryString.Length > 0)
|
||
|
{
|
||
|
queryString = String.Concat(ufps, "&", queryString);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
queryString = ufps;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_cachedFormQueryString = queryString;
|
||
|
return queryString;
|
||
|
}
|
||
|
|
||
|
internal virtual bool ShouldWriteFormID(Form form)
|
||
|
{
|
||
|
WmlPageAdapter pageAdapter = (WmlPageAdapter)CurrentForm.MobilePage.Adapter;
|
||
|
|
||
|
return (form.ID != null && pageAdapter.RendersMultipleForms());
|
||
|
}
|
||
|
|
||
|
// Renders the beginning of a form.
|
||
|
//
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderBeginForm"]/*' />
|
||
|
protected virtual void RenderBeginForm(Form form)
|
||
|
{
|
||
|
WmlFormAdapter formAdapter = (WmlFormAdapter)CurrentForm.Adapter;
|
||
|
|
||
|
IDictionary attributes = new ListDictionary();
|
||
|
if (ShouldWriteFormID(form))
|
||
|
{
|
||
|
attributes.Add("id", form.ClientID);
|
||
|
}
|
||
|
|
||
|
String title = form.Title;
|
||
|
if (title.Length > 0)
|
||
|
{
|
||
|
attributes.Add("title", title);
|
||
|
}
|
||
|
|
||
|
// Let the form adapter render the tag. This bit of indirection is
|
||
|
// somewhat horky, but necessary so that people can subclass adapters
|
||
|
// without worrying about the fact that much of the real work is done
|
||
|
// in the writer.
|
||
|
|
||
|
formAdapter.RenderCardTag(this, attributes);
|
||
|
|
||
|
// Write form variables.
|
||
|
|
||
|
if ((_formVariables != null && _formVariables.Count > 0) &&
|
||
|
(!_provideBackButton ||
|
||
|
Device.CanRenderOneventAndPrevElementsTogether))
|
||
|
{
|
||
|
_writtenFormVariables = true;
|
||
|
Write("<onevent type=\"onenterforward\"><refresh>");
|
||
|
foreach (DictionaryEntry entry in _formVariables)
|
||
|
{
|
||
|
WriteBeginTag("setvar");
|
||
|
WriteAttribute("name", (String)entry.Key);
|
||
|
WriteTextEncodedAttribute("value", (String)entry.Value);
|
||
|
Write(" />");
|
||
|
}
|
||
|
WriteLine("</refresh></onevent>");
|
||
|
|
||
|
}
|
||
|
|
||
|
formAdapter.RenderExtraCardElements(this);
|
||
|
|
||
|
if (_provideBackButton)
|
||
|
{
|
||
|
Write("<do type=\"prev\" label=\"");
|
||
|
Write(SR.GetString(SR.WmlMobileTextWriterBackLabel));
|
||
|
WriteLine("\"><prev /></do>");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Renders the ending of a form.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderEndForm"]/*' />
|
||
|
protected virtual void RenderEndForm()
|
||
|
{
|
||
|
CloseParagraph();
|
||
|
WriteEndTag("card");
|
||
|
WriteLine();
|
||
|
}
|
||
|
|
||
|
// Postback cards provide an alternate, space-efficient way of doing
|
||
|
// postbacks, on forms that have a lot of postback links. Instead of
|
||
|
// posting back directly, postback links switch to a postback card, setting
|
||
|
// variables for event target and argument. The postback card has
|
||
|
// an onenterforward event that submits the postback. It also has
|
||
|
// an onenterbackward, so that it becomes transparent in the card history.
|
||
|
// (Clicking Back to enter the postback card immediately takes you
|
||
|
// to the previous card)
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.UsePostBackCard"]/*' />
|
||
|
protected virtual bool UsePostBackCard(bool includeVariables)
|
||
|
{
|
||
|
bool b = _postBackCardsEfficient && Device.CanRenderPostBackCards;
|
||
|
if (b && includeVariables)
|
||
|
{
|
||
|
WmlPageAdapter pageAdapter = (WmlPageAdapter)CurrentForm.MobilePage.Adapter;
|
||
|
if (pageAdapter.RendersMultipleForms())
|
||
|
{
|
||
|
b = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Renders postback cards.
|
||
|
|
||
|
private void RenderPostBackCards()
|
||
|
{
|
||
|
for (int i = 0; i < 2; i++)
|
||
|
{
|
||
|
if (_writtenPostBackType[i])
|
||
|
{
|
||
|
WriteBeginTag("card");
|
||
|
WriteAttribute("id", i == 0 ? _postBackWithVarsCardId : _postBackWithoutVarsCardId);
|
||
|
WriteLine(">");
|
||
|
|
||
|
Write("<onevent type=\"onenterforward\">");
|
||
|
RenderGoAction(null, _postBackEventArgumentVarName, WmlPostFieldType.Variable, i == 0);
|
||
|
WriteLine("</onevent>");
|
||
|
|
||
|
WriteLine("<onevent type=\"onenterbackward\"><prev /></onevent>");
|
||
|
WriteLine("</card>");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderFormDoEvent"]/*' />
|
||
|
protected void RenderFormDoEvent(String doType, String arg, WmlPostFieldType postBackType, String text)
|
||
|
{
|
||
|
RenderDoEvent(doType, CurrentForm.UniqueID, arg, postBackType, text, true);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.RenderDoEvent"]/*' />
|
||
|
protected void RenderDoEvent(String doType, String target, String arg, WmlPostFieldType postBackType, String text, bool includeVariables)
|
||
|
{
|
||
|
//EnsureLayout();
|
||
|
WriteBeginTag("do");
|
||
|
WriteAttribute("type", doType);
|
||
|
if (text != null && text.Length > 0)
|
||
|
{
|
||
|
WriteTextEncodedAttribute("label", text);
|
||
|
}
|
||
|
Write(">");
|
||
|
RenderGoAction(target, arg, postBackType, includeVariables);
|
||
|
WriteEndTag("do");
|
||
|
}
|
||
|
|
||
|
// Makes sure the writer has rendered a paragraph tag corresponding to
|
||
|
// the current layout.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.EnsureLayout"]/*' />
|
||
|
protected virtual void EnsureLayout()
|
||
|
{
|
||
|
WmlLayout layout = CurrentLayout;
|
||
|
|
||
|
if (_currentWrittenLayout != null && layout.Compare(_currentWrittenLayout))
|
||
|
{
|
||
|
// Same layout as before. Only write any pending break.
|
||
|
if (PendingBreak)
|
||
|
{
|
||
|
// Avoid writing tags like </b> AFTER the <br/>, instead
|
||
|
// writing them before.
|
||
|
|
||
|
if (_currentWrittenFormat != null && !CurrentFormat.Compare(_currentWrittenFormat))
|
||
|
{
|
||
|
CloseCharacterFormat();
|
||
|
}
|
||
|
WriteBreak();
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Layout has changed. Close current layout, and open new one.
|
||
|
CloseParagraph();
|
||
|
OpenParagraph(layout,
|
||
|
layout.Align != Alignment.Left,
|
||
|
layout.Wrap != Wrapping.Wrap);
|
||
|
}
|
||
|
PendingBreak = false;
|
||
|
}
|
||
|
|
||
|
// Makes sure the writer has rendered character formatting tags
|
||
|
// corresponding to the current format.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.EnsureFormat"]/*' />
|
||
|
protected virtual void EnsureFormat()
|
||
|
{
|
||
|
WmlFormat format = CurrentFormat;
|
||
|
|
||
|
if (_currentWrittenFormat == null || !format.Compare(_currentWrittenFormat))
|
||
|
{
|
||
|
CloseCharacterFormat();
|
||
|
OpenCharacterFormat(format,
|
||
|
format.Bold,
|
||
|
format.Italic,
|
||
|
format.Size != FontSize.Normal);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Opens a paragraph with the given layout. Only the specified
|
||
|
// attributes are used.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.OpenParagraph"]/*' />
|
||
|
protected virtual void OpenParagraph(WmlLayout layout, bool writeAlignment, bool writeWrapping)
|
||
|
{
|
||
|
if (_currentWrittenLayout == null)
|
||
|
{
|
||
|
WriteBeginTag("p");
|
||
|
if (writeAlignment)
|
||
|
{
|
||
|
String alignment;
|
||
|
switch (layout.Align)
|
||
|
{
|
||
|
case Alignment.Right:
|
||
|
alignment = "right";
|
||
|
break;
|
||
|
|
||
|
case Alignment.Center:
|
||
|
alignment = "center";
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
alignment = "left";
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
WriteAttribute("align", alignment);
|
||
|
}
|
||
|
if (writeWrapping)
|
||
|
{
|
||
|
WriteAttribute("mode",
|
||
|
layout.Wrap == Wrapping.NoWrap ? "nowrap" : "wrap");
|
||
|
}
|
||
|
Write(">");
|
||
|
_currentWrittenLayout = layout;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Close any open paragraph.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.CloseParagraph"]/*' />
|
||
|
protected virtual void CloseParagraph()
|
||
|
{
|
||
|
if (_currentWrittenLayout != null)
|
||
|
{
|
||
|
CloseCharacterFormat();
|
||
|
WriteEndTag("p");
|
||
|
_currentWrittenLayout = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Renders tags to enter the given character format. Only the specified
|
||
|
// attributes are used.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.OpenCharacterFormat"]/*' />
|
||
|
protected virtual void OpenCharacterFormat(WmlFormat format, bool writeBold, bool writeItalic, bool writeSize)
|
||
|
{
|
||
|
if (_currentWrittenFormat == null)
|
||
|
{
|
||
|
if (writeBold && format.Bold)
|
||
|
{
|
||
|
WriteFullBeginTag(_boldTag);
|
||
|
format.WrittenBold = true;
|
||
|
}
|
||
|
if (writeItalic && format.Italic)
|
||
|
{
|
||
|
WriteFullBeginTag(_italicTag);
|
||
|
format.WrittenItalic = true;
|
||
|
}
|
||
|
if (writeSize && format.Size != FontSize.Normal)
|
||
|
{
|
||
|
WriteFullBeginTag(format.Size == FontSize.Large ? _largeTag : _smallTag);
|
||
|
format.WrittenSize = true;
|
||
|
}
|
||
|
_currentWrittenFormat = format;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Close any open character formatting tags.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.CloseCharacterFormat"]/*' />
|
||
|
protected virtual void CloseCharacterFormat()
|
||
|
{
|
||
|
if (_currentWrittenFormat != null)
|
||
|
{
|
||
|
if (_currentWrittenFormat.WrittenSize)
|
||
|
{
|
||
|
WriteEndTag(_currentWrittenFormat.Size == FontSize.Large ? _largeTag : _smallTag);
|
||
|
}
|
||
|
if (_currentWrittenFormat.WrittenItalic)
|
||
|
{
|
||
|
WriteEndTag(_italicTag);
|
||
|
}
|
||
|
if (_currentWrittenFormat.WrittenBold)
|
||
|
{
|
||
|
WriteEndTag(_boldTag);
|
||
|
}
|
||
|
_currentWrittenFormat = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static readonly char[] _attributeCharacters = new char[] {'"', '&', '<', '>', '$'};
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WriteAttribute"]/*' />
|
||
|
public override void WriteAttribute(String attribute, String value, bool encode)
|
||
|
{
|
||
|
// If in analyze mode, we don't actually have to perform the conversion, because
|
||
|
// it's not getting written anyway.
|
||
|
|
||
|
// If the value is null, we return without writing anything. This is different
|
||
|
// from HtmlTextWriter, which writes the name of the attribute, but no value at all.
|
||
|
// A name with no value is illegal in Wml.
|
||
|
if (value == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (AnalyzeMode)
|
||
|
{
|
||
|
encode = false;
|
||
|
}
|
||
|
|
||
|
if (encode)
|
||
|
{
|
||
|
// Unlike HTML encoding, we need to replace $ with $$, and <> with < and >.
|
||
|
// We can't do this by piggybacking HtmlTextWriter.WriteAttribute, because it
|
||
|
// would translate the & in < or > to &. So we more or less copy the
|
||
|
// ASP.NET code that does similar encoding.
|
||
|
|
||
|
Write(' ');
|
||
|
Write(attribute);
|
||
|
Write("=\"");
|
||
|
|
||
|
int cb = value.Length;
|
||
|
int pos = value.IndexOfAny(_attributeCharacters);
|
||
|
if (pos == -1)
|
||
|
{
|
||
|
Write(value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char[] s = value.ToCharArray();
|
||
|
int startPos = 0;
|
||
|
while (pos < cb)
|
||
|
{
|
||
|
if (pos > startPos)
|
||
|
{
|
||
|
Write(s, startPos, pos - startPos);
|
||
|
}
|
||
|
|
||
|
char ch = s[pos];
|
||
|
switch (ch)
|
||
|
{
|
||
|
case '\"':
|
||
|
Write(""");
|
||
|
break;
|
||
|
case '&':
|
||
|
Write("&");
|
||
|
break;
|
||
|
case '<':
|
||
|
Write("<");
|
||
|
break;
|
||
|
case '>':
|
||
|
Write(">");
|
||
|
break;
|
||
|
case '$':
|
||
|
Write("$$");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
startPos = pos + 1;
|
||
|
pos = value.IndexOfAny(_attributeCharacters, startPos);
|
||
|
if (pos == -1)
|
||
|
{
|
||
|
Write(s, startPos, cb - startPos);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Write('\"');
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
base.WriteAttribute(attribute, value, encode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WriteTextEncodedAttribute"]/*' />
|
||
|
protected void WriteTextEncodedAttribute(String attribute, String value)
|
||
|
{
|
||
|
WriteAttribute(attribute, value, true);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.CurrentForm"]/*' />
|
||
|
protected Form CurrentForm
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _currentForm;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.Page"]/*' />
|
||
|
protected MobilePage Page
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _page;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.NumberOfSoftkeys"]/*' />
|
||
|
protected int NumberOfSoftkeys
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _numberOfSoftkeys;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.AnalyzePostBack"]/*' />
|
||
|
protected virtual void AnalyzePostBack(bool includeVariables, WmlPostFieldType postBackType)
|
||
|
{
|
||
|
_usingPostBackType[includeVariables ? 0 : 1] = true;
|
||
|
if (postBackType != WmlPostFieldType.Submit || CurrentForm.Action.Length == 0)
|
||
|
{
|
||
|
_numberOfPostBacks++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WriteEncodedUrl"]/*' />
|
||
|
public override void WriteEncodedUrl(String url)
|
||
|
{
|
||
|
if (url == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int i = url.IndexOf('?');
|
||
|
if (i != -1)
|
||
|
{
|
||
|
WriteUrlEncodedString(url.Substring(0, i), false);
|
||
|
|
||
|
String s = url.Substring(i);
|
||
|
if (s.IndexOf('$') != -1)
|
||
|
{
|
||
|
s = s.Replace("$", "%24");
|
||
|
}
|
||
|
base.WriteEncodedText(s);
|
||
|
//WriteEncodedText(url.Substring(i));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WriteUrlEncodedString(url, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WriteEncodedText"]/*' />
|
||
|
public override void WriteEncodedText(String text)
|
||
|
{
|
||
|
if (text == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (text.IndexOf('$') != -1)
|
||
|
{
|
||
|
text = text.Replace("$", "$$");
|
||
|
}
|
||
|
|
||
|
base.WriteEncodedText(text);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WriteText"]/*' />
|
||
|
public void WriteText(String text, bool encodeText)
|
||
|
{
|
||
|
if (encodeText)
|
||
|
{
|
||
|
WriteEncodedText(text);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WritePlainText(text);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void WritePlainText(String text)
|
||
|
{
|
||
|
if (text == null)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (text.IndexOf('$') != -1)
|
||
|
{
|
||
|
text = text.Replace("$", "$$");
|
||
|
}
|
||
|
Write(text);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WriteBreak"]/*' />
|
||
|
protected new void WriteBreak()
|
||
|
{
|
||
|
Write("<br/>\r\n");
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WritePostField"]/*' />
|
||
|
public void WritePostField(String name, String value)
|
||
|
{
|
||
|
WritePostField(name, value, WmlPostFieldType.Normal);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WritePostFieldVariable"]/*' />
|
||
|
public void WritePostFieldVariable(String name, String arg)
|
||
|
{
|
||
|
WritePostField(name, arg, WmlPostFieldType.Variable);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.WritePostField1"]/*' />
|
||
|
public void WritePostField(String name, String value, WmlPostFieldType type)
|
||
|
{
|
||
|
Write("<postfield name=\"");
|
||
|
Write(name);
|
||
|
Write("\" value=\"");
|
||
|
if (type == WmlPostFieldType.Variable)
|
||
|
{
|
||
|
Write("$(");
|
||
|
}
|
||
|
if (type == WmlPostFieldType.Normal)
|
||
|
{
|
||
|
if (Device.RequiresUrlEncodedPostfieldValues)
|
||
|
{
|
||
|
WriteEncodedUrlParameter(value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WriteEncodedText(value);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Write(value);
|
||
|
}
|
||
|
if (type == WmlPostFieldType.Variable)
|
||
|
{
|
||
|
Write(")");
|
||
|
}
|
||
|
Write("\" />");
|
||
|
}
|
||
|
|
||
|
// MapClientIDToShortName provides a unique map of control ClientID properties
|
||
|
// to shorter names. In cases where a control has a very long ClientID, a
|
||
|
// shorter unique name is used. All references to the client ID on the page
|
||
|
// are mapped, resulting in the same postback regardless of mapping.
|
||
|
// MapClientIDToShortName also scrambles client IDs that need to be
|
||
|
// scrambled for security reasons.
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.MapClientIDToShortName"]/*' />
|
||
|
protected internal String MapClientIDToShortName(String clientID, bool generateRandomID)
|
||
|
{
|
||
|
if (_alwaysScrambleClientIDs)
|
||
|
{
|
||
|
generateRandomID = true;
|
||
|
}
|
||
|
|
||
|
if (_controlShortNames != null)
|
||
|
{
|
||
|
String lookup = (String)_controlShortNames[clientID];
|
||
|
if (lookup != null)
|
||
|
{
|
||
|
return lookup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!generateRandomID)
|
||
|
{
|
||
|
bool shortID = clientID.Length < _maxShortNameLength;
|
||
|
// Map names with underscores and conflicting names regardless of length.
|
||
|
bool goodID = !HasUnnamedControlId(clientID) && !NameConflicts(clientID);
|
||
|
|
||
|
if (shortID && goodID)
|
||
|
{
|
||
|
return clientID;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (_controlShortNames == null)
|
||
|
{
|
||
|
_controlShortNames = new ListDictionary();
|
||
|
}
|
||
|
|
||
|
String shortName;
|
||
|
if (generateRandomID)
|
||
|
{
|
||
|
shortName = GetRandomID(5);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
shortName = String.Empty;
|
||
|
}
|
||
|
|
||
|
shortName = String.Concat(_shortNamePrefix, shortName, _controlShortNames.Count.ToString(CultureInfo.InvariantCulture));
|
||
|
_controlShortNames[clientID] = shortName;
|
||
|
return shortName;
|
||
|
}
|
||
|
|
||
|
// VSWhidbey 280485: We used to check '_' for default control id. But
|
||
|
// VSWhidbey 188477 removed the '_', so here it checks "ctl" with id
|
||
|
// separator (for naming container case) instead.
|
||
|
private bool HasUnnamedControlId(string clientID) {
|
||
|
const string unnamedIdPrefix = "ctl";
|
||
|
if (clientID.StartsWith(unnamedIdPrefix, StringComparison.Ordinal)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
string unnamedIdPrefixWithIdSeparator = Page.IdSeparator + unnamedIdPrefix;
|
||
|
int unnamedIdPrefixLength = unnamedIdPrefix.Length;
|
||
|
if (clientID.Length > unnamedIdPrefixLength &&
|
||
|
clientID.IndexOf(unnamedIdPrefixWithIdSeparator, unnamedIdPrefixLength, StringComparison.Ordinal) != -1) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
private String GetRandomID(int length)
|
||
|
{
|
||
|
Byte[] randomBytes = new Byte[length];
|
||
|
_random.NextBytes(randomBytes);
|
||
|
|
||
|
char[] randomChars = new char[length];
|
||
|
for (int i = 0; i < length; i++)
|
||
|
{
|
||
|
randomChars[i] = (char)((((int)randomBytes[i]) % 26) + 'a');
|
||
|
}
|
||
|
|
||
|
return new String(randomChars);
|
||
|
}
|
||
|
|
||
|
private bool NameConflicts(String name)
|
||
|
{
|
||
|
if (name == null)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Debug.Assert(_postBackEventTargetVarName.ToLower(CultureInfo.InvariantCulture) == _postBackEventTargetVarName &&
|
||
|
_postBackEventArgumentVarName.ToLower(CultureInfo.InvariantCulture) == _postBackEventArgumentVarName &&
|
||
|
_shortNamePrefix.ToLower(CultureInfo.InvariantCulture) == _shortNamePrefix);
|
||
|
|
||
|
name = name.ToLower(CultureInfo.InvariantCulture);
|
||
|
return name == _postBackEventTargetVarName ||
|
||
|
name == _postBackEventArgumentVarName ||
|
||
|
name.StartsWith(_shortNamePrefix, StringComparison.Ordinal);
|
||
|
}
|
||
|
|
||
|
private static readonly WmlLayout _defaultLayout =
|
||
|
new WmlLayout(Alignment.Left, Wrapping.Wrap);
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.DefaultLayout"]/*' />
|
||
|
protected virtual WmlLayout DefaultLayout
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _defaultLayout;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private WmlLayout CurrentLayout
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (_layoutStack.Count > 0)
|
||
|
{
|
||
|
return (WmlLayout)_layoutStack.Peek();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return DefaultLayout;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.PendingBreak"]/*' />
|
||
|
protected bool PendingBreak
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _pendingBreak;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_pendingBreak = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static readonly WmlFormat _defaultFormat =
|
||
|
new WmlFormat(false, false, FontSize.Normal);
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlMobileTextWriter.DefaultFormat"]/*' />
|
||
|
protected virtual WmlFormat DefaultFormat
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _defaultFormat;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private WmlFormat CurrentFormat
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (_formatStack.Count > 0)
|
||
|
{
|
||
|
return (WmlFormat)_formatStack.Peek();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return DefaultFormat;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private bool _requiresNoSoftkeyLabels = false;
|
||
|
private bool _haveRequiresNoSoftkeyLabels = false;
|
||
|
|
||
|
private bool RequiresNoSoftkeyLabels()
|
||
|
{
|
||
|
if (!_haveRequiresNoSoftkeyLabels)
|
||
|
{
|
||
|
String RequiresNoSoftkeyLabelsString = Device["requiresNoSoftkeyLabels"];
|
||
|
if (RequiresNoSoftkeyLabelsString == null)
|
||
|
{
|
||
|
_requiresNoSoftkeyLabels = false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_requiresNoSoftkeyLabels = Convert.ToBoolean(RequiresNoSoftkeyLabelsString, CultureInfo.InvariantCulture);
|
||
|
}
|
||
|
_haveRequiresNoSoftkeyLabels = true;
|
||
|
}
|
||
|
return _requiresNoSoftkeyLabels;
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlLayout"]/*' />
|
||
|
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
||
|
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
||
|
protected class WmlLayout
|
||
|
{
|
||
|
private Wrapping _wrap;
|
||
|
private Alignment _align;
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlLayout.WmlLayout"]/*' />
|
||
|
public WmlLayout(Style style, WmlLayout currentLayout)
|
||
|
{
|
||
|
Alignment align = (Alignment)style[Style.AlignmentKey, true];
|
||
|
Align = (align != Alignment.NotSet) ? align : currentLayout.Align;
|
||
|
Wrapping wrap = (Wrapping)style[Style.WrappingKey , true];
|
||
|
Wrap = (wrap != Wrapping.NotSet) ? wrap : currentLayout.Wrap;
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlLayout.WmlLayout1"]/*' />
|
||
|
public WmlLayout(Alignment alignment, Wrapping wrapping)
|
||
|
{
|
||
|
Align = alignment;
|
||
|
Wrap = wrapping;
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlLayout.Wrap"]/*' />
|
||
|
public Wrapping Wrap
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _wrap;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_wrap = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlLayout.Align"]/*' />
|
||
|
public Alignment Align
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _align;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_align = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlLayout.Compare"]/*' />
|
||
|
public virtual bool Compare(WmlLayout layout)
|
||
|
{
|
||
|
return Wrap == layout.Wrap && Align == layout.Align;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat"]/*' />
|
||
|
[AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
||
|
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
|
||
|
protected class WmlFormat
|
||
|
{
|
||
|
private bool _bold;
|
||
|
private bool _italic;
|
||
|
private FontSize _size;
|
||
|
private bool _writtenBold = false;
|
||
|
private bool _writtenItalic = false;
|
||
|
private bool _writtenSize = false;
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.WmlFormat"]/*' />
|
||
|
public WmlFormat(Style style, WmlFormat currentFormat)
|
||
|
{
|
||
|
BooleanOption bold = (BooleanOption)style[Style.BoldKey, true];
|
||
|
Bold = (bold != BooleanOption.NotSet) ? bold == BooleanOption.True : currentFormat.Bold;
|
||
|
BooleanOption italic = (BooleanOption)style[Style.ItalicKey, true];
|
||
|
Italic = (italic != BooleanOption.NotSet) ? italic == BooleanOption.True : currentFormat.Italic;
|
||
|
FontSize fontSize = (FontSize)style[Style.FontSizeKey, true];
|
||
|
Size = (fontSize != FontSize.NotSet) ? fontSize : currentFormat.Size;
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.WmlFormat1"]/*' />
|
||
|
public WmlFormat(bool bold, bool italic, FontSize size)
|
||
|
{
|
||
|
Bold = bold;
|
||
|
Italic = italic;
|
||
|
Size = size;
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.Bold"]/*' />
|
||
|
public bool Bold
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _bold;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_bold = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.Italic"]/*' />
|
||
|
public bool Italic
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _italic;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_italic = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.Size"]/*' />
|
||
|
public FontSize Size
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _size;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_size = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.WrittenBold"]/*' />
|
||
|
public bool WrittenBold
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _writtenBold;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_writtenBold = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.WrittenItalic"]/*' />
|
||
|
public bool WrittenItalic
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _writtenItalic;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_writtenItalic = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.WrittenSize"]/*' />
|
||
|
public bool WrittenSize
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return _writtenSize;
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
_writtenSize = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\WmlMobileTextWriter.uex' path='docs/doc[@for="WmlFormat.Compare"]/*' />
|
||
|
public virtual bool Compare(WmlFormat format)
|
||
|
{
|
||
|
return Bold == format.Bold &&
|
||
|
Italic == format.Italic &&
|
||
|
Size == format.Size;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|