0

This question is related to a previous post: Check if user is using browser located in China or not

I am loading an external js library to evaluate which css do I want to load in my header. Following the accepted answer of the above mentionned post, I load the userinfo.io API in my HTML head, followed by the evaluation of the received data. Here is what I did:

<head>

...

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/userinfo/1.0.0/userinfo.min.js"></script>

<script type="text/javascript">
    UserInfo.getInfo(function(data) {
       // the "data" object contains the info
       if (data.country.code == 'CN') {
          // Load fallback fonts
          document.write('<link href="http://fonts.useso.com/css?family=Source+Sans+Pro:200,400,700|Dancing+Script:400,700|PT+Serif|Open+Sans:400,300,700" rel="stylesheet" type="text/css">');
       } else {
          // Load google fonts
          document.write('<link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,700|Dancing+Script:400,700|PT+Serif|Open+Sans:400,300,700" rel="stylesheet" type="text/css">');
       }
    }, function(err) {
       // the "err" object contains useful information in case of an error
    });
</script>

</head>

Debugging the js in Firefox, I can see that the library is successfully being loaded. It first happened, that I got an error message "Reference Error: UserInfo not defined". I played a bit with the order of the lines in my html head (there are a few more css includes, some meta tags and the title of course). After putting the

<head>

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/userinfo/1.0.0/userinfo.min.js"></script>

...

<script type="text/javascript">
    UserInfo.getInfo(function(data) {
       // the "data" object contains the info
       if (data.country.code == 'CN') {
          // Load fallback fonts
          document.write('<link href="http://fonts.useso.com/css?family=Source+Sans+Pro:200,400,700|Dancing+Script:400,700|PT+Serif|Open+Sans:400,300,700" rel="stylesheet" type="text/css">');
       } else {
          // Load google fonts
          document.write('<link href="http://fonts.googleapis.com/css?family=Source+Sans+Pro:200,400,700|Dancing+Script:400,700|PT+Serif|Open+Sans:400,300,700" rel="stylesheet" type="text/css">');
       }
    }, function(err) {
       // the "err" object contains useful information in case of an error
    });
</script>

</head>

as the first line inside the head tag, it started to actually recognize the object UserInfo and its method getInfo(). Meanwhile it also recognizes the function when I put the line back to it's original place (such as in the first code snippet). This behavior somehow made me wonder on how is javascript being executed in the head tag while loading the html page. Is it possible that once in a while the method is being called before the library is loaded?

Anyway, now when it successfully imports the userinfo.io library, the site does not load properly anymore. Having a look at the browser console I see:

Broser console output

Having a look at the source code of my page I only see the link tag that is properly loaded, but the rest of the page is missing.

enter image description here

So here's what I suppose:

I can somehow not use document.write() in the head tag because it interferes with the page loading. More likely I should access and modify the link tag by getElementById() after the page has successfully loaded. So I will actually trigger this with let's say jQuery's ready() function to be sure that the library has successfully loaded? I would appreciate any comment on these thoughts.

TylerH
  • 20,799
  • 66
  • 75
  • 101
flaudre
  • 2,358
  • 1
  • 27
  • 45

2 Answers2

2

document.write() is a very dangerous function (to a web page). You should be more specific about where you want to write something (not the whole document!). So, in your HTML you might specify an empty div block, and assign it an id:

<div id="writehere"></div>

Then in your JavaScript you would do something like this:

var place;  //global variable

and inside some page-initialization function do this:

place=document.getElementById("writehere");

and after that, you can do all the writing you want, wherever you want, such as:

place.innerHTML += "Special output text<br />";

You can even re-write it (use "=" instead of "+=" when you modify innerHTML).

I will confess that I may have missed one of the points you were asking about in your Question. I'm now getting the impression you want to specify extra stuff for the page to load during loading, and it isn't necessarily always going to be the same extra stuff. I'm not sure the head section is the correct place to try doing that, because I don't know about forcing the browser to pay attention to newly-added link items in the head section. I do know it can pay attention to SOME things, as in this example (which, while the code is called by an onload event associated with the body tag, puts an icon into the browser tab, or upper-left-corner of browser window):

var hd, itm;

