Creating custom content blocks where the user can select an

Posted by Community Admin on 04-Aug-2018 11:32

Creating custom content blocks where the user can select an image

All Replies

Posted by Community Admin on 30-Jan-2012 00:00

Hi,

I have a requirement to create several custom content blocks of varying sizes that can dropped into templates (these will be formatted and styled using css and will have headers, images, text and links to pages), however they need to be fully customizable so that the content editor can select an image to load from the library, change the text, the header and the link as they are used in multiple places across the site.

The problem I am having at the moment is determining the best way of developing this to read an image from the Sitefinity library so that a content editor can add this to a user control. At present I will be developing about 7/8 user controls that will be used all over the site for consistent layout design, they will all include images that need to be selected.

I'm thinking along the lines of developing a custom control to read an image from the library but I think I'm not sure whether I'm over complicating this or whether something already exists in Sitefinity that I can already use to plug in to the user control?

Any advice appreciated...
Thanks

Posted by Community Admin on 31-Jan-2012 00:00

Hi, 

In regards to selecting images, I have worked from the following example:  www.sitefinity.com/.../how-to-create-a-simple-image-selector

I have then spoken to support and modified the example to use a built-in image selector/uploader uploader controls. 

Posted by Community Admin on 31-Jan-2012 00:00

Hi,

Thanks, I've had a look at that. The example after that shows use of the thumbnail selector in the News but I need a thumbnail selector that I can put inside my own user control (do you know how this would be done?). I want the user to be able to drag the widget onto the form, edit the properties to load an image, set text etc.

Thanks,
Paul

Posted by Community Admin on 01-Feb-2012 00:00

Hi Paul,

Could you please give more details about what you try to achieve? Does your user control have its own designer where you can put the image selector? If this is the case you could check the following blog post

http://www.sitefinity.com/blogs/joshmorales/posts/11-10-05/selecting_sitefinity_4_content_inside_widget_designers.aspx 

Greetings,
Lubomir Velkov
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 01-Feb-2012 00:00

Hi,
Thanks for the link, I will go through that and see if it solves my problem.

At present my ascx user control file contains the following:

<div class="box380Wrapper">
    <div class="box380ImgHr">  
        <h3><asp:Literal ID="TitleLiteral" Text="" runat="server"></asp:Literal></h3>
        <span class="gradientTitleBoxoutDetailed"></span>
         
        <asp:HyperLink ID="ImageLink" NavigateUrl='' runat="server">
            <img src="images/anyimage380x176.jpg" width="380" height="176" alt="Description" />
        </asp:HyperLink>
 
        <div class="copyBoxoutDetailed">
            <p>
                <asp:Literal ID="Content380" Text="Lorem ipsum dolor sit amet, etc" runat="server"></asp:Literal>
                <br />
                <span class="linkText">
                    <asp:HyperLink ID="CopyLink" NavigateUrl='' runat="server" Text="Call to action" />
                </span>
            </p>
        </div>
    </div>
</div>

