How to read less variables in Javascript? - javascript

I am working on a project that all of the less variables are compiled to Css by Maven. There is lots of variables for colours in the less file. I want to have access to these colour variables from javascript. In that case I can define the colours once and use it in css and javascript.
Could anyone please help me with introducing a Maven plugin or a method to read the less variables in Javascript?

Here is a code snippet explaining how to access less variables in JavaScript
// getLessVars :: https://gist.github.com/2948738
/**
* getLessVars parses your LESS variables to Javascript (provided you make a dummy node in LESS)
* #param {String} id The CSS-id your variables are listed under.
* #param {Boolean} [parseNumbers=true] Try to parse units as numbers.
* #return {Object} A value object containing your LESS variables.
* #example
* LESS:
* #myLessVariable: 123px;
* #dummyLessId { width: #myLessVariable; }
* Javascript:
* getLessVars('dummyLessId');
* returns:
* {myLessVariable:123}
*/
function getLessVars(id,parseNumbers) {
var bNumbers = parseNumbers===undefined?true:parseNumbers
,oLess = {}
,rgId = /\#[\w-]+/
,rgKey = /\.([\w-]+)/
,rgUnit = /[a-z]+$/
,aUnits = 'em,ex,ch,rem,vw,vh,vmin,cm,mm,in,pt,pc,px,deg,grad,rad,turn,s,ms,Hz,kHz,dpi,dpcm,dppx'.split(',')
,rgValue = /:\s?(.*)\s?;\s?\}/
,rgStr = /^'([^']+)'$/
,sId = '#'+id
,oStyles = document.styleSheets;
for (var i=0,l=oStyles.length;i<l;i++) {
var oRules;
try{ oRules = oStyles[i].cssRules; }
catch (e) { continue; }
if (oRules) {
for (var j=0,k=oRules.length;j<k;j++) {
try { var sRule = oRules[j].cssText; }
catch (e) { continue; }
var aMatchId = sRule.match(rgId);
if (aMatchId&&aMatchId[0]==sId) {
var aKey = sRule.match(rgKey)
,aVal = sRule.match(rgValue);
if (aKey&&aVal) {
var sKey = aKey[1]
,oVal = aVal[1]
,aUnit
,aStr;
if (bNumbers&&(aUnit=oVal.match(rgUnit))&&aUnits.indexOf(aUnit[0])!==-1) {
oVal = parseFloat(oVal);
} else if (aStr=oVal.match(rgStr)) {
oVal = aStr[1];
}
oLess[sKey] = oVal;
}
}
}
}
}
return oLess;
}
// parse less
less.refresh();
// read variables from id #foobar
var oVars = getLessVars('foobar'),
mPre = document.createElement('pre'),
sData = "\n";
for (var s in oVars) sData += "\t" + s + ': ' + oVars[s] + "\n";
mPre.innerHTML = sData;
document.body.appendChild(mPre);
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
<html><head>
<style type="text/less">
// less variables
#myWidth: 200px;
#myPadding: 5px;
#myBorderColor: #666;
// add variables as classes to a non-existing id
#foobar {
.myWidth { width: #myWidth; }
.myPadding { width: #myPadding; }
.myBorderColor { color: #myBorderColor; }
}
// variables usage
div {
width: #myWidth;
padding: #myPadding;
border: 2px solid #myBorderColor;
}
</style>
</head><body>
<div>this div uses the following less properties:</div>
</body></html>
You can also refer https://gist.github.com/Sjeiti/2948738

Less can be used on the client as well. Reading from their documentation:
Client-side Usage
Using less.js in the browser is great for development, but it's not recommended for production
Client-side is the easiest way to get started and good for developing with Less, but in production, when performance and reliability is important, we recommend pre-compiling using node.js or one of the many third party tools available.
To start off, link your .less stylesheets with the rel attribute set to "stylesheet/less":
<link rel="stylesheet/less" type="text/css" href="styles.less" />
Next, download less.js and include it in a tag in the element of your page:
Tips
Make sure you include your stylesheets before the script.
When you link more than one .less stylesheet each of them is compiled independently. So any variables, mixins or namespaces you define in a stylesheet are not accessible in any other.
Due to the same origin policy of browsers loading external resources requires enabling CORS
Less CDN
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.7.2/less.min.js"></script>
Defined variables can be found in less data or trough less.Parser or various API.
For some Parser sample see: get variables values

Related

Dynamic progress bar based on progress of script?

I have a Google App Engine application, using the webapp2 framework, that interacts with a MySQL database. Users of the application can upload data. During uploading, I want to show a progress bar, since it can take up to some minutes.
Based on what I've seen in other topics (mainly: this topic and this one), I'm working on a JSON/Javascript solution, which are both new to me.
The progress bar itself is working if I'm passing a random number. However, I can't figure out how to 'load' the changing values from the Python script.
Here's the HTML/CSS/Javascript:
HTML:
<div id="myProgress">
<div id="myBar"</div>
</div>
CSS:
#myProgress {width: 300px;
height: 30px;
background-color: #ddd;
}
#myBar {width: 1%;
height: 30px;
background-color: #4CAF50;
}
Javascript:
<script type="text/javascript">
function move() {
var elem = document.getElementById("myBar");
var width = 1;
var id = setInterval(frame, 1000);
function frame() {
if (width >= 100) {
clearInterval(id);
}
else {
//var randomnumber = Math.floor(Math.random() * 100); --> works
var randomnumber = function update_values() {
$SCRIPT_ROOT = {{ script_root }};
$.getJSON($SCRIPT_ROOT+"/uploading",
function(data) {
$("#width").text(data.width+" %")
});
} ; --> this is wrong I assume
var width = randomnumber;
elem.style.width = width + '%';
}
}
}
window.onload=move();
</script>
The progress comes from a for loop in Python which is embedded in the script that loads the page. After the script is finished with one activity, I want the result of counter to be passed to the progress bar as its width. With static variables, I use the regular Jinja way.
class UploadingpageHandler(webapp2.RequestHandler):
def get(self):
activities_list = [1,2,3,4,5,6,7,8,9,10]
counter = 0
script_root = 'localhost:10080'
for activity in activities_list:
counter = counter + 10
upload.do_stuff_in_some_function_with_MySQL()
obj = {
'width': counter
}
self.response.headers['Content-Type'] = 'application/json' --> this
self.response.out.write(json.dumps(obj)) --> and this is wrong I assume
template_vars = {
'script_root': script_root
}
template = jinja_environment.get_template('uploading.html')
self.response.out.write(template.render(template_vars))
How to alter the scripts to get it working? Or is there a better way to solve this?
You need to store the progress of your "activities" outside of your function somewhere.
A hacky "solution" would be to store it into some sort of caching solution like memcached or redis with some sort of timestamp/signature so that you can retrieve it (and invalidate the old entries with a cron job-type thing).
Or you could go balls out and make your task entirely async with something like Celery, but I doubt you can do that on Google App Engine.

