Merging Multiple Stylesheets - javascript

i have been tasked with changing a bit of css for a site that i did not build and is quite old. Long story short - building the site from scratch is not an option. There are two CSS stylesheets associated with the site. I have tried combining them with no luck. The first stylesheet is declared in the head section of the document as normal. The second seems to be pulled from the following code:
<script type="text/javascript">
<!--
function P7_StyleLoader(tS) { //v1.3 by PVII
var tH = '',
tDoc = '',
tA = '<LIN' + 'K REL="stylesheet" HREF=',
tB = ' TYPE="text/css">';
if (document.getElementsByTagName) {
var bb = document.getElementsByTagName("LINK");
if (bb) {
for (var k = 0; k < bb.length; k++) {
if (bb[k].rel.toLowerCase() == "stylesheet") {
var h = bb[k].href,
x = h.lastIndexOf("/");
if (x > 0) {
tH = h.substring(0, x + 1);
}
bb[k].disabled = true;
tDoc = tA + '"' + tH + tS + '"' + tB;
document.write(tDoc);
break;
}
}
}
}
}
P7_StyleLoader('STYLE-SHEET-2.css');
//-->
</script>
if i merge them and drop one of these stylesheets from the html, the site pretty much breaks in terms of layout. Could someone tell me if the above code is doing anything else besides just pulling "STYLE-SHEET-2.css"? My thinking is that i'd like to use either the above code and put the other styles into it or vice-versa? Am i missing something here?
thanks!

the code REPLACES the current stylesheets by disabling other stylesheets
It seems to be code designed to remove Netscape 4 specific stylesheets since NS4 does not understand the disabled stylesheet :)
Here is a 2002 discussion about this obviously even older code
http://www.webxpertz.net/forums/showthread.php?t=20718

The javascript fragment is disabling all stylesheet link statements, and importing only style-sheet-2.css.

Yeuk. That is some nasty javascript.
What it's doing is roughly this: It scans through any <link> elements in the document already and disables them. It loads the stylesheet specified in the function call instead.
In addition, it works out what the directory path was in the original CSS include, and appends that to the front of the stylesheet it's loading, so that it is loaded from the same path as the original would have been.
The code is (slightly) obfuscated as well, presumably to prevent automated scripts from detecting what they're doing.
The question is why would anyone actually go to all that trouble?
I can't think of too many reasons why they may have done this. The only thing that makes sense would be to fool spam bots into loading the wrong styles or something similar to that. Make the page look different to a bot to how a human would see it. Possibly trying to fool search engine bots too, but that would be considered a very bad move - if Google catches on to that you'd get black-listed.

Well, actually, what it does is inserting a new -attribute for a stylesheet. You should view the DOM-document with firebug to view the exact generated link with style-sheet-2.css.
My guess is that it loads the following line:
<link rel="stylesheet" href="STYLE-SHEET-2.css" type="text/css" />
It's also possible (re-read your code..) that it's stripping all other CSS and replace the src with this one. Very weird..

Related

Current location path as a url parameter

I need to put a link out from a corporate site to a surveymonkey survey. Our site uses a proprietary CMS limiting me from adding any proper function or third party plugin.
After evaluating options like those exposed in this other question, I believe I call the correct javascript function but everytime I open my CMS, the link duplicates itself... leading me to think I've done something inapropriate.
Things look acceptable on the JSFiddle demo I put together for this question but I'm hoping you'd have a more elegant solution in mind so I could try options !
<script type="text/javascript">
document.write("<a href='https://www.surveymonkey.com/r/[SURVEYID]?url=" + window.location.pathname + " target='_blank'>Test - survey</a>");
</script>
Try this - it will probably not do what you want in one go, but it will hopefully isolate your problem so that you can better pinpoint what's going wrong:
HTML:
<div id="link"></div>
Javascript:
var SURVEYID = 3
var a = document.createElement("a");
a.innerHTML = "Test - survey";
a.href = "www.surveymonkey.com/r/"
+ SURVEYID
+ "?url="
+ window.location.pathname
+ "&target=_blank"
document.getElementById("link").appendChild(a)
I'm afraid there can be multiple things going wrong, but I hope you can now distinguish between the various parts that your URL is built up from.
This is mostly just a theory because I don't know your CMS or how it works, but I'm assuming that the CMS is inlining the javascript, executing it, and retaining that as its content along with the script. This would create that duplication. The original intent of using document.write I would assume was to completely replace the content; but if it's inlined, it only appends. An external script would completely replace. See below:
All of this text is retained.
<script type="text/javascript">
document.write("<a href='https://www.surveymonkey.com/r/[SURVEYID]?url=" + window.location.pathname + "' target='_blank'>Test - survey</a>");
</script>
In this demo, we use document.body.innerHTML instead. This will replace the content completely.
None of this text will be retained.
<script type="text/javascript">
document.body.innerHTML = "<a href='https://www.surveymonkey.com/r/[SURVEYID]?url=" + window.location.pathname + "' target='_blank'>Test - survey</a>";
</script>
If true, complete replacement of the body content is your goal, innerHTML is probably what you need.
Edit + Warning:
This may make the page inaccessible from the CMS depending on how it's built. It may make editing the page impossible.
Edit
Here's a better solution. Just set the href of the anchor by first getting it by the ID. This was based off of Sven ten Haaf's Answer.
<a href="#" id="__smlink" target='_blank'>Test - survey</a>
<script>
document.getElementById('__smlink').href = "https://www.surveymonkey.com/r/[SURVEYID]?url=" + window.location.pathname;
</script>