This is just a simple template of a content block that will be used all over the site, it is styled to user requirements. However, the user will need to change the image, the image link, the content area link, the text on the content area link, the text in the content area and the Title. Most of the stuff I know how to do in a simple user control, what I don't understand is how to allow the user to select and change the image. I've looked at lots of things but seem to be going around in circles looking at writing custom image selectors, writing modules, using the module builder (my module wouldn't activate) and using shared content controls. It seems like a very simple task to do but every potential solution seems very complex and involved and I cannot work out which is the best one to use for my requirement.

Basically, I need to replace the image in the code above with something that the user can choose from the library when they drop the user control onto the Page. Shouldn't that be simple?

Thanks,
Paul

Posted by Community Admin on 06-Feb-2012 00:00

Hello Paul,

Well you could use the following markup in your designer .ascx file -

<sf:MediaContentSelectorView id="selectorView" runat="server"
 MediaContentItemsListDescriptionTemplate="Telerik.Sitefinity.Resources.Templates.Designers.Libraries.Images.ImageItemDescriptionTemplate.htm"
    LibraryBinderServiceUrl="~/Sitefinity/Services/Content/AlbumService.svc"
    MediaContentBinderServiceUrl="~/Sitefinity/Services/Content/ImageService.svc"
    DisplayResizingOptionsControl="false"
    ShowOpenOriginalSizeCheckBox="true">
</sf:MediaContentSelectorView>

This will allow you to select images from albums. Did the blog post I sent you not work out for you?

Kind regards,
Lubomir Velkov
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 06-Feb-2012 00:00

Hi Lubomir,
The code in the blog post did not work, there seems to be some sort of error in it as the edit dialog is blank. I removed some of the code and eventully got something on the edit dialog but it is still unable to select a page or an image from the library.

Regarding use of the MediaContentSelectorView, I previously raised a support ticket to ask if I should use this and I believe that you replied and said that it would not be appropriate. Are you now saying that this would be appropriate? I have been around the houses with this and am becoming very disillusioned with Sitefinity. What should have been an easy 1hr task to add an image to a control has taken days, which is crazy!

Is there anybody who can actually tell me what will work 100%? This is getting quite urgent now!

Thanks
Paul

Posted by Community Admin on 09-Feb-2012 00:00

Hi Paul,

Could you please elaborate what is the error that you get when you use the code from the blog post? It also would really help us if you could send us some of your code so we could install it on our side and see what is going wrong.

All the best,
Lubomir Velkov
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 09-Feb-2012 00:00

Hi Lubomir,

I Just came back to this after a few days on something else and the PageField and ImageField seem to work perfectly now. I compiled several times the first time but I guess it just wasn't having the JavaScript for some reason. There is one slight problem I'm just looking at however, whilst the PageSelection appears to work fine, the ImageSelection won't populate the user control image below if it is inside a HyperLink, any reason for this? I ideally want my image to link to a page! Additionally, If I remove it from the Hyperlink the image will be displayed but it appears degraded in quality from that in the library which is a concern as well!

<asp:HyperLink ID="ImageLink" NavigateUrl='' runat="server">
    <asp:Image ID="Thumbnail" runat="server" />
</asp:HyperLink>


Thanks,
Paul

Posted by Community Admin on 14-Feb-2012 00:00

Hi Paul,

About the quality - could you check what is the exact URL to the image? Does it contain ".tmb" in it? Also about your other question - I'm not sure why the image isn't populated when inside a link - I suppose sending us the code for your designer would help us a lot.

Greetings,
Lubomir Velkov
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 14-Feb-2012 00:00

Hi Lubomir,

Please see this thread regarding the image size, I have got everything working now apart from this...

http://www.sitefinity.com/devnet/forums/sitefinity-4-x/developing-with-sitefinity/imageloader-is-resizing-my-images-in-user-control.aspx#1984969

Thanks,
Paul

Posted by Community Admin on 17-Feb-2012 00:00

Hello Paul,

I'm not sure if you have noticed but one of the images has .tmb in its name, so it is in fact the image's thumbnail. Maybe this is why there are differences in the sizes?

Greetings,
Lubomir Velkov
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 17-Feb-2012 00:00

Hi again,

So I've looked at my other images on the site and they are all .tmb (thumbs), yet it is only the 380x176 image which is being resized to 345x160, all the others remain the same. Any reason why?

Paul

Posted by Community Admin on 22-Feb-2012 00:00

Hi Paul,

I couldn't quite understand what did you mean exactly. What does "my other images on the site" mean? Do you refer to images inside content block widgets that are inside pages?

Greetings,
Lubomir Velkov
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 22-Feb-2012 00:00

Hi,

I use the same code to create other content blocks that are smaller (i.e. with images of width 173 and 260). In each of these cases, a .tmb is displayed in the HTML however the image retains the actual width and height and has not been resized as it has been when I select the 380 width image.

My questions are:
1. Why does it have to use a thumbnail anyway?
2. Why is it only resizing the 380 width image when I use exactly the same code to select other size images from the library.

Thanks

Posted by Community Admin on 27-Feb-2012 00:00

Hi,

 1. The selector for images used in the control has a MediaContentItemListDescriptionTemplate of:

<a sys:href="javascript:void(0);" class="selectCommand">
    <img sys:src="ThumbnailUrl" sys:alt="Title" />
    <span class="imgSelect"> </span>
</a>
<div class="sfTooltipWrp" style="">
    <ul>
        <li>Title: Title</li>
        <li>Album: LibraryTitle</li>
        <li>Dimensions: WidthxHeight</li>
        <li>Created on DateCreated.sitefinityLocaleFormat('dd MMM, yyyy HH:mm')</li>
    </ul>
</div>
It is taking a thumbnail of the image.

2. I was looking for something specific in the implementation of the selector (MediaContentSelectorView), but found no restriction and resizing option. Can you send me the implementation of the widget you work with?
I have attached a sample widget that selects videos, but controls is the same and can be changed with image selector? Is there a difference in your control?
Greetings,
Ana
the Telerik team
Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items

Posted by Community Admin on 28-Feb-2012 00:00

Hi Ana

I cannot seem to attach a zip file so will include here the code that I use for selecting my images (It should be noted however that I use a common generic designer which seesm to work ok with other image selectors ok which is why this is so confusing why it is only resizing my images that are 380x176

Box380.ascx

<div class="box380Wrapper">
    <div class="box380ImgHr">
        <h3><asp:Literal ID="TitleLiteral" Text="" runat="server"></asp:Literal></h3>
        <span class="gradientTitleBoxoutDetailed"></span>
         
        <asp:HyperLink ID="ImageLink" runat="server" />
 
        <div class="copyBoxoutDetailed">
            <p>
                <asp:Literal ID="LitContent" runat="server"></asp:Literal>
                <br />
                <span class="linkText">
                    <asp:HyperLink ID="LinkNewPage" runat="server" />
                </span>
            </p>
        </div>
    </div>
</div>

Box380.ascx.cs
namespace xxxx.Widgets.ContentArea
    [ControlDesigner(typeof(Resources.GenericBoxDesigner))]
    public partial class Box380 : System.Web.UI.UserControl
    
        /// <summary>
        /// Gets or sets the url to the selected image
        /// </summary>
        /// <value>
        /// The selected image url.
        /// </value>
        public string SelectedImageSrc get; set;
 
        /// <summary>
        /// Gets or sets the ID of the selected page.
        /// </summary>
        /// <value>
        /// The selected page ID.
        /// </value>
        public Guid SelectedPageID get; set;
 
        /// <summary>
        /// The title to be displayed at the top of the Box
        /// </summary>
        public virtual string BoxTitle get; set;
 
        /// <summary>
        /// The text to be displayed within the Box
        /// </summary>
        public virtual string BoxText get; set;
 
        /// <summary>
        /// The text to be displayed on the link
        /// </summary>
        public virtual string LinkText
        
            get
            
                return this.linkText;
            
            set
            
                this.linkText = value;
            
        
        private string linkText = "Call to action";  // Default Value
 
 
        /// <summary>
        /// Page Load
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        
            // Check whether the BoxTitle is non null and assign it
            if (!String.IsNullOrEmpty(BoxTitle))
            
                TitleLiteral.Text = BoxTitle;
            
 
            // Check to see if the BoxText is non null and assign it
            if (!String.IsNullOrEmpty(BoxText))
            
                LitContent.Text = BoxText;
            
 
            // Check to see if the link text is non null and assign it
            if (!String.IsNullOrEmpty(LinkText))
            
                LinkNewPage.Text = LinkText;
            
 
            using (var api = App.WorkWith())
            
                // get selected page info
                var page = api.Pages().Where(p => p.Id == SelectedPageID).Get().FirstOrDefault();
                if (page != null)
                
                    var url = ResolveUrl(page.GetFullUrl());
                    ImageLink.NavigateUrl = url;
                    ImageLink.Text = page.Title;
                    LinkNewPage.NavigateUrl = url;
                
            
            // assign selected image
            ImageLink.ImageUrl = SelectedImageSrc;
        
    

GenericBoxDesigner.ascx
<div class="sfContentViews">
    <div id="Options">
        <div>
            <div class="item">
                <label class="sfTxtLbl">Box Title:</label>
                <input type="text" class="midField" id="boxTitle" />
            </div>
            <div class="item">
                <label class="sfTxtLbl">Link Text:</label>
                <input type="text" class="midField" id="linkText" />
            </div>
            <div class="item">
                <label class="sfTxtLbl">Box Text:</label>
                <asp:TextBox id="boxText" ClientIDMode="Static" Rows="8" Columns="60" TextMode="multiline" runat="server" />
            </div>
            <div id="groupSettingPageSelect">
                <ul class="sfTargetList">
                    <li class="item">
                        <label class="sfTxtLbl">Select Page Link:</label>
                        <sf:PageField ID="PageSelector" runat="server" WebServiceUrl="~/Sitefinity/Services/Pages/PagesService.svc/" DisplayMode="Write" />
                    </li>
                    <li>
                        <label class="sfTxtLbl">Select Image:</label>
                        <sitefinity:ImageField ID="ImageSelector" runat="server" DisplayMode="Write" UploadMode="Dialog" DataFieldName="Image" />
                    </li>
                </ul>
            </div>
        </div>
    </div>
</div>

GenericBoxDesigner.ascx.cs
namespace xxxx.Widgets.ContentArea.Resources
    public class GenericBoxDesigner : ControlDesignerBase
    
        /// <summary>
        /// Initializes the controls.
        /// </summary>
        /// <param name="container"></param>
        protected override void InitializeControls(Telerik.Sitefinity.Web.UI.GenericContainer container)
        
            // load in simple mode
            base.DesignerMode = ControlDesignerModes.Simple;
 
            // set root node for page selector
            PageSelector.RootNodeID = Telerik.Sitefinity.Abstractions.SiteInitializer.FrontendRootNodeId;
 
            // set the image selector type to use string (src)
            ImageSelector.DataFieldType = typeof(String);
        
 
        /// <summary>
        /// Gets the page selector.
        /// </summary>
        protected PageField PageSelector
        
            get return Container.GetControl<PageField>("PageSelector", true);
        
 
        /// <summary>
        /// Gets the image selector.
        /// </summary>
        protected ImageField ImageSelector
        
            get return Container.GetControl<ImageField>("ImageSelector", true);
        
 
        private string _layoutTemplatePath = "~/Widgets/ContentArea/Resources/GenericBoxDesigner.ascx";
        /// <summary>
        /// Gets or sets the path of the external template to be used by the control.
        /// </summary>
        public override string LayoutTemplatePath
        
            get return _layoutTemplatePath;
            set _layoutTemplatePath = value;
        
 
        private string _scriptPath = "~/Widgets/ContentArea/Resources/GenericBoxDesigner.js";
        /// <summary>
        /// Gets or sets the designer script path.
        /// </summary>
        /// <value>
        /// The designer script path.
        /// </value>
        public string DesignerScriptPath
        
            get return _scriptPath;
            set _scriptPath = value;
        
 
        /// <summary>
        /// Gets the name of the embedded layout template.
        /// </summary>
        protected override string LayoutTemplateName
        
            get return null;
        
 
        /// <summary>
        /// Gets a collection of <see cref="T:System.Web.UI.ScriptReference"/> objects that define script resources that the control requires.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerable"/> collection of <see cref="T:System.Web.UI.ScriptReference"/> objects.
        /// </returns>
        public override IEnumerable<ScriptReference> GetScriptReferences()
        
            var scripts = base.GetScriptReferences() as List<ScriptReference>;
            if (scripts == null) return base.GetScriptReferences();
 
            scripts.Add(new ScriptReference(DesignerScriptPath));
            return scripts.ToArray();
        
 
        /// <summary>
        /// Gets a collection of script descriptors that represent ECMAScript (JavaScript) client components.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerable"/> collection of <see cref="T:System.Web.UI.ScriptDescriptor"/> objects.
        /// </returns>
        public override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
        
            var descriptors = new List<ScriptDescriptor>(base.GetScriptDescriptors());
            var descriptor = (ScriptControlDescriptor)descriptors.Last();
            descriptor.AddComponentProperty("PageSelector", this.PageSelector.ClientID);
            descriptor.AddComponentProperty("ImageSelector", this.ImageSelector.ClientID);
            return descriptors;
        
    

GenericBoxDesigner.js
Type.registerNamespace("xxxx.Widgets.ContentArea.Resources");
 
xxxx.Widgets.ContentArea.Resources.GenericBoxDesigner = function (element)
    xxxx.Widgets.ContentArea.Resources.GenericBoxDesigner.initializeBase(this, [element]);
 
    this._PageSelector = null;
    this._ImageSelector = null;
    this._resizeControlDesignerDelegate = null;
 
xxxx.Widgets.ContentArea.Resources.GenericBoxDesigner.prototype =
    initialize: function ()
        xxxx.Widgets.ContentArea.Resources.GenericBoxDesigner.callBaseMethod(this, 'initialize');
    ,
    dispose: function ()
        xxxx.Widgets.ContentArea.Resources.GenericBoxDesigner.callBaseMethod(this, 'dispose');
    ,
    refreshUI: function ()
        var data = this._propertyEditor.get_control();
 
        this.resizeEvents();
 
        // Get Title
        jQuery("#boxTitle").val(data.BoxTitle);
        jQuery("#linkText").val(data.LinkText);
        jQuery("#boxText").val(data.BoxText);
 
        // load image src
        var i = this.get_ImageSelector();
        i.set_value(data.SelectedImageSrc);
 
        // load selected page
        var p = this.get_PageSelector();
        var pageid = data.SelectedPageID;
        if (pageid) p.set_value(pageid);
    ,
    applyChanges: function ()
        // save selected page
        var controlData = this._propertyEditor.get_control();
 
        controlData.BoxTitle = jQuery("#boxTitle").val();
        controlData.LinkText = jQuery("#linkText").val();
        controlData.BoxText = jQuery("#boxText").val(); 
 
        controlData.SelectedPageID = this.get_PageSelector().get_value();
 
        // save selected image
        var i = this.get_ImageSelector();
        controlData.SelectedImageSrc = i.get_value();
    ,
 
    // add resize events
    resizeEvents: function ()
        // resize on Page Select
        var s = this.get_PageSelector();
        s.add_selectorOpened(this._resizeControlDesigner);
        s.add_selectorClosed(this._resizeControlDesigner);
 
        // resize control designer on image selector load
        var i = this.get_ImageSelector();
        this._resizeControlDesignerDelegate = Function.createDelegate(this, this._resizeControlDesigner);
        $addHandler(i._replaceImageButtonElement, "click", this._resizeControlDesignerDelegate);
 
        // resize control designer on image selector mode toggle
        var d = i._asyncImageSelector._dialogModesSwitcher;
        d.add_valueChanged(this._resizeControlDesigner);
 
        // resize control designer on image selector cancel
        var a = i._asyncImageSelector._cancelLink;
        $addHandler(a, "click", this._resizeControlDesignerDelegate);
 
        // resize control designer on image selector save
        var s = i._asyncImageSelector._saveLink;
        $addHandler(s, "click", this._resizeControlDesignerDelegate);
 
        // resize control designer on image upload
        i._asyncImageSelector.get_uploaderView().add_onFileUploaded(this._resizeControlDesigner);
    ,
 
    // Page Selector
    get_PageSelector: function ()
        return this._PageSelector;
    ,
    set_PageSelector: function (value)
        this._PageSelector = value;
    ,
 
    // Image Selector
    get_ImageSelector: function ()
        return this._ImageSelector;
    ,
    set_ImageSelector: function (value)
        this._ImageSelector = value;
    ,
 
    // function to initialize resizer methods and handlers
    _resizeControlDesigner: function ()
        setTimeout("dialogBase.resizeToContent()", 100);
    
 
xxxx.Widgets.ContentArea.Resources.GenericBoxDesigner.registerClass('xxxx.Widgets.ContentArea.GenericBoxDesigner', Telerik.Sitefinity.Web.UI.ControlDesign.ControlDesignerBase);
if (typeof (Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();


Posted by Community Admin on 14-Apr-2012 00:00

Paul, did you ever manage to sort this out? 

I've got the same situation at the moment where I'm using the ImageField selector in the designer and the end result is a URL pointing to the .tmb image. If I (in Firefox) right click and view image I can see the incorrect URL. If I remove everything in the URL from .tmb onwards the correct size image is shown. 

Does anyone know why the thumbnail URL is extracted by default? 

Regards,
Jacques

Posted by Community Admin on 14-Apr-2012 00:00

Paul, did you ever manage to sort this out? 

I've got the same situation at the moment where I'm using the ImageField selector in the designer and the end result is a URL pointing to the .tmb image. If I (in Firefox) right click and view image I can see the incorrect URL. If I remove everything in the URL from .tmb onwards the correct size image is shown. 

Does anyone know why the thumbnail URL is extracted by default? 

Regards,
Jacques

Posted by Community Admin on 30-Apr-2012 00:00

I'm having the same trouble...

Can someone from Telerik respond??  Using the ImageSelector in a control designer, we get an image with the "tmb" in the URL, which is most definitely NOT what we want; we want the image! 

Mike

Posted by Community Admin on 30-Apr-2012 00:00

I have a number of designers using the ImageSelector.

However, I save the guid rather than the url.

data.imageId = selector.get_selectedImageItem().Id;  // save the image GUID

I have a read-only property on the public control that provides the MediaUrl by converting the current saved GUID value, and I use that read-only property to init the ImageSelector in the designer.
selector.set_value(data.imageMediaUrl); // init the selector with the read-only MediaUrl property

The biggest issue I have with the selector is the way the dialog is embedded into the base dialog of the designer, and lacks events for open/close of the dialog... so it's difficult (I haven't found a way) to size it properly.

Posted by Community Admin on 12-Jul-2012 00:00

Hi,

I never did solve this, it was on my previous contract, I ended up getting in contact with Telerik and they ultimately said there was a problem with the ImageSelector control, the exact details are in my old Inbox I'm afraid. Unfortunately for the project, which was for a major client, it affected the size of images that were selected on the home page, so we had to do something different.

Delays and errors like this not only affect projects but don't do developers any favours when work is promised by a certain date unfortunately as it took a long time to get to the bottom of it

Cheers to all who helped though,
Paul

Posted by Community Admin on 12-Jul-2012 00:00

Mike, are you still having trouble with getting the Thumbnail extension in your URL?  I was able to get the actual URL from the ImageField by using the following code.

applyChanges: function ()
       var data = this._propertyEditor.get_control();
       var imageId = this.get_ImageSelector();
       if (imageId && imageId.get_selectedImageItem()) data.ImageSrc = imageId.get_selectedImageItem().Url;

Posted by Community Admin on 12-Jul-2012 00:00

URL is not really the ideal reference to store, as it can change and then break your pages.

Storing the id (GUID) is preferable, and then use that to access the current URL at run-time.

Posted by Community Admin on 13-Jul-2012 00:00

I agree with you and I usually do use the GUID but Mike asked specifically for a way that doesn't use link to the thumbnail extension, I was giving him an alternative that would directly give him the link. The URL it returns is also a relative path, so it would it would work for multiple domains.

On the flip side, wouldn't using a GUID require an additional DB call that technically isn't necessary?

This thread is closed