How to render a text item in my App using the fonts that are already installed on a users PC?

I have a text "name" in my App that I want to be styled using the fonts that are installed on users PC (locally) which I would fetch using a function like filesystemobject. Something like this (This is only an indicative code to only get the filenames first.)
<html>
<head>
<script>
function ShowFolderFileList()
{
var fso, f, f1, fc, s;
fso = new ActiveXObject("Scripting.FileSystemObject");
f = fso.GetFolder("My Folder");
fc = new Enumerator(f.files);
s = "";
for (; !fc.atEnd(); fc.moveNext())
{
s += fc.item();
s += "<br>";
}
document.write(s);
}
</script>
</head>
<body>
<form name="myForm">
<input type="Button" value="Get File" onClick='ShowFolderFileList'>
</form>
</body>
</html>
I have tried and explained my question as much as possible. Do comment if require more details I shall provide more information pertaining to your query.
You can easily access the fonts embedded in users navigators, known as "web safe fonts". These classic fonts are supposed to be widely available, cross-OS. Full "web safe font" list is available via google :)
To use one of them, simply use a CSS rule, like :
p {font-family: "Times New Roman";}
I'm sure you expect more specific fonts, and as far as I know, you can't list the font installed on the user PC via javascript. Flash might be needed for that. However, i found this piece of code that can say if a font is installed or not on the user computer, this may serve your objective.
/**
* JavaScript code to detect available availability of a
* particular font in a browser using JavaScript and CSS.
*
* Author : Lalit Patel
* Website: http://www.lalit.org/lab/javascript-css-font-detect/
* License: Apache Software License 2.0
* http://www.apache.org/licenses/LICENSE-2.0
* Version: 0.15 (21 Sep 2009)
* Changed comparision font to default from sans-default-default,
* as in FF3.0 font of child element didn't fallback
* to parent element if the font is missing.
* Version: 0.2 (04 Mar 2012)
* Comparing font against all the 3 generic font families ie,
* 'monospace', 'sans-serif' and 'sans'. If it doesn't match all 3
* then that font is 100% not available in the system
* Version: 0.3 (24 Mar 2012)
* Replaced sans with serif in the list of baseFonts
*/
/**
* Usage: d = new Detector();
* d.detect('font name');
*/
var Detector = function() {
// a font will be compared against all the three default fonts.
// and if it doesn't match all 3 then that font is not available.
var baseFonts = ['monospace', 'sans-serif', 'serif'];
//we use m or w because these two characters take up the maximum width.
// And we use a LLi so that the same matching fonts can get separated
var testString = "mmmmmmmmmmlli";
//we test using 72px font size, we may use any size. I guess larger the better.
var testSize = '72px';
var h = document.getElementsByTagName("body")[0];
// create a SPAN in the document to get the width of the text we use to test
var s = document.createElement("span");
s.style.fontSize = testSize;
s.innerHTML = testString;
var defaultWidth = {};
var defaultHeight = {};
for (var index in baseFonts) {
//get the default width for the three base fonts
s.style.fontFamily = baseFonts[index];
h.appendChild(s);
defaultWidth[baseFonts[index]] = s.offsetWidth; //width for the default font
defaultHeight[baseFonts[index]] = s.offsetHeight; //height for the defualt font
h.removeChild(s);
}
function detect(font) {
var detected = false;
for (var index in baseFonts) {
s.style.fontFamily = font + ',' + baseFonts[index]; // name of the font along with the base font for fallback.
h.appendChild(s);
var matched = (s.offsetWidth != defaultWidth[baseFonts[index]] || s.offsetHeight != defaultHeight[baseFonts[index]]);
h.removeChild(s);
detected = detected || matched;
}
return detected;
}
this.detect = detect;
};