Relative images broken, need javascript fix

new here. I have no access to most of the source files on my website, so I am trying to fix some broken images on page load with javascript.
When I use the inspect element for one of these broken images it shows like this:
<img src="-82.jpg" width="60px">
when they should be
<img src="http://example.com/files/images/-82.jpg" width="60px">
This is for bunch of different images, -82.jpg, -2482.jpg, -3582.jpg
Here's what I have tried so far. This seems to work but for some reason it breaks other javascript on the page.
html
<script type="text/javascript" src="http://example.com/files/js/fiximages.js"></script>
<body onload="fixImages();">
my fiximages.js file
function fixImages() {
var toReplace = '<img src="-';
var replaceWith ='<img src="http://www.example.com/files/images/-';
document.body.innerHTML = document.body.innerHTML.replace(toReplace, replaceWith);
}
I'm a bit of a noob so I also need to know how to link the html to the javascript to get it to load when the page loads. Thanks guys.
This should solve your problem:
function fixImages() {
// Create a list of all img which src starts with "-".
var imgs = document.querySelectorAll('img[src^="-"]');
// Loop through this list.
for (var i = 0; i < imgs.length; i++) {
// For each img, replace its src with the correct path + the
// src that's already there.
imgs[i].setAttribute('src', 'http://www.example.com/files/images/' + imgs[i].getAttribute('src'));
}
}
Demo
Welcome to SO!
The problem in your approach is that changing the body's pure HTML is never a good idea for a dynamic page. Also, javascript's replace, when used without a regex, is going to replace only the first ocurrence of the string.
Now, when you need to change an element's attribute, Javascript has a manipulation called DOM. There are plenty material and tutorials on the web... You should look into it!
http://www.w3.org/TR/DOM-Level-2-Core/introduction.html
http://www.w3schools.com/jsref/dom_obj_document.asp
With DOM, you can select an element as a variable, and manipulate its properties and attributes, so, in your case it would be:
function fixImages() {
var imgs = document.getElementsByTagName("img");
for(var i=0; i<imgs.length; i++) {
if(imgs[i].src.indexOf("-") == 0)
imgs[i].src = "http://www.example.com/files/images/" + imgs[i].src;
}
}

Apply Mathjax to arbitrary elements

I have emacs org-generated HTML that contains dvipng'd equations by default. That's ok, I want to provide a good fallback for those who disabled their JS. The generated pictures and resulting <img> tags have complete LaTeX source in their alt attribute. I have also tweaked the code to apply a specific class to all such images so it becomes a simpler matter in JS end, which isn't my forté.
The MathJax documentation lists a couple of different configurations and a way to customize a configuration by myself; I don't see a selector function or anything to apply Mathjax to suit my needs. I know I can write own DOM-munging JS and then call Mathjax afterwards but surely Mathjax bends to this kind of functionality by itself?
This is an example from the generated HTML.
<img class="dvipng" src="upload/blog_ff4e604.png"
alt="$\frac{1}{2\pi{}i}\int_C\frac{f'(z)}{f(z)}{\rm d}z = N_0(f)$">
MathJax doesn't include this directly, but you could do the following:
<script type="text/x-mathjax-config">
MathJax.Extension.myImg2jax = {
version: "1.0",
PreProcess: function (element) {
var images = element.getElementsByTagName("img");
for (var i = images.length - 1; i >= 0; i--) {
var img = images[i];
if (img.className === "dvipng") {
var script = document.createElement("script"); script.type = "math/tex";
var match = img.alt.match(/^(\$\$?)(.*)\1/);
if (match[1] === "$$") {script.type += ";mode=display"}
MathJax.HTML.setScript(script,match[2]);
img.parentNode.replaceChild(script,img);
}
}
}
};
MathJax.Hub.Register.PreProcessor(["PreProcess",MathJax.Extension.myImg2jax]);
</script>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML"></script>
which defines a new preprocessor that looks for your images and extracts the math from the ALT tags. This assumes you use $...$ for in-line math and $$...$$ for displayed math.
This code removed the image when it converts it to the MathJax <script> tag. It would be possible to move the image to a preview span where it will show up until MathJax processes the TeX code. That is a bit more sophisticated, but could be done with a little more work. I'll leave that to the interested reader. :-)