hd = document.getElementById('ID_of_Head');
itm = document.createElement('link');
itm.id = 'whatever';
itm.rel = 'shortcut icon';
itm.type = 'image/png';
itm.href = 'desired URL'; //OOPS; my comment below wrongly says 'src' property
hd.appendChild(itm);
//you can now re-use the 'itm' variable to specify another link, if you wish

It is possible that the appendChild() function suffices to trigger the browser to pay attention to the newly-added link, in which case this might work generically, and not just for this specific example. On the other hand, I haven't tried adding multiple links; it is possible that only one of them at a time can be "paid attention to". In that case, though, there is still a way, involving a sequence of functions, each of which specifies adding just one link to the head. At the end of each function you would do this:

setTimeout('nextlinkfunc();', 200);  //give each function a different name!

When the current link-adding function ends, it sets a timer and gives the browser a chance to pay attention to the just-added link. After 200 milliseconds (1/5 sec) the timer triggers the specified next function --where you would specify adding another link to the head. That function's last thing would be another setTimeOut() to a third function, with its own unique name.... A variation on that could be a more complicated single function, where a parameter is used to specify which "call" is being made to the function (the very first call to the function must specify a parameter value of 1, of course):

//Note need to declare the global 'hd' and 'itm' variables,
// and set the 'hd' variable, before calling this function the first time
function nextlinkfunc(p)
{ itm = document.createElement('link');
  //more stuff as previously presented
  switch(p++)
  { case 1: //Note each 'case' block could have extra 'conditional' code
      itm.href = "URL_of_1st_link";
      break;
    case 2: //Conditional code can encompass many different combinations of URLs
      itm.href = "URL_of_2nd_link";
      break;
    //etc
  }
  hd.appendChild(itm);
  if(p<max_number_of_links_you_want_to_add)
    setTimeout('nextlinkfunc('p');', 200);
}
svangordon
  • 872
  • 7
  • 17
  • First, could you specify what you mean by "dangerous function"? Second, I agree this will work with a
    , but my question was related to the -tag. I believe that i cannot assign "id" to it, because "id" is not listed in -tag attributes (c.f. http://www.w3schools.com/tags/tag_link.asp)
    – flaudre Nov 10 '14 at 09:30
  • Are you saying I should put the inside a
    such as:
    ...?
    – flaudre Nov 10 '14 at 09:36
  • 1
    `document.write()` is able to replace everything on a web page with the stuff you write using `document.write()` --including the JavaScript code that contains that `document.write()`. I would call that "dangerous" to a web page. Regarding doing stuff inside the `head` tag with a `div` tag, I don't know that it can't be done. On the other hand, you can give the `head` tag an ID, fetch that with `document.getElementById()`, and use the `appendChild()` function to specify adding a `link` tag. Experiment! – vernonner3voltazim Nov 10 '14 at 15:18
  • 1
    The `link` tag, described on the page you linked, DOES support "global attributes", which includes the ID. Scroll down that page far enough to see. Therefore you might not need either a `div` block or the `appendChild()` function; just set the `innerHTML` of the `link` tag (or, perhaps most simply of all, the `src` property of the `link` tag). – vernonner3voltazim Nov 10 '14 at 15:25
0

Alright, this works fine! Thanks.

<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/userinfo/1.0.0/userinfo.min.js"></script>

<script type="text/javascript">
  UserInfo.getInfo(function(data) {

    var elHead, elLink;

    elLink = document.createElement('link');
    elLink.rel = 'stylesheet';
    elLink.type = 'text/css';

    if (data.country.code == 'CN') {
      elLink.href = 'http://fonts.useso.com/css?family=Source+Sans+Pro:200,400,700|Dancing+Script:400,700|PT+Serif|Open+Sans:400,300,700';
    }else{
      elLink.href = 'http://fonts.google.com/css?family=Source+Sans+Pro:200,400,700|Dancing+Script:400,700|PT+Serif|Open+Sans:400,300,700';
    }

    elHead = document.getElementsByTagName("head")[0];

    elHead.appendChild(elLink);

  }, function(err) {

  });
</script>

...

<body onload="UserInfo.getInfo();">
flaudre
  • 2,358
  • 1
  • 27
  • 45