Refreshing page with a new image [duplicate]

This question already has answers here:
Load Random Images from Directory
(5 answers)
Closed 7 years ago.
I currently have a stagnant image on my site:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/stylesheets/normalize.css" media="all" rel="stylesheet" />
<link href="/stylesheets/master.css" media="all" rel="stylesheet" />
<script>
window.onload = function () {
var images = [],
i=1, indexImages = true,
prefix = '../image/',
extension = '.jpg';
while (indexImages) {
var a = new XMLHttpRequest(); a.open('GET', prefix+i+extension, false); a.send();
if (a.status != 404) { i += 1; images.push(prefix+i+extension); } else {
indexImages = false;
localStorage['backgroundIndex'] = !localStorage['backgroundIndex']?0:+localStorage['backgroundIndex']+2>images.length?0:+localStorage['backgroundIndex']+1;
document.body.style.backgroundImage = 'url(' + images[+localStorage['backgroundIndex']] + ')';
}
}
}
</script>
<style>
body {
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
background-color: black;
border-bottom: 8px solid #7D8A28;
}
</style>
</head>
<body>
<section id="card">
</section>
</body>
</html>
It's just that I want it to be a different image each time the page refreshes, so it auto changes to 2.jpg, 3.jpg, 10.jpg, whatever. (There are hundreds to choose from)
Could someone help me out with a solution? I'm not very good at this, and this is my first site.
Thanks.
I don't think CSS alone can do this, here's an answer:
Random
window.onload = function () {
var images = [
'image/1.png',
'image/2.png',
'image/3.png',
'image/4.png'
];
document.body.style.backgroundImage = 'url(' + images[Math.floor(Math.random()*images.length)] + ')';
}
This will load a random image every time you visit the page.
Specified Order
To load them in sequential order: First time image1, second time image2. The images don't need even have a number for this to work just fine. Do:
window.onload = function () {
var images = [
'image/A.png',
'image/B.png',
'image/C.png',
'image/D.png'
];
localStorage['backgroundIndex'] = !localStorage['backgroundIndex']?0:+localStorage['backgroundIndex']+2>images.length?0:+localStorage['backgroundIndex']+1;
document.body.style.backgroundImage = 'url(' + images[+localStorage['backgroundIndex']] + ')';
}
Generating the Array (ONLY IF YOUR IMAGES HAVE A NUMBER AT THE END)
This will automatically generate the array for you and you don't have to provide the amount of images
window.onload = function () {
var images = [],
i = 1,
prefix = 'image/',
extension = '.png',
max = 1000;
function index() {
var a = new XMLHttpRequest();
a.open('GET', prefix + i + extension, false);
a.send();
a.onreadystatechange = function () {
if (a.readyState === 4) {
if (a.status != 404) {
i += 1;
images.push(prefix + i + extension);
i < max ? index();
} else {}
localStorage['backgroundIndex'] = !localStorage['backgroundIndex'] ? 0 : +localStorage['backgroundIndex'] + 2 > images.length ? 0 : +localStorage['backgroundIndex'] + 1;
document.body.style.backgroundImage = 'url(' + images[+localStorage['backgroundIndex']] + ')';
}
};
}
index();
}
Most versatile solution
If you have PHP, this is probably the best solution in terms of working in many cases. But you really don't want to use PHP if you can avoid it. It will get all images in a directory to generate the array:
window.onload = function () {
var images = (JSON.parse("<?=scandir('../images')?>")||[]).filter(function (a) { return ['.', '..'].indexOf(a) < 0; });
document.body.style.backgroundImage = 'url(' + images[+localStorage['backgroundIndex']] + ')';
};
You can easily do it with JavaScript. You could define an array with all the images you have and then create a random number every time the page loads. Then use the random number to access the array's index to read the name of the image. Like so:
var images = ["image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg", "image5.jpg"];
var randomNumber = Math.floor((Math.random() * images.length));
//images[randomNumber] contains your random image
Hope it helps.
Regards,
I see all these JS solutions but most likely you need a php one as I am sure you don't wanna put the names of hundreds of images in a file. So if you have some knowledge of programming in php then try this.
Generate a random number. Let's say it is 42
Read the file names one by one (http://php.net/manual/en/function.readdir.php)
Once you reach the 42nd file, pass it to the page.
You can either put the filename directly in the css or have a php page as a background image source which returns the images. Either case, the above steps will give you what you want.
The above works well if file names and types are different. However, if file names are numerical and all files are the same extension then just generating a number and just using it as the file name is slightly faster than the above method.
However, it is still faster than most JS solution. Remember that JS is on client side. That mean it will be executed after that page is loaded. With JS, files need to be as minimal as possible. Otherwise, the page would load and you wouldn't have a background until that request is returned. Considering all these delays, I wouldn't call JS efficient over PHP.
Although you can always make it nice and fade it in or something :)
No need for AJAX
Why you should use PHP
The added benefit of using PHP is we can make it so all you have to do is drop an image into a folder and it will automatically be added to the randomized list! Which is great for maintainability. You code it once, and leave it alone!
In my opinion, there is no added benefit to using AJAX. Any time you add an image, you would have to add it to your JS image array. However, I don't know your exact scenario.
Important
All the other solutions that mention PHP, so far, have failed to mention one very important part... the page you are working in must be parsed as a PHP file.
There are two ways to do so:
Parse html/htm page as php page via .htaccess (advanced)
Change your the page extension to '.php' (simple)
(My solution requires that your page is parsed as PHP)
Solution 1
I would use JavaScript to randomly select the image from a PHP generated list, then append CSS to apply the background image to the page before the window.onload event.
PHP with JavaScript Random
Append the following to page head:
<script type="text/javascript">
<?php
// Path to image can be a relative or absolute path. I recommend absolute.
// The following is my absolute path.
$img_dir_path = '/rand-img/images/';
// Get directory list. If using absolute, prepend $_SERVER['DOCUMENT_ROOT'] for php
$dir_listing = scandir($_SERVER['DOCUMENT_ROOT'].$img_dir_path, 1);
// array_diff() to remove '.' & '..' from front of $dir_listing array
$img_array = array_diff( $dir_listing, array('.', '..') );
?>
// JavaScript variables
var img_dir_path = '<?php echo $img_dir_path ?>';
var img_array = <?php echo json_encode($img_array) ?>;
var rand_index = Math.floor(Math.random() * img_array.length);
var img_path = img_dir_path + img_array[rand_index];
// no need to wait for window.onload if we append actual style tag
var css = 'body { background-image: url('+img_path+') !important; }',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
</script>
Using PHP for random, will only work if the page is loaded without cache.
However, using JavaScript will randomize the image even if the actual page is cached.
Solution 2
In my experience, this solution will randomize the image the vast majority of the time. However, if the page is loaded via cache, the background image will not be re-randomized.
PHP Random
Append the following to page head:
<?php
// Path to image can be a relative or absolute path. I recommend absolute.
// The following is my absolute path.
$img_dir_path = '/rand-img/images/';
// Get directory list. If using absolute, prepend $_SERVER['DOCUMENT_ROOT'] for php
$dir_listing = scandir($_SERVER['DOCUMENT_ROOT'].$img_dir_path, 1);
// array_diff() to remove '.' & '..' from front of $dir_listing array
$img_array = array_diff( $dir_listing, array('.', '..') );
// Random number based off size of $img_array
$random_index = mt_rand(0, count($img_array)-1);
// Build image path
$image_path = $img_dir_path . $dir_listing[ $random_index ];
?>
<style type="text/css">
body {
background-image: url("<?php echo $image_path ?>");
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center;
background-color: black;
border-bottom: 8px solid #7D8A28;
}
</style>