Access CSS file contents via JavaScript

Is it possible to get the entire text content of a CSS file in a document? F.ex:
<link rel="stylesheet" id="css" href="/path/to/file.css">
<script>
var cssFile = document.getElementById('css');
// get text contents of cssFile
</script>
I’m not really into getting all the CSS rules via document.styleSheets, is there another way?
Update: There is the ajax option of course, I appreciate the answers given. But it seems rather unnecessary to reload a file using ajax that is already loaded in the browser. So if anyone knows another way to extract the text contents of a present CSS file (NOT the CSS rules), please post!
With that specific example (where the CSS is on the same origin as the page), you could read the file as text via ajax:
$.ajax({
url: "/path/to/file.css",
dataType: "text",
success: function(cssText) {
// cssText will be a string containing the text of the file
}
});
If you want to access the information in a more structured way, document.styleSheets is an array of the style sheets associated with the document. Each style sheet has a property called cssRules (or just rules on some browsers), which is an array of the text of each rule in the style sheet. Each rule has a cssText property. So you could loop through those, e.g.:
$.each(document.styleSheets, function(sheetIndex, sheet) {
console.log("Looking at styleSheet[" + sheetIndex + "]:");
$.each(sheet.cssRules || sheet.rules, function(ruleIndex, rule) {
console.log("rule[" + ruleIndex + "]: " + rule.cssText);
});
});
Live example - That example has one stylesheet with two rules.
you could load the content with a simple ajax get call, if stylesheet is included from the same domain
Edit after your update: I tried this code (on FX10) as a proof of concept that uses only one request to the CSS but it seems a bit hacky to me and should be tested and verified. it also should be improved with some fallback if javascript is not available.
CSS (external file test.css)
div { border: 3px solid red;}
HTML/jQuery
<!doctype html >
<html>
<head>
<!-- provide a fallback if js not available -->
<noscript>
<link rel="stylesheet" href="test.css" />
</noscript>
</head>
<body>
<div></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.js"></script>
<script>
$(document).ready(function() {
$.when($.get("test.css"))
.done(function(response) {
$('<style />').text(response).appendTo($('head'));
$('div').html(response);
});
})
</script>
</body>
</html>
You should see the CSS code inside the div with a red border all around :)
Enjoy.
The closest you can get to obtaining the stylesheet without using ajax is to indeed iterate over all CSS rules and concatenate them into a string. This yields the original file with all comments and excess whitespace removed. Which makes sense, as the browser only needs to keep the parsed style sheet in memory, not the original file. It is only 3 lines of code:
function css_text(x) { return x.cssText; }
var file = document.getElementById('css');
var content = Array.prototype.map.call(file.sheet.cssRules, css_text).join('\n');
I think your best bet would be to load it with ajax with something like:
$.get("/path/to/file.css", function(cssContent){
alert("My CSS = " + cssContent);
});
Yep, you can use $.get.
Example:
$.get('/path/to/css/file.css', function (resp) {
// resp now should contain your CSS file content.
});
If you used XMLHttpRequest to load the page you could get acces to those files without having to load them a second time.
it's preferable to not duplicate ton reduce bandwidth and efficiency.
what if the css is generated dynamically and is different depending on the time it is requested?
You can access your loaded CSS by using document.styleSheets.

How write to page without document.write length limitation

