views:

680

answers:

4

So I'm running this javascript, and everything works fine, except the paths to the background image. It works on my local ASP.NET Dev environment, but it does NOT work when deployed to a server in a virtual directory.

This is in an external .js file, folder structure is

Site/Content/style.css
Site/Scripts/myjsfile.js
Site/Images/filters_expand.jpg
Site/Images/filters_colapse.jpg

then this is where the js file is included from

Site/Views/ProductList/Index.aspx

$("#toggle").click(function() {
    if (left.width() > 0) {
        AnimateNav(left, right, 0);
        $(this).css("background", "url('../Images/filters_expand.jpg')");
    }
    else {
        AnimateNav(left, right, 170);
        $(this).css("background", "url('../Images/filters_collapse.jpg')");
    }
});

I've tried using '/Images/filters_collapse.jpg' and that doesn't work either; however, it seems to work on the server if I use '../../Images/filters_collapse.jpg'.

Basically, I want have the same functionallity as the ASP.NET tilda -- ~.

update

Are paths in external .js files relative to the Page they are included in, or the actual location of the .js file?

+2  A: 

Good question.

  • When in a CSS file, URLs will be relative to the CSS file.

  • When writing properties using JavaScript, URLs should always be relative to the page (the main resource requested).

There is no tilde functionality built-in in JS that I know of. The usual way would be to define a JavaScript variable specifying the base path:

<script type="text/javascript">

  directory_root = "http://www.example.com/resources";

</script> 

and to reference that root whenever you assign URLs dynamically.

Pekka
+5  A: 

JavaScript file paths

When in script, paths are relative to displayed page

to make things easier you can print out a simple js declaration like this and using this variable all across your scripts:

Solution employed on StackOverflow:

<script type="text/javascript">
   var imagePath = 'http://sstatic.net/so/img/';
</script>

just have a look at StackOverflow's html source, you will find this badass one-liner [formatted to 3 lines :) ] in the <head /> section

Juraj Blahunka
+1 for baddass and one-liner in the same sentence. :)
Nate Bross
I ended up doing this, except I use Url.Content to generate the value for `imagePath.` Thanks!
Nate Bross
A: 

This is from my Site.Master:

<%=Html.RenderCssHandler(Url.Content("~/Content/styles/default.css"))%>
<%=Html.RenderCssHandler(Url.Content("~/Content/WidgetFrameworkV2/widget_v2.css"))%>
<%=Html.RenderCssHandler(Url.Content("~/Content/styles/EditMode.css"))%>
<%=Html.RenderJavaScriptHandler(Url.Content("~/Scripts/jquery-1.3.1.min.js"))%>
<%=Html.RenderPendingJavaScriptHandler(Url.Content("~/Scripts/pending.js"))%>

HtmlHelpers:

    public static string ServerHost
    {
        get { return HttpContext.Current.Request.ApplicationPath; } //.Url.GetLeftPart(UriPartial.Authority); }
    }

    public static string RenderCssHandler(this HtmlHelper htmlHelper, string cssfile)
    {
        //string scriptUrl = ServerHost + VirtualPathUtility.ToAbsolute(cssfile);
        string constructHandler = string.Format("{0}/Services/GetMinifiedCss?css={1}", ServerHost,
                                                HttpUtility.UrlEncode(VirtualPathUtility.ToAbsolute(cssfile))).Replace("//", "/");
        string renderedScript = string.Format("<link href='{0}' rel='stylesheet' type='text/css' />{1}", constructHandler,
                                              Environment.NewLine);
        return renderedScript;
    }

    public static string RenderJavaScriptHandler(this HtmlHelper htmlHelper, string script)
    {
        // convert input script URL to absolute site URL
        //string scriptUrl = ServerHost + VirtualPathUtility.ToAbsolute(script);
        string constructHandler = string.Format("{0}/Services/GetJavaScript?jsPath={1}", ServerHost,
                                                HttpUtility.UrlEncode(VirtualPathUtility.ToAbsolute(script))).Replace("//", "/");
        string renderedScript = string.Format("<script type='text/javascript' src='{0}'></script>{1}", constructHandler,
                                              Environment.NewLine);
        return renderedScript;
    }

    public static string RenderPendingJavaScriptHandler(this HtmlHelper htmlHelper, string script)
    {
        // convert input script URL to absolute site URL
        //string scriptUrl = ServerHost + VirtualPathUtility.ToAbsolute(script);
        string constructHandler = string.Format("{0}/Services/GetPendingJavaScript?jsPath={1}&ServerHost={2}", ServerHost,
                                                HttpUtility.UrlEncode(VirtualPathUtility.ToAbsolute(script)),
                                                HttpUtility.UrlEncode(ServerHost)).Replace("//", "/");
        string renderedScript = string.Format("<script type='text/javascript' src='{0}'></script>{1}", constructHandler,
                                              Environment.NewLine);
        return renderedScript;
    }

Services Controller:

    [OutputCache(Duration = 86400, Location = OutputCacheLocation.Client, VaryByParam = "jsPath;ServerHost")]
    [CompressFilter]
    // Minifies, compresses JavaScript files and replaces tildas "~" with input serverHost address 
    // (for correct rewrite of paths inside JS files) and stores the response in client (browser) cache for a day
    public JavaScriptResult GetPendingJavaScript(string jsPath, string serverHost)
    {
        //string path = Utility.MyUrlDecode(base64EncodedPath);
        //string serverHost = Utility.MyUrlDecode(base64EncodedServerHost);
        string path = HttpUtility.UrlDecode(jsPath);
        string server = HttpUtility.UrlDecode(serverHost);
        JavaScriptResult js = new JavaScriptResult();
        string filePath = Server.MapPath(path);
        if (System.IO.File.Exists(filePath))
        {
            JavaScriptMinifier jsmin = new JavaScriptMinifier();
            FileStream fstream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            StreamReader reader = new StreamReader(fstream);
            string script = jsmin.Minify(reader);
            if (!string.IsNullOrEmpty(serverHost))
            {
                if (server == "/")
                    script = script.Replace("~", "");
                else
                    script = script.Replace("~", server);
            }

            fstream.Close();
            reader.Close();

            js.Script = script;
        }
        return js;
    }

(please note that I've left out GetMinifiedCss action because it follows the same guidelines as GetJavaScript action)

And Action Filters:

public class CompressFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        string acceptEncoding = request.Headers["Accept-Encoding"];

        if (string.IsNullOrEmpty(acceptEncoding)) return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;

        if (acceptEncoding.Contains("GZIP"))
        {
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}

HTH

P.S. Use the JavaScriptMinifier of your choice for minification....Google search should find it.

mare
Yes, this is how I am including my .js files, I was wondering if I could use a similar approach inside the .js files themselves. It appears that there isn't any solution as elegent.
Nate Bross
A: 

I used pekka's pattern. I think yet another pattern.

<script src="<% = Url.Content("~/Site/Scripts/myjsfile.js") %>?root=<% = Page.ResolveUrl("~/Site/images") %>">

and parsed querystring in myjsfile.js.

Plugins | jQuery Plugins

takepara