File: UI\WebControls\ImageMap.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
//------------------------------------------------------------------------------
// <copyright file="ImageMap.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.UI.WebControls {
 
    using System;
    using System.ComponentModel;
    using System.Globalization;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.Util;
    using System.Web;
 
    /// <devdoc>
    /// <para>ImageMap class.  Provides support for multiple
    /// region-defined actions within an image.</para>
    /// </devdoc>
    [
    DefaultEvent("Click"),
    DefaultProperty("HotSpots"),
    ParseChildren(true, "HotSpots"),
    SupportsEventValidation,
    ]
    public class ImageMap : Image, IPostBackEventHandler {
 
        private static readonly object EventClick = new object();
        private bool _hasHotSpots;
        private HotSpotCollection _hotSpots;
 
        [
        Browsable(true),
        EditorBrowsableAttribute(EditorBrowsableState.Always)
        ]
        public override bool Enabled {
            get {
                return base.Enabled;
            }
            set {
                base.Enabled = value;
            }
        }
 
        /// <devdoc>
        /// <para>Gets the HotSpotCollection with defines the regions of ImageMap hot spots.</para>
        /// </devdoc>
        [
        WebCategory("Behavior"),
        WebSysDescription(SR.ImageMap_HotSpots),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
        NotifyParentProperty(true),
        PersistenceMode(PersistenceMode.InnerDefaultProperty)
        ]
        public HotSpotCollection HotSpots {
            get {
                if (_hotSpots == null) {
                    _hotSpots = new HotSpotCollection();
                    if (IsTrackingViewState) {
                        ((IStateManager)_hotSpots).TrackViewState();
                    }
                }
                return _hotSpots;
            }
        }
 
 
        /// <devdoc>
        /// <para>Gets or sets the HotSpotMode to either postback or navigation.</para>
        /// </devdoc>
        [
        WebCategory("Behavior"),
        DefaultValue(HotSpotMode.NotSet),
        WebSysDescription(SR.HotSpot_HotSpotMode),
        ]
        public virtual HotSpotMode HotSpotMode {
            get {
                object obj = ViewState["HotSpotMode"];
                return (obj == null) ? HotSpotMode.NotSet : (HotSpotMode)obj;
            }
            set {
                if (value < HotSpotMode.NotSet || value > HotSpotMode.Inactive) {
                    throw new ArgumentOutOfRangeException("value");
                }
                ViewState["HotSpotMode"] = value;
            }
        }
 
 
        /// <devdoc>
        /// <para>Gets or sets the name of the window for navigation.</para>
        /// </devdoc>
        [
        WebCategory("Behavior"),
        DefaultValue(""),
        WebSysDescription(SR.HotSpot_Target),
        ]
        public virtual string Target {
            get {
                object value = ViewState["Target"];
                return (value == null)? String.Empty : (string)value;
            }
            set {
                ViewState["Target"] = value;
            }
        }
 
        /// <devdoc>
        /// <para>The event raised when a hotspot is clicked.</para>
        /// </devdoc>
        [
        Category("Action"),
        WebSysDescription(SR.ImageMap_Click)
        ]
        public event ImageMapEventHandler Click {
            add {
                Events.AddHandler(EventClick, value);
            }
            remove {
                Events.RemoveHandler(EventClick, value);
            }
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Overridden to add the "usemap" attribute the the image tag.
        /// Overrides WebControl.AddAttributesToRender.</para>
        /// </devdoc>
        protected override void AddAttributesToRender(HtmlTextWriter writer) {
            base.AddAttributesToRender(writer);
 
            if (_hasHotSpots) {
                writer.AddAttribute(HtmlTextWriterAttribute.Usemap, "#ImageMap" + ClientID, false);
            }
        }
 
        /// <devdoc>
        /// <para>Restores view-state information that was saved by SaveViewState.
        /// Implements IStateManager.LoadViewState.</para>
        /// </devdoc>
        protected override void LoadViewState(object savedState) {
            object baseState = null;
            object[] myState = null;
 
            if (savedState != null) {
                myState = (object[])savedState;
                if (myState.Length != 2) {
                    throw new ArgumentException(SR.GetString(SR.ViewState_InvalidViewState));
                }
 
                baseState = myState[0];
            }
 
            base.LoadViewState(baseState);
 
            if ((myState != null) && (myState[1] != null)) {
                ((IStateManager)HotSpots).LoadViewState(myState[1]);
            }
        }
 
 
        /// <devdoc>
        /// <para>Called when the user clicks the ImageMap.</para>
        /// </devdoc>
        protected virtual void OnClick(ImageMapEventArgs e) {
            ImageMapEventHandler clickHandler = (ImageMapEventHandler)Events[EventClick];
            if (clickHandler != null) {
                clickHandler(this, e);
            }
        }
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Sends server control content to a provided HtmlTextWriter, which writes the content
        /// to be rendered to the client.
        /// Overrides Control.Render.</para>
        /// </devdoc>
        protected internal override void Render(HtmlTextWriter writer) {
            if (Enabled && !IsEnabled && SupportsDisabledAttribute) {
                // We need to do the cascade effect on the server, because the browser
                // only renders as disabled, but doesn't disable the functionality.
                writer.AddAttribute(HtmlTextWriterAttribute.Disabled, "disabled");
            }
 
            _hasHotSpots = ((_hotSpots != null) && (_hotSpots.Count > 0));
 
            base.Render(writer);
 
            if (_hasHotSpots) {
                string fullClientID = "ImageMap" + ClientID;
                writer.AddAttribute(HtmlTextWriterAttribute.Name, fullClientID);
                writer.AddAttribute(HtmlTextWriterAttribute.Id, fullClientID);
                writer.RenderBeginTag(HtmlTextWriterTag.Map);
 
                HotSpotMode mapMode = HotSpotMode;
                if (mapMode == HotSpotMode.NotSet) {
                    mapMode = HotSpotMode.Navigate;
                }
                HotSpotMode spotMode;
                int hotSpotIndex = 0;
                string controlTarget = Target;
                foreach (HotSpot item in _hotSpots) {
                    writer.AddAttribute(HtmlTextWriterAttribute.Shape, item.MarkupName, false);
                    writer.AddAttribute(HtmlTextWriterAttribute.Coords, item.GetCoordinates());
                    spotMode = item.HotSpotMode;
                    if (spotMode == HotSpotMode.NotSet) {
                        spotMode = mapMode;
                    }
                    if (spotMode == HotSpotMode.PostBack) {
                        // Make sure the page has a server side form if we are posting back
                        if (Page != null) {
                            Page.VerifyRenderingInServerForm(this);
                        }
                        if ((RenderingCompatibility < VersionUtil.Framework40) || IsEnabled) {
                            string eventArgument = hotSpotIndex.ToString(CultureInfo.InvariantCulture);
                            writer.AddAttribute(HtmlTextWriterAttribute.Href,
                                Page.ClientScript.GetPostBackClientHyperlink(this, eventArgument, true));
                        }
                    }
                    else if (spotMode == HotSpotMode.Navigate) {
                        if ((RenderingCompatibility < VersionUtil.Framework40) || IsEnabled) {
                            String resolvedUrl = ResolveClientUrl(item.NavigateUrl);
                            writer.AddAttribute(HtmlTextWriterAttribute.Href, resolvedUrl);
                        }
                        // Use HotSpot target first, if not specified, use ImageMap's target
                        string target = item.Target;
                        if (target.Length == 0) target = controlTarget;
                        if (target.Length > 0) writer.AddAttribute(HtmlTextWriterAttribute.Target, target);
                    }
                    else if (spotMode == HotSpotMode.Inactive) {
                        writer.AddAttribute("nohref", "true");
                    }
                    writer.AddAttribute(HtmlTextWriterAttribute.Title, item.AlternateText);
                    writer.AddAttribute(HtmlTextWriterAttribute.Alt, item.AlternateText);
                    string s = item.AccessKey;
                    if (s.Length > 0) {
                        writer.AddAttribute(HtmlTextWriterAttribute.Accesskey, s);
                    }
                    int n = item.TabIndex;
                    if (n != 0) {
                        writer.AddAttribute(HtmlTextWriterAttribute.Tabindex, n.ToString(NumberFormatInfo.InvariantInfo));
                    }
 
                    writer.RenderBeginTag(HtmlTextWriterTag.Area);
                    writer.RenderEndTag();
                    ++hotSpotIndex;
                }
                writer.RenderEndTag();  // Map
            }
        }
 
 
        /// <devdoc>
        /// <para>Saves any server control view-state changes that have
        /// occurred since the time the page was posted back to the server.
        /// Implements IStateManager.SaveViewState.</para>
        /// </devdoc>
        protected override object SaveViewState() {
            object baseState = base.SaveViewState();
            object hotSpotsState = null;
 
            if ((_hotSpots != null) && (_hotSpots.Count > 0)) {
                hotSpotsState = ((IStateManager)_hotSpots).SaveViewState();
            }
 
            if ((baseState != null) || (hotSpotsState != null)) {
                object[] savedState = new object[2];
                savedState[0] = baseState;
                savedState[1] = hotSpotsState;
 
                return savedState;
            }
 
            return null;
        }
 
 
        /// <devdoc>
        /// <para>Causes the tracking of view-state changes to the server control.
        /// Implements IStateManager.TrackViewState.</para>
        /// </devdoc>
        protected override void TrackViewState() {
            base.TrackViewState();
            if (_hotSpots != null) {
                ((IStateManager)_hotSpots).TrackViewState();
            }
        }
 
        #region Implementation of IPostBackEventHandler
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Notifies the server control that caused the postback that
        /// it should handle an incoming post back event.
        /// Implements IPostBackEventHandler.</para>
        /// </devdoc>
        void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
            RaisePostBackEvent(eventArgument);
        }
 
 
        /// <internalonly/>
        /// <devdoc>
        /// <para>Notifies the server control that caused the postback that
        /// it should handle an incoming post back event.
        /// Implements IPostBackEventHandler.</para>
        /// </devdoc>
        protected virtual void RaisePostBackEvent(string eventArgument) {
            ValidateEvent(UniqueID, eventArgument);
 
            string postBackValue = null;
            if (eventArgument != null && _hotSpots != null) {
                int hotSpotIndex = Int32.Parse(eventArgument, CultureInfo.InvariantCulture);
 
                if (hotSpotIndex >= 0 && hotSpotIndex < _hotSpots.Count) {
                    HotSpot hotSpot = _hotSpots[hotSpotIndex];
                    HotSpotMode mode = hotSpot.HotSpotMode;
                    if (mode == HotSpotMode.NotSet) {
                        mode = HotSpotMode;
                    }
                    if (mode == HotSpotMode.PostBack) {
                        postBackValue = hotSpot.PostBackValue;
                    }
                }
            }
            // Ignore invalid indexes silently(VSWhidbey 185738)
            if (postBackValue != null) {
                OnClick(new ImageMapEventArgs(postBackValue));
            }
        }
        #endregion
    }
}