views:

65

answers:

4

I have quickie:

When you code/develop themes, how do you link to various files in your html/css code?

Example: We at our firm use mostly <base target="http://whatever"&gt; in our main template and then just <img src="./images/file.png"> in our html, "/category/page" as links and something alike in our css.

However, when testing on different machines, we use ip address rather than localhost on main dev station of coder, so all base links don't work (because localhost goes to viewing machine, not coder's, in our network).

Same thing happens when updating pages - on dev server, we have to edit base target, so browsing site won't take us to live site - this part is actually rather simple PHP (if ... echo else echo something else), but it still not solve problem of more coding-testing problems.

So, my question is, how do YOU solve it? How do you use relative links, which basically don't care for what domain is the page on and don't care for url rewrite? (because ../images/ is different for / and different for /something/somethingElse/page)?

A: 

Personally I always use absolute paths (i.e. /path/to/file.css) and steer clear of base altogether.

Have you considered editing the hosts file to map IP addresses to host names locally?

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1        localhost
172.16.185.128   some.dev.server # maps http://some.dev.server/ to http://172.16.185.128/
craiga
+1  A: 

The way I've done it for a few projects now is to create a rootPath variable that contains the right amount of ../'s to get to the root. Something like this....

 $dirs        = substr_count($url, '/');        // Counts slashes in url

 $sRoot       = '';     // Set sRoot var
 if ( $dirs   == 0 ) {      // If they're no slashes    
   $sRoot     = './';       // Set sRoot var 
 } else {
    $x = 0;     
    while ($x < $dirs ) {       // Else, for every slash, put a ../         
      $sRoot  .= '../';
      $x++;     // Increment x var  
    }
 }

This works perfectly for us because of the way our htaccess file is set up. It wouldn't take much fiddling to get it to work with standard pages though.

thebluefox
A: 

Personally I dislike the use of base as it leads to the sort of issues you are experiencing. Absolute paths are always best as they are unambiguous. If you want to say switch themes or javascript library versions or whatever your links could be dynamically genererated by your application to reflect this, e.g:

/libs/v1/javascript.js

/themes/blue_theme/mycss.css
Richard
yes, but if the path (local) is `localhost/dev/app/`, absolute paths are different from `dev.something.com/app/` or `app.com/`
Adam Kiss
When I say absolute path I don't mean including the host name, by absolute I mean starting with /
Richard
@Richard but it starts from the host name-in cases mentioned, file "image.png" in "app" directory will be: `/dev/app/image.png`, `/app/image.png` and `/image.png`, won't it?
Adam Kiss
+1  A: 

Hi Adam,

I am familar with the issue you describe above. This is a particular issue when you have several environments, Development, Test, Production, etc... I have tried most of what everyone has suggested above, but have found them to be only partially effective. What I did to finally solve this issue was to create a custom control that I call an "AnchorDomain". This control simply allows you to put in a path such as "/category/page" or "/images/file.png" into its VirtulPath propery and it will dynamically build the correct url for you based on the environment in which you are running your project. This way for all the problem url in my project I simply use this control and am able to run my code independent of the environment and all of my url resolve with the correct name. So for instance here is an example of the syntax in a aspx page.

<cc1:AnchorDomain runat="server" Title="My Homepage" Url="default.aspx" UsePageVirtualPath="false" />

So in this case no matter what environment you are in this link will always show the correct address.

At first it might seem like overkill to do it this way, but this control solves this issue in all cases i have run across.

See code below:

Enjoy!

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.ComponentModel;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

namespace Pdc.EventPro.WebControls
{
  [DefaultProperty("Text"), ToolboxData("<{0}:AnchorDomain1 runat=server></{0}:AnchorDomain1>")]
  public class AnchorDomain : Control
  {
    private string _href = string.Empty;

    public AnchorDomain()
    {
      VirtualPath = HttpContext.Current.Request.Path.Substring(0, HttpContext.Current.Request.Path.LastIndexOf("/") + 1);
    }

    private string VirtualPath
    {
      get
      {
        return (string)ViewState["virtualPath"];
      }
      set
      {
        ViewState["virtualPath"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("Performance Development Corporation")]
    public string Title
    {
      get
      {
        return (string)ViewState["title"];
      }

      set
      {
        ViewState["title"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("")]
    public string LinkText
    {
      get
      {
        return (string)ViewState["linktext"];
      }

      set
      {
        ViewState["linktext"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("")]
    public string Url
    {
      get
      {
        return (string)ViewState["url"];
      }

      set
      {
        ViewState["url"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("false")]
    public bool UsePageVirtualPath
    {
      get
      {
        return (bool)ViewState["useVirtualPath"];
      }

      set
      {
        ViewState["useVirtualPath"] = value;
      }
    }

    [Bindable(true), Category("Content"), DefaultValue("false")]
    public string CssClass
    {
      get
      {
        return (string)ViewState["CssClass"];
      }

      set
      {
        ViewState["CssClass"] = value;
      }
    }

    protected override void Render(HtmlTextWriter writer)
    {
      if (string.IsNullOrEmpty(Url) && UsePageVirtualPath == false)
      {
        _href = CreateUri(HttpContext.Current.Request.Url.GetLeftPart(System.UriPartial.Authority), HttpContext.Current.Request.ApplicationPath).ToString();
      }
      else if (!string.IsNullOrEmpty(Url) && UsePageVirtualPath == true)
      {
        _href = CreateUri(HttpContext.Current.Request.Url.GetLeftPart(System.UriPartial.Authority), CombineUri(VirtualPath, Url)).ToString();
      }
      else
      {
        _href = CreateUri(HttpContext.Current.Request.Url.GetLeftPart(System.UriPartial.Authority), CombineUri(HttpContext.Current.Request.ApplicationPath, Url)).ToString();
      }

      writer.WriteBeginTag("a");
      writer.WriteAttribute("href", _href);
      writer.WriteAttribute("title", Title);
      writer.WriteAttribute("class", CssClass);
      writer.Write(HtmlTextWriter.TagRightChar);
      writer.Write(LinkText);
      writer.WriteEndTag("a");

      base.Render(writer);
    }

    private Uri CreateUri(string baseUri, string relativeUri)
    {
      Uri result = null;

      if (Uri.TryCreate(new Uri(baseUri), relativeUri, out result))
      {
        return result;
      }

      return result;
    }

    private string CombineUri(string basePath1, string basePath2)
    {
      return string.Format("{0}/{1}", basePath1.TrimEnd('/'), basePath2.TrimStart('/')); 
    }
  }
}
Doug
now if I only translate it to PHP :D
Adam Kiss