e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
774 lines
39 KiB
C#
774 lines
39 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="XhtmlBasicControlAdapter.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Security.Permissions;
|
|
using System.Text;
|
|
using System.Web;
|
|
using System.Web.Mobile;
|
|
using System.Web.UI;
|
|
using System.Web.UI.MobileControls;
|
|
using System.Web.UI.MobileControls.Adapters;
|
|
using System.Configuration;
|
|
using System.Globalization;
|
|
using System.Web.Security;
|
|
|
|
#if COMPILING_FOR_SHIPPED_SOURCE
|
|
namespace System.Web.UI.MobileControls.ShippedAdapterSource.XhtmlAdapters
|
|
#else
|
|
namespace System.Web.UI.MobileControls.Adapters.XhtmlAdapters
|
|
#endif
|
|
{
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter"]/*' />
|
|
[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 XhtmlControlAdapter : ControlAdapter {
|
|
private bool _physicalCssClassPushed = false;
|
|
|
|
private bool IsRooted(String basepath) {
|
|
return(basepath == null || basepath.Length == 0 || basepath[0] == '/' || basepath[0] == '\\');
|
|
}
|
|
|
|
private bool IsRelativeUrl(string url) {
|
|
// If it has a protocol, it's not relative
|
|
if (url.IndexOf(":", StringComparison.Ordinal) != -1)
|
|
return false;
|
|
|
|
return !IsRooted(url);
|
|
}
|
|
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.PageAdapter"]/*' />
|
|
protected XhtmlPageAdapter PageAdapter {
|
|
get {
|
|
return Page.Adapter as XhtmlPageAdapter;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.Render"]/*' />
|
|
public override void Render(HtmlTextWriter writer) {
|
|
Render((XhtmlMobileTextWriter)writer);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.Render1"]/*' />
|
|
public virtual void Render(XhtmlMobileTextWriter writer) {
|
|
RenderChildren(writer);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderPostBackEventAsAnchor"]/*' />
|
|
protected virtual void RenderPostBackEventAsAnchor (
|
|
XhtmlMobileTextWriter writer,
|
|
String argument,
|
|
String linkText) {
|
|
RenderPostBackEventAsAnchor(writer, argument, linkText, null /* accessKey */, null /* style */, null /*cssClass */);
|
|
}
|
|
|
|
// For convenience in extensibility -not used internally. The overload with style and cssClass args is
|
|
// to be preferred. See ASURT 144034.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderPostBackEventAsAnchor1"]/*' />
|
|
protected virtual void RenderPostBackEventAsAnchor (
|
|
XhtmlMobileTextWriter writer,
|
|
String argument,
|
|
String linkText,
|
|
String accessKey) {
|
|
RenderPostBackEventAsAnchor(writer, argument, linkText, accessKey, null /* style */, null /* cssClass */);
|
|
}
|
|
|
|
// For Style/CssClass args, see ASURT 144034
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderPostBackEventAsAnchor2"]/*' />
|
|
protected virtual void RenderPostBackEventAsAnchor (
|
|
XhtmlMobileTextWriter writer,
|
|
String argument,
|
|
String linkText,
|
|
String accessKey,
|
|
Style style,
|
|
String cssClass) {
|
|
writer.WriteBeginTag("a");
|
|
writer.Write(" href=\"");
|
|
PageAdapter.RenderUrlPostBackEvent(writer, Control.UniqueID /* target */, argument);
|
|
writer.Write("\" ");
|
|
if (accessKey != null && accessKey.Length > 0) {
|
|
writer.WriteAttribute("accesskey", accessKey);
|
|
}
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] != "true") {
|
|
if (CssLocation != StyleSheetLocation.PhysicalFile) {
|
|
String className = writer.GetCssFormatClassName(style);
|
|
if (className != null) {
|
|
writer.WriteAttribute ("class", className);
|
|
}
|
|
}
|
|
else if (cssClass != null && cssClass.Length > 0) {
|
|
writer.WriteAttribute ("class", cssClass, true /* encode */);
|
|
}
|
|
}
|
|
writer.Write(">");
|
|
writer.WriteEncodedText(linkText);
|
|
writer.WriteEndTag("a");
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalSetPendingBreakAfterInline"]/*' />
|
|
protected virtual void ConditionalSetPendingBreakAfterInline (XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.BreaksOnInlineElements] == "true") {
|
|
return;
|
|
}
|
|
ConditionalSetPendingBreak(writer);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalSetPendingBreak"]/*' />
|
|
protected virtual void ConditionalSetPendingBreak (XhtmlMobileTextWriter writer) {
|
|
MobileControl mobileControl = Control as MobileControl;
|
|
if (mobileControl != null && mobileControl.BreakAfter) {
|
|
writer.SetPendingBreak ();
|
|
}
|
|
}
|
|
|
|
// Overloads for complex controls like list that compose list items. For these controls, the accessKey attribute
|
|
// for each link may be different from the accessKey attribute for the control.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderBeginLink"]/*' />
|
|
protected virtual void RenderBeginLink(XhtmlMobileTextWriter writer, String target, String accessKey, Style style, String cssClass) {
|
|
RenderBeginLink(writer, target, accessKey, style, cssClass, null /* title */);
|
|
}
|
|
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderBeginLink"]/*' />
|
|
protected virtual void RenderBeginLink(XhtmlMobileTextWriter writer, String target, String accessKey, Style style, String cssClass, String title) {
|
|
writer.WriteBeginTag("a");
|
|
writer.Write(" href=\"");
|
|
RenderHrefValue (writer, target);
|
|
writer.Write("\"");
|
|
if (accessKey != null && accessKey.Length > 0) {
|
|
writer.WriteAttribute("accesskey", accessKey, true);
|
|
}
|
|
if (CssLocation != StyleSheetLocation.PhysicalFile) {
|
|
String className = writer.GetCssFormatClassName(style);
|
|
if (className != null) {
|
|
writer.WriteAttribute ("class", className);
|
|
}
|
|
}
|
|
else if (cssClass != null && cssClass.Length > 0) {
|
|
writer.WriteAttribute ("class", cssClass, true /* encode */);
|
|
}
|
|
if (title != null && title.Length > 0) {
|
|
writer.WriteAttribute("title", title, true /* encode */);
|
|
}
|
|
writer.WriteLine(">");
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderBeginLink1"]/*' />
|
|
protected virtual void RenderBeginLink(XhtmlMobileTextWriter writer, String target) {
|
|
String attributeValue = ((IAttributeAccessor)Control).GetAttribute(XhtmlConstants.AccessKeyCustomAttribute);
|
|
RenderBeginLink(writer, target, attributeValue, null, null);
|
|
}
|
|
|
|
// Writes the href value for RenderBeginLink, depending on whether the target is a new form on the
|
|
// current page or a standard url (e.g., a new page).
|
|
private void RenderHrefValue (XhtmlMobileTextWriter writer, String target) {
|
|
bool appendCookielessDataDictionary = PageAdapter.PersistCookielessData &&
|
|
!target.StartsWith("http:", StringComparison.Ordinal) &&
|
|
!target.StartsWith("https:", StringComparison.Ordinal);
|
|
bool queryStringWritten = false;
|
|
|
|
// ASURT 144021
|
|
if (target == null || target.Length == 0) {
|
|
target = Page.Response.ApplyAppPathModifier(Control.TemplateSourceDirectory);
|
|
}
|
|
|
|
|
|
|
|
if (target.StartsWith(Constants.FormIDPrefix, StringComparison.Ordinal)) {
|
|
RenderFormNavigationHrefValue (writer, target);
|
|
appendCookielessDataDictionary = false;
|
|
}
|
|
else {
|
|
// For page adapter Control = null.
|
|
if (Control != null) {
|
|
target = Control.ResolveUrl(target);
|
|
}
|
|
|
|
// ASURT 147179
|
|
if ((String)Device["requiresAbsolutePostbackUrl"] == "true"
|
|
&& IsRelativeUrl(target)) {
|
|
String templateSourceDirectory = Page.TemplateSourceDirectory;
|
|
String prefix = writer.EncodeUrlInternal(Page.Response.ApplyAppPathModifier(Page.TemplateSourceDirectory));
|
|
if (prefix[prefix.Length - 1] != '/') {
|
|
prefix = prefix + '/';
|
|
}
|
|
target = prefix + target;
|
|
}
|
|
|
|
if ((String)Device[XhtmlConstants.SupportsUrlAttributeEncoding] != "false") {
|
|
writer.WriteEncodedText (target);
|
|
}
|
|
else {
|
|
writer.Write (target);
|
|
}
|
|
queryStringWritten = target.IndexOf ('?') != -1;
|
|
}
|
|
|
|
if (appendCookielessDataDictionary) {
|
|
RenderCookielessDataDictionaryInQueryString (writer, queryStringWritten);
|
|
}
|
|
}
|
|
|
|
// Writes an href postback event with semantics of form navigation (activation).
|
|
private void RenderFormNavigationHrefValue (XhtmlMobileTextWriter writer, String target) {
|
|
String prefix = Constants.FormIDPrefix;
|
|
Debug.Assert (target.StartsWith (prefix, StringComparison.Ordinal));
|
|
String name = target.Substring(prefix.Length);
|
|
Form form = Control.ResolveFormReference(name);
|
|
// EventTarget = Control, EventArg = Form has semantics navigate to (activate) the form.
|
|
PageAdapter.RenderUrlPostBackEvent (writer, Control.UniqueID /* target */, form.UniqueID /* argument */);
|
|
}
|
|
|
|
private void RenderCookielessDataDictionaryInQueryString (XhtmlMobileTextWriter writer, bool queryStringWritten) {
|
|
IDictionary dictionary = PageAdapter.CookielessDataDictionary;
|
|
if (dictionary != null) {
|
|
foreach (String name in dictionary.Keys) {
|
|
if (queryStringWritten) {
|
|
String amp = (String)Device[XhtmlConstants.SupportsUrlAttributeEncoding] != "false" ? "&" : "&";
|
|
writer.Write(amp);
|
|
}
|
|
else {
|
|
writer.Write ('?');
|
|
queryStringWritten = true;
|
|
}
|
|
writer.Write (name);
|
|
writer.Write ('=');
|
|
writer.Write (dictionary[name]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderEndLink"]/*' />
|
|
protected virtual void RenderEndLink(XhtmlMobileTextWriter writer) {
|
|
writer.WriteEndTag("a");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// SECONDARY UI SUPPORT
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
internal const int NotSecondaryUIInit = -1; // For initialization of private consts in derived classes.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.NotSecondaryUI"]/*' />
|
|
protected static readonly int NotSecondaryUI = NotSecondaryUIInit;
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.SecondaryUIMode"]/*' />
|
|
protected virtual int SecondaryUIMode {
|
|
get {
|
|
if (Control == null || Control.Form == null) {
|
|
return NotSecondaryUI;
|
|
}
|
|
else {
|
|
return((XhtmlFormAdapter)Control.Form.Adapter).GetSecondaryUIMode(Control);
|
|
}
|
|
}
|
|
set {
|
|
((XhtmlFormAdapter)Control.Form.Adapter).SetSecondaryUIMode(Control, value);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ExitSecondaryUIMode"]/*' />
|
|
protected virtual void ExitSecondaryUIMode() {
|
|
SecondaryUIMode = NotSecondaryUI;
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.LoadAdapterState"]/*' />
|
|
public override void LoadAdapterState(Object state) {
|
|
if (state != null) {
|
|
SecondaryUIMode = (int)state;
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.SaveAdapterState"]/*' />
|
|
public override Object SaveAdapterState() {
|
|
int mode = SecondaryUIMode;
|
|
if (mode != NotSecondaryUI) {
|
|
return mode;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// ENTER STYLE SUPPORT: These methods should, in general, be used in place
|
|
// of writer.EnterStyle, ExitStyle, etc. They check whether there is
|
|
// a cssLocation attribute on the active form, and enter style only if
|
|
// not.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalEnterStyle"]/*' />
|
|
protected virtual void ConditionalEnterStyle(XhtmlMobileTextWriter writer, Style style) {
|
|
ConditionalEnterStyle(writer, style, String.Empty);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalEnterStyle1"]/*' />
|
|
protected virtual void ConditionalEnterStyle(XhtmlMobileTextWriter writer, Style style, String tag) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
// Do nothing. Styles should be handled by CssClass custom attribute.
|
|
return;
|
|
}
|
|
if (tag == null || tag.Length == 0) {
|
|
writer.EnterStyle(style);
|
|
}
|
|
else {
|
|
writer.EnterStyle(style, tag);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalExitStyle"]/*' />
|
|
protected virtual void ConditionalExitStyle(XhtmlMobileTextWriter writer, Style style) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
// Do nothing. Styles should be handled by CssClass custom attribute.
|
|
return;
|
|
}
|
|
writer.ExitStyle(style);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalEnterFormat"]/*' />
|
|
protected virtual void ConditionalEnterFormat(XhtmlMobileTextWriter writer, Style style) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
// Do nothing. Styles should be handled by CssClass custom attribute.
|
|
return;
|
|
}
|
|
writer.EnterFormat(style);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalExitFormat"]/*' />
|
|
protected virtual void ConditionalExitFormat(XhtmlMobileTextWriter writer, Style style) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
// Do nothing. Styles should be handled by CssClass custom attribute.
|
|
return;
|
|
}
|
|
writer.ExitFormat(style);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalEnterLayout"]/*' />
|
|
protected virtual void ConditionalEnterLayout(XhtmlMobileTextWriter writer, Style style) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
// Do nothing. Styles should be handled by CssClass custom attribute.
|
|
return;
|
|
}
|
|
writer.EnterLayout(style);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalExitLayout"]/*' />
|
|
protected virtual void ConditionalExitLayout(XhtmlMobileTextWriter writer, Style style) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
// Do nothing. Styles should be handled by CssClass custom attribute.
|
|
return;
|
|
}
|
|
writer.ExitLayout(style);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// STYLESHEET LOCATION SUPPORT
|
|
// Use for determining whether stylesheet is physical or virtual, and
|
|
// where it is located (application cache, session state, or a physical
|
|
// directory).
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// For intelligibility at point of call.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.StyleSheetLocationAttributeValue"]/*' />
|
|
protected virtual String StyleSheetLocationAttributeValue {
|
|
get{
|
|
return(String) Page.ActiveForm.CustomAttributes[XhtmlConstants.StyleSheetLocationCustomAttribute];
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.StyleSheetStorageApplicationSetting"]/*' />
|
|
protected virtual String StyleSheetStorageApplicationSetting {
|
|
get {
|
|
return(String) ConfigurationManager.AppSettings[XhtmlConstants.CssStateLocationAppSettingKey];
|
|
}
|
|
}
|
|
|
|
// Add new supported markups here.
|
|
private Doctype _documentType = Doctype.NotSet;
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.DocumentType"]/*' />
|
|
protected virtual Doctype DocumentType {
|
|
get{
|
|
if (_documentType != Doctype.NotSet) {
|
|
return _documentType;
|
|
}
|
|
if ((String)Device[XhtmlConstants.RequiresOnEnterForward] == "true") {
|
|
return Doctype.Wml20;
|
|
}
|
|
// Use capability rather than preferred rendering type header for accuracy.
|
|
String browserCap = Device[XhtmlConstants.InternalStyleConfigSetting];
|
|
// Send internal styles by default.
|
|
if (browserCap == null || !String.Equals(browserCap, "false", StringComparison.OrdinalIgnoreCase))
|
|
return _documentType = Doctype.XhtmlMobileProfile;
|
|
else
|
|
return _documentType = Doctype.XhtmlBasic;
|
|
}
|
|
}
|
|
|
|
private StyleSheetLocation _cssLocation = StyleSheetLocation.NotSet;
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.CssLocation"]/*' />
|
|
protected virtual StyleSheetLocation CssLocation {
|
|
get {
|
|
if (_cssLocation != StyleSheetLocation.NotSet) {
|
|
return _cssLocation;
|
|
}
|
|
if (StyleSheetLocationAttributeValue != null && StyleSheetLocationAttributeValue.Length > 0) {
|
|
return _cssLocation = StyleSheetLocation.PhysicalFile;
|
|
}
|
|
if (DocumentType == Doctype.XhtmlMobileProfile || DocumentType == Doctype.Wml20) {
|
|
return _cssLocation = StyleSheetLocation.Internal;
|
|
}
|
|
// if (String.Compare(StyleSheetStorageApplicationSetting, XhtmlConstants.CacheStyleSheetValue, ((true /* ignore case */) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) == 0) {
|
|
if (String.Compare(StyleSheetStorageApplicationSetting, XhtmlConstants.CacheStyleSheetValue, StringComparison.OrdinalIgnoreCase) == 0) {
|
|
return _cssLocation = StyleSheetLocation.ApplicationCache;
|
|
}
|
|
return _cssLocation = StyleSheetLocation.SessionState;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// CSSCLASS CUSTOM ATTRIBUTE / PHYSICAL STYLESHEET SUPPORT
|
|
// The cssClass custom attribute should only be honored if we are using a physical
|
|
// stylesheet.
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// The use of _physicalCssClassPushed precludes nesting calls to ConditionalRenderClassAttribute, ConditionalRenderOpeningSpanElement,
|
|
// ConditionalRenderClosingSpanElement, etc. The ConditionalRenderOpening call and ConditionalRenderClosing call must be paired without
|
|
// nesting. ConditionalRenderClassAttribute is to be paired with ConditionalPopPhysicalCssClass (without nesting).
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderClassAttribute"]/*' />
|
|
protected virtual void ConditionalRenderClassAttribute(XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
String classAttribute = (String) Control.CustomAttributes[XhtmlConstants.CssClassCustomAttribute];
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile &&
|
|
classAttribute != null &&
|
|
classAttribute.Length > 0 &&
|
|
writer.DiffersFromCurrentPhysicalCssClass(classAttribute)) {
|
|
writer.WriteAttribute("class", classAttribute);
|
|
writer.PushPhysicalCssClass(classAttribute);
|
|
Debug.Assert(!_physicalCssClassPushed, "These calls should not be nested.");
|
|
_physicalCssClassPushed = true;
|
|
}
|
|
}
|
|
|
|
private bool _physicalSpanClassOpen = false;
|
|
// Render opening <span class=...> in case the stylesheet location has been specified as a physical file.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderOpeningSpanElement"]/*' />
|
|
protected virtual void ConditionalRenderOpeningSpanElement(XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
String classAttribute = (String) Control.CustomAttributes[XhtmlConstants.CssClassCustomAttribute];
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile &&
|
|
classAttribute != null &&
|
|
classAttribute.Length > 0 &&
|
|
writer.DiffersFromCurrentPhysicalCssClass(classAttribute)) {
|
|
writer.WriteLine();
|
|
writer.WriteBeginTag("span");
|
|
writer.WriteAttribute("class", classAttribute, true /*encode*/);
|
|
writer.Write(">");
|
|
writer.PushPhysicalCssClass(classAttribute);
|
|
_physicalSpanClassOpen = true;
|
|
Debug.Assert(!_physicalCssClassPushed, "These calls should not be nested.");
|
|
_physicalCssClassPushed = true;
|
|
}
|
|
}
|
|
|
|
// Render closing </span> in case the stylesheet location has been specified as a physical file.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderClosingSpanElement"]/*' />
|
|
protected virtual void ConditionalRenderClosingSpanElement(XhtmlMobileTextWriter writer) {
|
|
String classAttribute = (String) Control.CustomAttributes[XhtmlConstants.CssClassCustomAttribute];
|
|
if (_physicalSpanClassOpen) {
|
|
Debug.Assert(_physicalCssClassPushed, "_physicalSpanClassOpen implies _physicalCssClassPushed");
|
|
writer.WriteEndTag("span");
|
|
writer.WriteLine();
|
|
ConditionalPopPhysicalCssClass(writer); // resets _physicalCssClassPushed
|
|
_physicalSpanClassOpen = false;
|
|
}
|
|
}
|
|
|
|
// Render opening <div class=...> in case the stylesheet location has been specified as a physical file.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderOpeningDivElement"]/*' />
|
|
protected virtual void ConditionalRenderOpeningDivElement(XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
String classAttribute = (String) Control.CustomAttributes[XhtmlConstants.CssClassCustomAttribute];
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
writer.WriteLine();
|
|
if ((String)Device["usePOverDiv"] == "true") {
|
|
writer.WriteBeginTag("p");
|
|
}
|
|
else {
|
|
writer.WriteBeginTag("div");
|
|
}
|
|
if (classAttribute != null &&
|
|
classAttribute.Length > 0 &&
|
|
writer.DiffersFromCurrentPhysicalCssClass(classAttribute)) {
|
|
writer.WriteAttribute("class", classAttribute, true);
|
|
writer.PushPhysicalCssClass(classAttribute);
|
|
Debug.Assert(!_physicalCssClassPushed, "These calls should not be nested.");
|
|
_physicalCssClassPushed = true;
|
|
}
|
|
writer.Write(">");
|
|
}
|
|
}
|
|
|
|
// Render closing </div> in case the stylesheet location has been specified as a physical file.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderClosingDivElement"]/*' />
|
|
protected virtual void ConditionalRenderClosingDivElement(XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] == "true") {
|
|
return;
|
|
}
|
|
String classAttribute = (String) Control.CustomAttributes[XhtmlConstants.CssClassCustomAttribute];
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile) {
|
|
writer.WriteLine();
|
|
if ((String)Device["usePOverDiv"] == "true") {
|
|
writer.WriteEndTag("p");
|
|
}
|
|
else {
|
|
writer.WriteEndTag("div");
|
|
}
|
|
writer.WriteLine();
|
|
ConditionalPopPhysicalCssClass(writer);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalPopPhysicalCssClass"]/*' />
|
|
protected virtual void ConditionalPopPhysicalCssClass(XhtmlMobileTextWriter writer) {
|
|
if (_physicalCssClassPushed) {
|
|
writer.PopPhysicalCssClass();
|
|
_physicalCssClassPushed = false;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// GENERAL CUSTOM ATTRIBUTE SUPPORT
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// Plays same role as HtmlAdapter.AddCustomAttribute. Named for consistency
|
|
// within Xhtml adapter set.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderCustomAttribute"]/*' />
|
|
protected virtual void ConditionalRenderCustomAttribute(XhtmlMobileTextWriter writer,
|
|
String attributeName) {
|
|
ConditionalRenderCustomAttribute(writer, attributeName, attributeName);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalRenderCustomAttribute1"]/*' />
|
|
protected virtual void ConditionalRenderCustomAttribute(XhtmlMobileTextWriter writer,
|
|
String attributeName, String markupAttributeName) {
|
|
String attributeValue = ((IAttributeAccessor)Control).GetAttribute(attributeName);
|
|
if (attributeValue != null && attributeValue.Length > 0) {
|
|
writer.WriteAttribute(markupAttributeName, attributeValue, true);
|
|
}
|
|
}
|
|
|
|
// Utilities to increase intelligibility
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.GetCustomAttributeValue"]/*' />
|
|
protected virtual String GetCustomAttributeValue(String attributeName) {
|
|
return((IAttributeAccessor)Control).GetAttribute(attributeName);
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.GetCustomAttributeValue1"]/*' />
|
|
protected virtual String GetCustomAttributeValue(MobileControl control, String attributeName) {
|
|
return((IAttributeAccessor)control).GetAttribute(attributeName);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
// SPECIALIZED UTILITY METHODS FOR LIST SELECTIONLIST OBJECTLIST
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// tagname can be any of table, ul, ol. See the list adapters for examples.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderOpeningListTag"]/*' />
|
|
protected virtual void RenderOpeningListTag(XhtmlMobileTextWriter writer, String tagName) {
|
|
String classAttribute = (String) Control.CustomAttributes[XhtmlConstants.CssClassCustomAttribute];
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile && (String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] != "true") {
|
|
writer.WritePendingBreak();
|
|
writer.WriteBeginTag(tagName);
|
|
if (classAttribute != null &&
|
|
classAttribute.Length > 0 &&
|
|
writer.DiffersFromCurrentPhysicalCssClass(classAttribute)) {
|
|
writer.WriteAttribute("class", classAttribute, true);
|
|
writer.PushPhysicalCssClass(classAttribute);
|
|
Debug.Assert(!_physicalCssClassPushed, "These calls should not be nested.");
|
|
_physicalCssClassPushed = true;
|
|
}
|
|
writer.Write(">");
|
|
}
|
|
else if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] != "true") {
|
|
writer.WritePendingBreak();
|
|
StyleFilter filter = writer.CurrentStyleClass.GetFilter(Style);
|
|
writer.EnterStyle(new XhtmlFormatStyleClass(Style, filter), tagName);
|
|
}
|
|
else {
|
|
writer.WritePendingBreak();
|
|
writer.WriteFullBeginTag(tagName);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderClosingListTag"]/*' />
|
|
protected virtual void RenderClosingListTag(XhtmlMobileTextWriter writer, String tagName) {
|
|
if (CssLocation == StyleSheetLocation.PhysicalFile && (String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] != "true") {
|
|
writer.WriteEndTag(tagName);
|
|
ConditionalPopPhysicalCssClass(writer);
|
|
}
|
|
else if ((String)Device[XhtmlConstants.RequiresXhtmlCssSuppression] != "true") {
|
|
writer.ExitStyle(Style);
|
|
}
|
|
else {
|
|
writer.WriteEndTag(tagName);
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ClearPendingBreakIfDeviceBreaksOnBlockLevel"]/*' />
|
|
protected virtual void ClearPendingBreakIfDeviceBreaksOnBlockLevel(XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.BreaksOnBlockElements] != "false") {
|
|
writer.ClearPendingBreak();
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalClearPendingBreak"]/*' />
|
|
protected virtual void ConditionalClearPendingBreak(XhtmlMobileTextWriter writer) {
|
|
if ((String)Device[XhtmlConstants.BreaksOnInlineElements] == "true") {
|
|
writer.ClearPendingBreak();
|
|
}
|
|
}
|
|
|
|
// Required for a very rare device case where <select> cannot follow <table>.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.ConditionalClearCachedEndTag"]/*' />
|
|
protected virtual void ConditionalClearCachedEndTag(XhtmlMobileTextWriter writer, String s) {
|
|
if (s != null && s.Length > 0) {
|
|
writer.ClearCachedEndTag ();
|
|
}
|
|
}
|
|
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderAsHiddenInputField"]/*' />
|
|
protected virtual void RenderAsHiddenInputField(XhtmlMobileTextWriter writer) {
|
|
}
|
|
|
|
// Renders hidden variables for IPostBackDataHandlers which are
|
|
// not displayed due to pagination or secondary UI.
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.RenderOffPageVariables"]/*' />
|
|
protected void RenderOffPageVariables(XhtmlMobileTextWriter writer, Control control, int page) {
|
|
if (control.HasControls()) {
|
|
foreach (Control child in control.Controls) {
|
|
// Note: Control.Form != null.
|
|
if (!child.Visible || child == Control.Form.Header || child == Control.Form.Footer) {
|
|
continue;
|
|
}
|
|
|
|
MobileControl mobileCtl = child as MobileControl;
|
|
|
|
if (mobileCtl != null) {
|
|
if (mobileCtl.IsVisibleOnPage(page)
|
|
&& (mobileCtl == ((XhtmlFormAdapter)mobileCtl.Form.Adapter).SecondaryUIControl ||
|
|
null == ((XhtmlFormAdapter)mobileCtl.Form.Adapter).SecondaryUIControl)) {
|
|
if (mobileCtl.FirstPage == mobileCtl.LastPage) {
|
|
// Entire control is visible on this page, so no need to look
|
|
// into children.
|
|
continue;
|
|
}
|
|
|
|
// Control takes up more than one page, so it may be possible that
|
|
// its children are on a different page, so we'll continue to
|
|
// fall through into children.
|
|
}
|
|
else if (mobileCtl is IPostBackDataHandler) {
|
|
XhtmlControlAdapter adapter = mobileCtl.Adapter as XhtmlControlAdapter;
|
|
if (adapter != null) {
|
|
adapter.RenderAsHiddenInputField(writer);
|
|
}
|
|
}
|
|
}
|
|
RenderOffPageVariables(writer, child, page);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string AMP = "&";
|
|
/// <include file='doc\XhtmlBasicControlAdapter.uex' path='docs/doc[@for="XhtmlControlAdapter.PreprocessQueryString"]/*' />
|
|
protected String PreprocessQueryString(String queryString) {
|
|
StringBuilder processedString = new StringBuilder();
|
|
int offset = 0;
|
|
int pos = 0;
|
|
int length = queryString.Length;
|
|
|
|
// ASURT 143419
|
|
while (offset < length) {
|
|
pos = queryString.IndexOf(AMP, offset, StringComparison.Ordinal);
|
|
if (pos == -1) {
|
|
processedString.Append(queryString.Substring(offset, queryString.Length - offset));
|
|
break;
|
|
}
|
|
|
|
if (pos != 0) {
|
|
processedString.Append(queryString.Substring(offset, pos - offset + 1));
|
|
}
|
|
do {
|
|
pos++;
|
|
} while (pos < length && queryString[pos] == '&');
|
|
offset = pos;
|
|
}
|
|
queryString = processedString.ToString();
|
|
|
|
// ASURT 144130
|
|
if (PageAdapter.PersistCookielessData == false) {
|
|
queryString = RemoveQueryStringPair(FormsAuthentication.FormsCookieName, queryString);
|
|
}
|
|
|
|
// ASURT 145389
|
|
queryString = RemoveQueryStringPair("x-up-destcharset", queryString);
|
|
return queryString;
|
|
}
|
|
|
|
private String RemoveQueryStringPair(String name, String queryString) {
|
|
int pos = queryString.IndexOf(name, StringComparison.Ordinal);
|
|
if (pos != -1) {
|
|
int pos2 = queryString.IndexOf(AMP, pos, StringComparison.Ordinal);
|
|
|
|
if (pos2 != -1) {
|
|
queryString = queryString.Remove(pos, pos2-pos+1);
|
|
}
|
|
else {
|
|
pos2 = queryString.IndexOf(AMP, StringComparison.Ordinal);
|
|
if ((pos2 != -1) && (pos2 < pos)) {
|
|
queryString = queryString.Substring(0, pos-1);
|
|
}
|
|
else {
|
|
queryString = queryString.Substring(0, pos);
|
|
}
|
|
}
|
|
}
|
|
return queryString;
|
|
}
|
|
}
|
|
}
|