JavaScript page resizing

I know that you don't normally like doing things like this but I'm at University and have to do a project with several different stylesheets for the same page. I have been given JavaScript code to enable me to resize the page when the window is resized.
This code works however I am getting a peculiar effect on one of the stylesheets where the content div takes up most of the page when it shouldn't, this page has measurements in ems whereas my other stylesheets use px but I am supposed to use ems for at least one page. Although I could give my lecturer a reason for it being bigger I would prefer to fix the problem. The JavaScript code I am using is shown below:
function smoothresize() {
blockwidth = 59.4; /*This is in ems as per the lecturers request a well and is the size of the container div I created*/
minmargin = 0;
minsize = 10;
emwidth = (minmargin * 2) + blockwidth;
computeResize(emwidth, minsize, false)
}
function computeResize(wide, minsize, jerk) {
windowpixels = document.documentElement.clientWidth;
pixelsize = windowpixels / wide;
emsize = calculateEmsize(pixelsize, minsize, jerk);
b = document.getElementsByTagName('html')[0];
b.style.fontSize = emsize + "em";
}
function calculateEmsize(psize, minsize, jerk) {
if (psize > minsize) {
raw = psize;
}
else {
raw = minsize;
}
if (jerk) {
result = ((Math.floor(raw)) / 16);
}
else {
result = raw / 16;
}
return result
}
This is where I have Implemented the code in my XHTML:
<body onload="smoothresize()" onresize="smoothresize()">
I wouldn't be able to use jQuery as a solution to the problem either, I would only be able to modify the code given.
Any help in this matter Would be greatly appreciated
Check out jQuery's user interface plugin. It contains a "resizable" option; you ought to be able to add <script type="text/javascript">window.onload=function(){};</script> that loads the desired JQUI function upon page load.

