Scaramouche
Scaramouche

Reputation: 3257

"include" js and css file using a RELATIVE path from js file

Using Symfony 2.8.24 and jQuery 3.2.1

Been googling for this for a while now and, yes, there are lots of similar cases, involving using relative paths for resource loading but, none I have found which explains what I need, so SO:

I need to include (or load or append to head or something) a css file which is (lets say for simplicity) in the same folder as the js file, I'm trying to do so (and this is the real problem) using a relative path to it, (and this is the real real problem) relative to the js file, NOT the html file.

I really don't know if this is even possible so, you know, IMPOSSIBLE is a valid answer.

Also, the whole point of this is portability of course, this plugin I'm trying to make uses several css and js files all sitting in different folders inside the plugin folder structure and I intend to include (or load or append to head or something) each one if and when necessary. If I could do that making the process oblivious of where the plugin's top folder is copied, I would not have to change the absolute paths every time I use it in a different project.

Current/unwanted state:

var cssId = 'cssId';
if (!document.getElementById(cssId)) {
    var head = document.getElementsByTagName('head')[0];
    var link = document.createElement('link');
    $(link).attr({
       'id': cssId,
       'rel': 'stylesheet',
       'type': 'text/css',
       'href': urlBase + '/js/plugins/PluginName/main.css', //PROBLEM HERE
       //ideally previous line would be like: 'href': 'main.css',
       'media': 'all'
    });    
    head.appendChild(link);
}

Insights and ideas, on me!

Upvotes: 1

Views: 2065

Answers (1)

Tobias Buschor
Tobias Buschor

Reputation: 3295

A tricky hack would be to use Error.stack, which is supported in current browsers but is not yet standardized.

c1CssImport = function (location) { // todo: handle absolute urls
    const e = new Error();
    const calledFile = e.stack.split('\n')[2].match(/[a-z]+:[^:]+/);
    const calledUrl = new URL(calledFile);
    calledUrl.search = '';
    const target = new URL(location, calledUrl).toString();
    for (let el of document.querySelectorAll('link[rel=stylesheet]')) {
        if (el.href === target) return; // already loaded
    }
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = target;
    document.head.append(link);
    // todo: return a promise
}

Then just call c1CssImport() where you like to include relative-url based css files:

c1CssImport('./ui.css');

note:

  • you dont need jQuery
  • The script only includes the CSS once
  • absolute urls are not handled in this script
  • i dont know if js-files included from other domains can handle this technic (not tested)

For js includes i recommentd using js modules

Upvotes: 1

Related Questions