I'm very much not a javascript/html/css person.
Even so I find myself in the position of having to do a webpage. It's static the only thing you can do on it is click on flags to change dispay-language based on a cookie.
If the cookie says "this" I write text in one language, and if the cookie says "that" I write in another language. This works perfectly but I have to use lots of document.write statements and it's ugly and cumbersome.
Right now I type the text I want and use a macro in emacs to fold the text at about
80 chars and put document.write(" in the beginning of each line and "); at the end. I then paste it into the web page in a if(cookie_this) { } else { }.
There must be a better way to do it... Please?
Edit:
I was looking workaround for the limitations in document.write
Constraints:
No server side magic, that means no ruby/php/perl
One page only, or rather only one visible url
The solution should be simpler than the working one I have
Expanding on artlung's answer:
You can display or hide things given a lang attribute (or any other criteria, such as a class name). In jQuery and HTML:
<p>Language:
<select id="languageSelector">
<option value="en">English</option>
<option value="es">Español</option>
</select>
</p>
<div lang="en-us">
Hello
</div>
<div lang="es">
Hola
</div>
<script type="text/javascript">
var defaultLanguage = 'en';
var validLanguages = ['en', 'es'];
function setLanguage(lang, setCookie) {
if(!$.inArray(languages, lang))
lang = defaultLang;
if(typeof(setCookie) != 'undefined' && setCookie) {
$.cookie('language', lang);
}
// Hide all things which can be hidden due to language.
$('*[lang]').filter(function() { return $.inArray(languages, $(this).attr('lang')); }).hide();
// Show currently selected language.
$('*[lang^=' + lang + ']).show();
}
$(function() {
var lang = $.cookie('language'); // use jQuery.cookie plugin
setLanguage(lang);
$('#languageSelector').change(function() {
setLanguage($(this).val(), true);
});
});
</script>
jQuery can do this with I lot less ease, but you could create an element then set that elements innerHTML property. You may have to change your call slightly so that you append the child element. See createElement function for more info. For example
<script type="text/javascript">
function writeElement(language, elementId) {
var newElement = document.createElement("span");
if (language = "this") {
newElement.innerHTML = "text for this";
}
else {
newElement.innerHTML = "text for that";
}
var element = document.getElementById(elementId);
element.appendChild(newElement);
}
</script>
Usage
<span id="data1"></span>
<script type="text/javascript">
writeElement("this", "data1")
</script>
Add a comment if you can support jQuery and you want a sample of that instead.
I think that the right way to approach this is to parse the Accept-Language header, and do this server-side.
But in the instance that you are stuck with client-side scripting. Say your content was marked like this
<script type="text/javascript">
if(cookie_this) {
document.getElementById('esContent').style.display = 'block';
} else {
document.getElementById('enContent').style.display = 'block';
}
</script>
<div id="esContent" style="display:none">
Hola, mundo.
</div>
<div id="enContent" style="display:none">
Hello, world.
</div>
This does not degrade for people with CSS enabled, and JavaScript disabled. Other approaches might include using Ajax to load content based on a cookie value (you could use jQuery for this).
If you just want one visible URL, but can host multiple pages on the server you could also try XHR. I use jQuery because I am most familiar with it although it would be possible to implement in javascript alone:
<html>
<head>
<script type="text/javascript" src="path/to/jquery.js"> </script>
<script type="text/javascript">
$(document).ready(function () {
if (cookie_this) {
$("body").load("onelanguage.html body");
} else {
$("body").load("otherlanguage.html body");
}
});
</script>
</head>
<body>
</body>
</html>
The detection should be on the server (preferably based on the Accept-Language header the client sent), and you should send a static file that has already been localized.
This does not fit the (edited) criteria of the original question, but may be useful regardless.
Use a server-side script. What you're looking for can easily be done in PHP. You'd probably want a hierarchy of documents based on language, and would look up given that. For example, a directory tree:
/en/
/en/page1.html
/en/page2.html
/es/
/es/page1.html
/es/page2.html
In PHP it's as simple as
$language = $_GET['lang'];
$page = $_GET['page'];
include($language . '/' . $page);
// URL is: /whatever.php?lang=LANGUAGE_HERE&page=PAGE_HERE
However, that has many security issues along with it. Sanitize your input and make sure the directory and file exist. Fuller example:
$contentRoot = './'; // CHANGE ME. Do include trailing /.
$defaultLanguage = 'en'; // CHANGE ME.
$defaultPage = 'home'; // CHANGE ME.
if(isset($_GET['lang']))
$language = $_GET['lang'];
else
$language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 2);
if(isset($_GET['page']))
$page = $_GET['page'];
else
$page = $defaultPage;
$languageDir = basename($_GET['lang']) . '/';
$pageFile = basename($page) . '.html';
if(!file_exists($contentRoot . $languageDir) || !is_dir($contentRoot . $languageDir))
$languageDir = $defaultLanguage;
$fullFileName = $contentRoot . $languageDir . $pageFile;
if(!file_exists($fullFileName) || !is_file($fullFileName) || !is_readable($fullFileName))
$pageFile = $defaultPage;
readfile($fullFileName);
// Or, if you want to parse PHP in the file:
include($fullFileName);
You may also want to use mod_rewrite (Apache) to allow URL's such as http://www.mysite.com/en/page1. (Just be sure to hide the actual page.)
// TODO mode_rewrite rules
Another approach is putting the above hierarchy into the document root and handing out URL's directly. This gives you less power (e.g. templating is more difficult), however, and you have to worry about external media being referenced properly.
If you're looking for a dynamic approach, on the client side use Javascript to fetch the data using Ajax. This is also trivial, and does not require a dynamic server backend. I recommend a Javascript framework such as jQuery to make this as easy as possible.
There is no good way to do this in JS. The best way is to use VERY simple PHP code.
But, if you want, there is a way in JS - prepare pages like these:
some pages with different language versions, like index_en.html, index_ru.html
main index.html page, where you have code like
if(cookie) windows.location.replace('index_en.html') else ...

Categories