Inject CSS stylesheet as string using Javascript

I'm developing a Chrome extension, and I'd like users to be able to add their own CSS styles to change the appearance of the extension's pages (not web pages). I've looked into using document.stylesheets, but it seems like it wants the rules to be split up, and won't let you inject a complete stylesheet. Is there a solution that would let me use a string to create a new stylesheet on a page?
I'm currently not using jQuery or similar, so pure Javascript solutions would be preferable.
There are a couple of ways this could be done, but the simplest approach is to create a <style> element, set its textContent property, and append to the page’s <head>.
/**
* Utility function to add CSS in multiple passes.
* #param {string} styleString
*/
function addStyle(styleString) {
const style = document.createElement('style');
style.textContent = styleString;
document.head.append(style);
}
addStyle(`
body {
color: red;
}
`);
addStyle(`
body {
background: silver;
}
`);
If you want, you could change this slightly so the CSS is replaced when addStyle() is called instead of appending it.
/**
* Utility function to add replaceable CSS.
* #param {string} styleString
*/
const addStyle = (() => {
const style = document.createElement('style');
document.head.append(style);
return (styleString) => style.textContent = styleString;
})();
addStyle(`
body {
color: red;
}
`);
addStyle(`
body {
background: silver;
}
`);
IE edit: Be aware that IE9 and below only allows up to 32 stylesheets, so watch out when using the first snippet. The number was increased to 4095 in IE10.
2020 edit: This question is very old but I still get occasional notifications about it so I’ve updated the code to be slightly more modern and replaced .innerHTML with .textContent. This particular instance is safe, but avoiding innerHTML where possible is a good practice since it can be an XSS attack vector.
Thanks to this guy, I was able to find the correct answer. Here's how it's done:
function addCss(rule) {
let css = document.createElement('style');
css.type = 'text/css';
if (css.styleSheet) css.styleSheet.cssText = rule; // Support for IE
else css.appendChild(document.createTextNode(rule)); // Support for the rest
document.getElementsByTagName("head")[0].appendChild(css);
}
// CSS rules
let rule = '.red {background-color: red}';
rule += '.blue {background-color: blue}';
// Load the rules and execute after the DOM loads
window.onload = function() {addCss(rule)};
fiddle
Have you ever heard of Promises? They work on all modern browsers and are relatively simple to use. Have a look at this simple method to inject css to the html head:
function loadStyle(src) {
return new Promise(function (resolve, reject) {
let link = document.createElement('link');
link.href = src;
link.rel = 'stylesheet';
link.onload = () => resolve(link);
link.onerror = () => reject(new Error(`Style load error for ${src}`));
document.head.append(link);
});
}
You can implement it as follows:
window.onload = function () {
loadStyle("https://fonts.googleapis.com/css2?family=Raleway&display=swap")
.then(() => loadStyle("css/style.css"))
.then(() => loadStyle("css/icomoon.css"))
.then(() => {
alert('All styles are loaded!');
}).catch(err => alert(err));
}
It's really cool, right? This is a way to decide the priority of the styles using Promises.
Or, if you want to import all styles at the same time, you can do something like this:
function loadStyles(srcs) {
let promises = [];
srcs.forEach(src => promises.push(loadStyle(src)));
return Promise.all(promises);
}
Use it like this:
loadStyles([
'css/style.css',
'css/icomoon.css'
]);
You can implement your own methods, such as importing scripts on priorities, importing scripts simultaneously or importing styles and scripts simultaneously. If i get more votes, i'll publish my implementation.
If you want to learn more about Promises, read more here
I had this same need recently and wrote a function to do the same as Liam's, except to also allow for multiple lines of CSS.
injectCSS(function(){/*
.ui-button {
border: 3px solid #0f0;
font-weight: bold;
color: #f00;
}
.ui-panel {
border: 1px solid #0f0;
background-color: #eee;
margin: 1em;
}
*/});
// or the following for one line
injectCSS('.case2 { border: 3px solid #00f; } ');
The source of this function. You can download from the Github repo. Or see some more example usage here.
My preference is to use it with RequireJS, but it also will work as a global function in the absence of an AMD loader.
I think the easiest way to inject any HTML string is via: insertAdjacentHTML
// append style block in <head>
const someStyle = `
<style>
#someElement { color: green; }
</style>
`;
document.head.insertAdjacentHTML('beforeend', someStyle);
Create a style tag and add the css styles into the textContent property as a string. Append these in the document head. Boom you are good to go.
var styles = document.createElement("style");
styles.setAttribute("type", "text/css");
styles.textContent = `#app{background-color:lightblue;}`;
document.head.appendChild(styles);

Categories