Skip to content

Instantly share code, notes, and snippets.

@linewx
Forked from zkenda/JsLitmus.js
Created September 19, 2013 04:50
Show Gist options
  • Save linewx/6619242 to your computer and use it in GitHub Desktop.
Save linewx/6619242 to your computer and use it in GitHub Desktop.

Revisions

  1. @zkenda zkenda revised this gist Feb 3, 2013. No changes.
  2. @zkenda zkenda revised this gist Feb 3, 2013. 4 changed files with 6050 additions and 0 deletions.
    649 changes: 649 additions & 0 deletions JsLitmus.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,649 @@
    // JSLitmus.js
    //
    // Copyright (c) 2010, Robert Kieffer, http://broofa.com
    // Available under MIT license (http://en.wikipedia.org/wiki/MIT_License)

    (function() {
    // Private methods and state

    // Get platform info but don't go crazy trying to recognize everything
    // that's out there. This is just for the major platforms and OSes.
    var platform = 'unknown platform', ua = navigator.userAgent;

    // Detect OS
    var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
    var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
    if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;

    // Detect browser
    var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;

    // Detect version
    var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
    var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
    var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';

    /**
    * A smattering of methods that are needed to implement the JSLitmus testbed.
    */
    var jsl = {
    /**
    * Enhanced version of escape()
    */
    escape: function(s) {
    s = s.replace(/,/g, '\\,');
    s = escape(s);
    s = s.replace(/\+/g, '%2b');
    s = s.replace(/ /g, '+');
    return s;
    },

    /**
    * Get an element by ID.
    */
    $: function(id) {
    return document.getElementById(id);
    },

    /**
    * Null function
    */
    F: function() {},

    /**
    * Set the status shown in the UI
    */
    status: function(msg) {
    var el = jsl.$('jsl_status');
    if (el) el.innerHTML = msg || '';
    },

    /**
    * Convert a number to an abbreviated string like, "15K" or "10M"
    */
    toLabel: function(n) {
    if (n == Infinity) {
    return 'Infinity';
    } else if (n > 1e9) {
    n = Math.round(n/1e8);
    return n/10 + 'B';
    } else if (n > 1e6) {
    n = Math.round(n/1e5);
    return n/10 + 'M';
    } else if (n > 1e3) {
    n = Math.round(n/1e2);
    return n/10 + 'K';
    }
    return n;
    },

    /**
    * Copy properties from src to dst
    */
    extend: function(dst, src) {
    for (var k in src) dst[k] = src[k]; return dst;
    },

    /**
    * Like Array.join(), but for the key-value pairs in an object
    */
    join: function(o, delimit1, delimit2) {
    if (o.join) return o.join(delimit1); // If it's an array
    var pairs = [];
    for (var k in o) pairs.push(k + delimit1 + o[k]);
    return pairs.join(delimit2);
    },

    /**
    * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
    */
    indexOf: function(arr, o) {
    if (arr.indexOf) return arr.indexOf(o);
    for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
    return -1;
    }
    };

    /**
    * Test manages a single test (created with
    * JSLitmus.test())
    *
    * @private
    */
    var Test = function (name, f) {
    if (!f) throw new Error('Undefined test function');
    if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) {
    throw new Error('"' + name + '" test: Test is not a valid Function object');
    }
    this.loopArg = RegExp.$1;
    this.name = name;
    this.f = f;
    };

    jsl.extend(Test, /** @lends Test */ {
    /** Calibration tests for establishing iteration loop overhead */
    CALIBRATIONS: [
    new Test('calibrating loop', function(count) {while (count--);}),
    new Test('calibrating function', jsl.F)
    ],

    /**
    * Run calibration tests. Returns true if calibrations are not yet
    * complete (in which case calling code should run the tests yet again).
    * onCalibrated - Callback to invoke when calibrations have finished
    */
    calibrate: function(onCalibrated) {
    for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
    var cal = Test.CALIBRATIONS[i];
    if (cal.running) return true;
    if (!cal.count) {
    cal.isCalibration = true;
    cal.onStop = onCalibrated;
    //cal.MIN_TIME = .1; // Do calibrations quickly
    cal.run(2e4);
    return true;
    }
    }
    return false;
    }
    });

    jsl.extend(Test.prototype, {/** @lends Test.prototype */
    /** Initial number of iterations */
    INIT_COUNT: 10,
    /** Max iterations allowed (i.e. used to detect bad looping functions) */
    MAX_COUNT: 1e9,
    /** Minimum time a test should take to get valid results (secs) */
    MIN_TIME: .5,

    /** Callback invoked when test state changes */
    onChange: jsl.F,

    /** Callback invoked when test is finished */
    onStop: jsl.F,

    /**
    * Reset test state
    */
    reset: function() {
    delete this.count;
    delete this.time;
    delete this.running;
    delete this.error;
    },

    /**
    * Run the test (in a timeout). We use a timeout to make sure the browser
    * has a chance to finish rendering any UI changes we've made, like
    * updating the status message.
    */
    run: function(count) {
    count = count || this.INIT_COUNT;
    jsl.status(this.name + ' x ' + count);
    this.running = true;
    var me = this;
    setTimeout(function() {me._run(count);}, 200);
    },

    /**
    * The nuts and bolts code that actually runs a test
    */
    _run: function(count) {
    var me = this;

    // Make sure calibration tests have run
    if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
    this.error = null;

    try {
    var start, f = this.f, now, i = count;

    // Start the timer
    start = new Date();

    // Now for the money shot. If this is a looping function ...
    if (this.loopArg) {
    // ... let it do the iteration itself
    f(count);
    } else {
    // ... otherwise do the iteration for it
    while (i--) f();
    }

    // Get time test took (in secs)
    this.time = Math.max(1,new Date() - start)/1000;

    // Store iteration count and per-operation time taken
    this.count = count;
    this.period = this.time/count;

    // Do we need to do another run?
    this.running = this.time <= this.MIN_TIME;

    // ... if so, compute how many times we should iterate
    if (this.running) {
    // Bump the count to the nearest power of 2
    var x = this.MIN_TIME/this.time;
    var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
    count *= pow;
    if (count > this.MAX_COUNT) {
    throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
    }
    }
    } catch (e) {
    // Exceptions are caught and displayed in the test UI
    this.reset();
    this.error = e;
    }

    // Figure out what to do next
    if (this.running) {
    me.run(count);
    } else {
    jsl.status('');
    me.onStop(me);
    }

    // Finish up
    this.onChange(this);
    },

    /**
    * Get the number of operations per second for this test.
    *
    * @param normalize if true, iteration loop overhead taken into account
    */
    getHz: function(/**Boolean*/ normalize) {
    var p = this.period;

    // Adjust period based on the calibration test time
    if (normalize && !this.isCalibration) {
    var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];

    // If the period is within 20% of the calibration time, then zero the
    // it out
    p = p < cal.period*1.2 ? 0 : p - cal.period;
    }

    return Math.round(1/p);
    },

    /**
    * Get a friendly string describing the test
    */
    toString: function() {
    return this.name + ' - ' + this.time/this.count + ' secs';
    }
    });

    // CSS we need for the UI
    var STYLESHEET = '<style> \
    #jslitmus {font-family:sans-serif; font-size: 12px;} \
    #jslitmus a {text-decoration: none;} \
    #jslitmus a:hover {text-decoration: underline;} \
    #jsl_status { \
    margin-top: 10px; \
    font-size: 10px; \
    color: #888; \
    } \
    A IMG {border:none} \
    #test_results { \
    margin-top: 10px; \
    font-size: 12px; \
    font-family: sans-serif; \
    border-collapse: collapse; \
    border-spacing: 0px; \
    } \
    #test_results th, #test_results td { \
    border: solid 1px #ccc; \
    vertical-align: top; \
    padding: 3px; \
    } \
    #test_results th { \
    vertical-align: bottom; \
    background-color: #ccc; \
    padding: 1px; \
    font-size: 10px; \
    } \
    #test_results #test_platform { \
    color: #444; \
    text-align:center; \
    } \
    #test_results .test_row { \
    color: #006; \
    cursor: pointer; \
    } \
    #test_results .test_nonlooping { \
    border-left-style: dotted; \
    border-left-width: 2px; \
    } \
    #test_results .test_looping { \
    border-left-style: solid; \
    border-left-width: 2px; \
    } \
    #test_results .test_name {white-space: nowrap;} \
    #test_results .test_pending { \
    } \
    #test_results .test_running { \
    font-style: italic; \
    } \
    #test_results .test_done {} \
    #test_results .test_done { \
    text-align: right; \
    font-family: monospace; \
    } \
    #test_results .test_error {color: #600;} \
    #test_results .test_error .error_head {font-weight:bold;} \
    #test_results .test_error .error_body {font-size:85%;} \
    #test_results .test_row:hover td { \
    background-color: #ffc; \
    text-decoration: underline; \
    } \
    #chart { \
    margin: 10px 0px; \
    width: 250px; \
    } \
    #chart img { \
    border: solid 1px #ccc; \
    margin-bottom: 5px; \
    } \
    #chart #tiny_url { \
    height: 40px; \
    width: 250px; \
    } \
    #jslitmus_credit { \
    font-size: 10px; \
    color: #888; \
    margin-top: 8px; \
    } \
    </style>';

    // HTML markup for the UI
    var MARKUP = '<div id="jslitmus"> \
    <button onclick="JSLitmus.runAll(event)">Run Tests</button> \
    <button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
    <br \> \
    <br \> \
    <input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
    <table id="test_results"> \
    <colgroup> \
    <col /> \
    <col width="100" /> \
    </colgroup> \
    <tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
    <tr><th>Test</th><th>Ops/sec</th></tr> \
    <tr id="test_row_template" class="test_row" style="display:none"> \
    <td class="test_name"></td> \
    <td class="test_result">Ready</td> \
    </tr> \
    </table> \
    <div id="jsl_status"></div> \
    <div id="chart" style="display:none"> \
    <a id="chart_link" target="_blank"><img id="chart_image"></a> \
    TinyURL (for chart): \
    <iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
    </div> \
    <a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
    </div>';

    /**
    * The public API for creating and running tests
    */
    window.JSLitmus = {
    /** The list of all tests that have been registered with JSLitmus.test */
    _tests: [],
    /** The queue of tests that need to be run */
    _queue: [],

    /**
    * The parsed query parameters the current page URL. This is provided as a
    * convenience for test functions - it's not used by JSLitmus proper
    */
    params: {},

    /**
    * Initialize
    */
    _init: function() {
    // Parse query params into JSLitmus.params[] hash
    var match = (location + '').match(/([^?#]*)(#.*)?$/);
    if (match) {
    var pairs = match[1].split('&');
    for (var i = 0; i < pairs.length; i++) {
    var pair = pairs[i].split('=');
    if (pair.length > 1) {
    var key = pair.shift();
    var value = pair.length > 1 ? pair.join('=') : pair[0];
    this.params[key] = value;
    }
    }
    }

    // Write out the stylesheet. We have to do this here because IE
    // doesn't honor sheets written after the document has loaded.
    document.write(STYLESHEET);

    // Setup the rest of the UI once the document is loaded
    if (window.addEventListener) {
    window.addEventListener('load', this._setup, false);
    } else if (document.addEventListener) {
    document.addEventListener('load', this._setup, false);
    } else if (window.attachEvent) {
    window.attachEvent('onload', this._setup);
    }

    return this;
    },

    /**
    * Set up the UI
    */
    _setup: function() {
    var el = jsl.$('jslitmus_container');
    if (!el) document.body.appendChild(el = document.createElement('div'));

    el.innerHTML = MARKUP;

    // Render the UI for all our tests
    for (var i=0; i < JSLitmus._tests.length; i++)
    JSLitmus.renderTest(JSLitmus._tests[i]);
    },

    /**
    * (Re)render all the test results
    */
    renderAll: function() {
    for (var i = 0; i < JSLitmus._tests.length; i++)
    JSLitmus.renderTest(JSLitmus._tests[i]);
    JSLitmus.renderChart();
    },

    /**
    * (Re)render the chart graphics
    */
    renderChart: function() {
    var url = JSLitmus.chartUrl();
    jsl.$('chart_link').href = url;
    jsl.$('chart_image').src = url;
    jsl.$('chart').style.display = '';

    // Update the tiny URL
    jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
    },

    /**
    * (Re)render the results for a specific test
    */
    renderTest: function(test) {
    // Make a new row if needed
    if (!test._row) {
    var trow = jsl.$('test_row_template');
    if (!trow) return;

    test._row = trow.cloneNode(true);
    test._row.style.display = '';
    test._row.id = '';
    test._row.onclick = function() {JSLitmus._queueTest(test);};
    test._row.title = 'Run ' + test.name + ' test';
    trow.parentNode.appendChild(test._row);
    test._row.cells[0].innerHTML = test.name;
    }

    var cell = test._row.cells[1];
    var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];

    if (test.error) {
    cns.push('test_error');
    cell.innerHTML =
    '<div class="error_head">' + test.error + '</div>' +
    '<ul class="error_body"><li>' +
    jsl.join(test.error, ': ', '</li><li>') +
    '</li></ul>';
    } else {
    if (test.running) {
    cns.push('test_running');
    cell.innerHTML = 'running';
    } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
    cns.push('test_pending');
    cell.innerHTML = 'pending';
    } else if (test.count) {
    cns.push('test_done');
    var hz = test.getHz(jsl.$('test_normalize').checked);
    cell.innerHTML = hz != Infinity ? hz : '&infin;';
    cell.title = 'Looped ' + test.count + ' times in ' + test.time + ' seconds';
    } else {
    cell.innerHTML = 'ready';
    }
    }
    cell.className = cns.join(' ');
    },

    /**
    * Create a new test
    */
    test: function(name, f) {
    // Create the Test object
    var test = new Test(name, f);
    JSLitmus._tests.push(test);

    // Re-render if the test state changes
    test.onChange = JSLitmus.renderTest;

    // Run the next test if this one finished
    test.onStop = function(test) {
    if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
    JSLitmus.currentTest = null;
    JSLitmus._nextTest();
    };

    // Render the new test
    this.renderTest(test);
    },

    /**
    * Add all tests to the run queue
    */
    runAll: function(e) {
    e = e || window.event;
    var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
    for (var i = 0; i < len; i++) {
    JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
    }
    },

    /**
    * Remove all tests from the run queue. The current test has to finish on
    * it's own though
    */
    stop: function() {
    while (JSLitmus._queue.length) {
    var test = JSLitmus._queue.shift();
    JSLitmus.renderTest(test);
    }
    },

    /**
    * Run the next test in the run queue
    */
    _nextTest: function() {
    if (!JSLitmus.currentTest) {
    var test = JSLitmus._queue.shift();
    if (test) {
    jsl.$('stop_button').disabled = false;
    JSLitmus.currentTest = test;
    test.run();
    JSLitmus.renderTest(test);
    if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
    } else {
    jsl.$('stop_button').disabled = true;
    JSLitmus.renderChart();
    }
    }
    },

    /**
    * Add a test to the run queue
    */
    _queueTest: function(test) {
    if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
    JSLitmus._queue.push(test);
    JSLitmus.renderTest(test);
    JSLitmus._nextTest();
    },

    /**
    * Generate a Google Chart URL that shows the data for all tests
    */
    chartUrl: function() {
    var n = JSLitmus._tests.length, markers = [], data = [];
    var d, min = 0, max = -1e10;
    var normalize = jsl.$('test_normalize').checked;

    // Gather test data
    for (var i=0; i < JSLitmus._tests.length; i++) {
    var test = JSLitmus._tests[i];
    if (test.count) {
    var hz = test.getHz(normalize);
    var v = hz != Infinity ? hz : 0;
    data.push(v);
    markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
    markers.length + ',10');
    max = Math.max(v, max);
    }
    }
    if (markers.length <= 0) return null;

    // Build chart title
    var title = document.getElementsByTagName('title');
    title = (title && title.length) ? title[0].innerHTML : null;
    var chart_title = [];
    if (title) chart_title.push(title);
    chart_title.push('Ops/sec (' + platform + ')');

    // Build labels
    var labels = [jsl.toLabel(min), jsl.toLabel(max)];

    var w = 250, bw = 15;
    var bs = 5;
    var h = markers.length*(bw + bs) + 30 + chart_title.length*20;

    var params = {
    chtt: escape(chart_title.join('|')),
    chts: '000000,10',
    cht: 'bhg', // chart type
    chd: 't:' + data.join(','), // data set
    chds: min + ',' + max, // max/min of data
    chxt: 'x', // label axes
    chxl: '0:|' + labels.join('|'), // labels
    chsp: '0,1',
    chm: markers.join('|'), // test names
    chbh: [bw, 0, bs].join(','), // bar widths
    // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
    chs: w + 'x' + h
    };
    return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
    }
    };

    JSLitmus._init();
    })();
    39 changes: 39 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,39 @@
    <!DOCTYPE html>
    <html>
    <head>
    <title></title>
    <meta charset="UTF-8" />
    <link rel="stylesheet/less" type="text/css" href="test.less">
    <script type="text/javascript" src="less-1.3.1.js"></script>
    <script type="text/javascript" src="less-1.3.1.modifyVars.js"></script>
    <script type="text/javascript" src="JsLitmus.js"></script>
    <script type="text/javascript">

    //lame random color
    function getColor()
    {
    return "#"+Math.floor((Math.random()*9)+1) + Math.floor((Math.random()*9)+1) + Math.floor((Math.random()*9)+1);
    }

    window.onload = function() {
    //less.modifyVars_new({'@color1': '#e2e'});
    JSLitmus.test('less.modifyVars',function(){ less.modifyVars({"@color1": getColor()});});

    JSLitmus.test('less.modify',function(){ less.modify({"@color1": getColor()});});
    };

    </script>
    </head>
    <body>

    <h3>test</h3>
    <p>less.modifyVars - official</p>

    <button onclick="less.modifyVars({'@color1': 'darken(@color2, 21%)'});">modifyVars 1</button>
    <button onclick="less.modifyVars({'@color1': '#eee'});">modifyVars 2</button>

    <p>less.modify - experimental</p>
    <button onclick="less.modify({'@color1': '#252'});">modifyVars 1</button>
    <button onclick="less.modify({'@color1': '#369'});">modifyVars 2</button>
    </body>
    </html>
    4,415 changes: 4,415 additions & 0 deletions less-1.3.1.js
    4,415 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
    947 changes: 947 additions & 0 deletions test.less
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,947 @@
    @color1: #f00;
    @color2: #f90;

    @font-face {
    font-family: 'PFSquareSansProRegular';
    src: url('/res/font/pfsquaresanspro-regular-webfont.eot');
    src: url('/res/font/pfsquaresanspro-regular-webfont.eot?#iefix') format('embedded-opentype'),
    url('/res/font/pfsquaresanspro-regular-webfont.woff') format('woff'),
    url('/res/font/pfsquaresanspro-regular-webfont.ttf') format('truetype'),
    url('/res/font/pfsquaresanspro-regular-webfont.svg#PFSquareSansProRegular') format('svg');
    font-weight: normal;
    font-style: normal;
    }



    @font-face {
    font-family: 'PFSquareSansProBold';
    src: url('/res/font/pfsquaresanspro-bold-webfont.eot');
    src: url('/res/font/pfsquaresanspro-bold-webfont.eot?#iefix') format('embedded-opentype'),
    url('/res/font/pfsquaresanspro-bold-webfont.woff') format('woff'),
    url('/res/font/pfsquaresanspro-bold-webfont.ttf') format('truetype'),
    url('/res/font/pfsquaresanspro-bold-webfont.svg#PFSquareSansProBold') format('svg');
    font-weight: normal;
    font-style: normal;
    }

    @font-face {
    font-family: 'PFSquareSansProRegular';
    src: url('/res/font/pfsquaresanspro-regular-webfont.eot');
    src: url('/res/font/pfsquaresanspro-regular-webfont.eot?#iefix') format('embedded-opentype'),
    url('/res/font/pfsquaresanspro-regular-webfont.woff') format('woff'),
    url('/res/font/pfsquaresanspro-regular-webfont.ttf') format('truetype'),
    url('/res/font/pfsquaresanspro-regular-webfont.svg#PFSquareSansProRegular') format('svg');
    font-weight: normal;
    font-style: normal;
    }

    @font-face {
    font-family: 'PFSquareSansProMedium';
    src: url('/res/font/pfsquaresanspro-medium-webfont.eot');
    src: url('/res/font/pfsquaresanspro-medium-webfont.eot?#iefix') format('embedded-opentype'),
    url('/res/font/pfsquaresanspro-medium-webfont.woff') format('woff'),
    url('/res/font/pfsquaresanspro-medium-webfont.ttf') format('truetype'),
    url('/res/font/pfsquaresanspro-medium-webfont.svg#PFSquareSansProMedium') format('svg');
    font-weight: normal;
    font-style: normal;
    }

    @font-face {
    font-family: 'PFSquareSansProLight';
    src: url('/res/font/pfsquaresanspro-light-webfont.eot');
    src: url('/res/font/pfsquaresanspro-light-webfont.eot?#iefix') format('embedded-opentype'),
    url('/res/font/pfsquaresanspro-light-webfont.woff') format('woff'),
    url('/res/font/pfsquaresanspro-light-webfont.ttf') format('truetype'),
    url('/res/font/pfsquaresanspro-light-webfont.svg#PFSquareSansProLight') format('svg');
    font-weight: normal;
    font-style: normal;
    }

    body {
    background: @color1;
    color: @color2;
    font-family: Arial;
    font-size: 12px;
    }
    td {
    vertical-align: top;
    }

    input {
    outline: none;
    }

    .hideMe {
    display: none !important;
    }
    .sprite {
    background: @color1 url(/res/img/sprite-box.png) 0px 0px no-repeat;
    position: relative;
    }

    .tu-main {
    position: relative;
    width: 960px;
    margin: 10px auto;

    &.uploading {
    .big-btn {
    display: none;
    }
    .uploading-cover {
    display: block;
    }
    .progress-track {
    display: block;
    }
    }

    a {
    text-decoration: none;
    outline: none;
    color: #00baf2;

    &:hover {
    text-decoration: underline;
    }
    }
    h2 {
    color: #00baf2;
    font-weight: normal;
    font-family: 'PFSquareSansProRegular','Arial','sans-serif';
    font-size: 26px;
    line-height: 26px;
    margin: 0px 0px 10px 0px;
    }
    h3 {
    color: @color1;
    font-size: 18px;
    font-weight: normal;
    font-family: 'PFSquareSansProRegular','Arial','sans-serif';
    margin: 4px 0px 10px 0px;
    }
    p {
    color: #676f6c;
    font-family: 'PFSquareSansProRegular','Arial','sans-serif';
    font-size: 13px;
    line-height: 18px;
    padding-bottom: 6px;
    }
    .mail_laptop {
    text-align: center;
    margin: 40px 0px 0px 0px;
    }
    .thanx-mail {

    p {
    font-size: 15px;
    line-height: 20px;
    }
    }
    .uploading-cover {
    display: none;
    position: absolute;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    z-index: 999;
    //background: url(/res/img/uploading-cover.png);
    background: url(/res/img/_.gif);
    }
    }

    .box-gradient {
    position: relative;
    padding: 22px;
    margin-bottom: 18px;

    &.box-intro {
    padding-bottom: 200px;

    a {
    font-style: italic;
    }

    .box-content {
    padding: 25px;

    p.intro-text-1 {
    width: 560px;
    padding-bottom: 18px;
    font-size: 15px;
    line-height: 20px;
    }
    p.intro-text-2 {
    width: 620px;
    padding-bottom: 18px;
    font-size: 15px;
    line-height: 20px;
    }
    }
    }
    &.box-form {
    .box-content {
    padding: 21px;
    }
    }

    .box-tl, .box-tr,
    .box-bl, .box-br,
    .box-tm, .box-bm {
    background: url(/res/img/sprite-box.png) 0px 0px no-repeat;
    position: absolute;
    height: 43px;
    }
    .box-tl {width: 44px; top: 0px; left: 0px; background-position: 0px 0px;}
    .box-tr {width: 44px; top: 0px; right: 0px; background-position: -44px 0px;}
    .box-bl {width: 44px; bottom: 0px; left: 0px; background-position: 0px -43px;}
    .box-br {width: 44px; bottom: 0px; right: 0px; background-position: -44px -43px;}
    .box-tm {top: 0px; left: 44px; right: 44px; background-repeat: repeat-x; background-position: 0px -86px;}
    .box-bm {bottom: 0px; left: 44px; right: 44px; background-repeat: repeat-x; background-position: 0px -129px;}

    .box-ml, .box-mr {
    background: url(/res/img/sprite-box_hrzn.png) 0px 0px repeat-y;
    position: absolute;
    }
    .box-ml {top: 43px; bottom: 43px; left: 0px; width: 44px; background-position: 0px 0px;}
    .box-mr {top: 43px; bottom: 43px; right: 0px; width: 44px; background-position: -44px 0px;}

    .box-content {
    //background: #fff;
    position: relative;
    min-height: 42px;
    z-index: 2;
    }
    }

    .how-does-it-work {
    background: url(/res/img/how-does-it-work.png) 50% 0px no-repeat;
    position: absolute;
    bottom: 0px;
    left: 0px;
    right: 0px;
    height: 196px;

    .how-desc {
    position: absolute;
    top: 120px;
    left: 0px;
    width: 160px;
    color: #787878;
    text-align: center;

    font-family: 'PFSquareSansProMedium','Arial','sans-serif';
    font-size: 12px;
    line-height: 16px;

    &.how-step-1 {left: 19px;}
    &.how-step-2 {left: 211px;}
    &.how-step-3 {left: 402px;}
    &.how-step-4 {left: 596px;}
    &.how-step-5 {left: 785px;}
    }
    }

    .help {
    display: inline-block;
    position: relative;
    top: 4px;
    width: 20px;
    height: 20px;
    margin-left: 4px;
    background-position: -58px -304px;
    cursor: help;

    &.over {
    .box-bubble {
    display: block;
    }
    }

    .box-bubble {
    display: none;
    position: absolute;
    top: -24px;
    left: 100%;
    margin-left: 18px;
    z-index: 12;

    .box-content {
    background: #fff;
    position: relative;
    display: block;
    width: 100px;
    padding: 3px 9px 6px 6px;
    margin: 9px 9px 9px 9px;
    text-align: left;
    font-family: Arial;
    font-size: 10px;
    line-height: 15px;
    color: #666;
    }
    .box-arrow,
    .box-tl, .box-tr,
    .box-bl, .box-br,
    .box-tm, .box-bm {
    background: url(/res/img/sprite-box.png) 0px 0px no-repeat;
    position: absolute;
    height: 11px;
    }
    .box-tl {width: 9px; top: 0px; left: 0px; background-position: 0px -304px;}
    .box-tr {width: 11px; top: 0px; right: 0px; background-position: -9px -304px;}
    .box-bl {width: 9px; bottom: 0px; left: 0px; background-position: 0px -315px;}
    .box-br {width: 11px; bottom: 0px; right: 0px; background-position: -9px -315px;}
    .box-tm {top: 0px; left: 9px; right: 11px; background-repeat: repeat-x; background-position: 0px -326px;}
    .box-bm {bottom: 0px; left: 9px; right: 11px; background-repeat: repeat-x; background-position: 0px -337px;}
    .box-ml {top: 11px; bottom: 11px; left: 0px; width: 9px; background-position: -88px 0px;}
    .box-mr {top: 11px; bottom: 11px; right: 0px; width: 9px; background-position: -99px 0px;}
    .box-arrow {top: 20px; left: -11px; width: 13px; height: 28px; background-position: -66px -220px;}
    }
    }

    .btn_delRow {
    display: none;
    position: absolute;
    top: -2px;
    right: 22px;
    width: 26px;
    height: 27px;
    background-position: -39px -414px;
    cursor: pointer;
    }

    .more-than-one {
    .btn_delRow {
    display: block;
    }
    }

    .box-form {
    color: #666;

    h2 {margin-bottom: 25px;}

    input {
    margin: 0px;
    border: 1px solid #00A8E2;
    box-shadow: inset 1px 1px 0px #bbb;

    &:disabled {
    background: transparent;
    }
    }
    label {
    a {text-decoration: underline;}
    }

    .check_label {
    clear: both;
    width: 400px;
    height: 22px;

    .diff_delivery {
    position: relative;
    height: 22px;
    display: inline-block;
    padding: 4px 0px 0px 0px;
    }
    }
    .form-part-6 {
    .check_label {
    margin: 14px 0px 10px 0px;
    }
    }

    .form-part-4,
    .form-part-5 {

    .col_1 {
    float: left;
    width: 174px;
    margin: 0px 35px 4px 0px;

    input {
    width: 172px;
    margin: 3px 0px 3px 0px;
    }
    }
    .col_2 {
    position: relative;
    float: left;
    width: 180px;
    margin: 0px 0px 20px 0px;

    input {
    width: 172px;
    margin: 3px 0px 3px 0px;
    }
    .select {
    top: 0px;
    }

    .form_cover {
    display: none;
    }

    &.disabled {

    .form_cover {
    display: block;
    position: absolute;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    z-index: 7;
    background: url(/res/img/bg-form_cover.png);
    }

    h3 {
    color: #666;
    }
    input {
    border: #666 1px solid;
    box-shadow: 0px 0px 0px;
    }
    .select {
    top: 2px;
    left: 0px;
    width: 172px;
    height: 16px;
    border: #666 1px solid;

    .select_start,
    .select_middle,
    .select_end {
    display: none;
    }
    }
    }
    }

    label {
    clear: both;
    display: block;
    margin: 0px 0px 8px 0px;

    .select {
    top: 1px;
    width: 149px;
    margin: 1px 0px 1px 0px;
    }
    }

    }

    .form-part-5 .col_1 {margin-bottom: 14px;}

    .strings {
    position: relative;
    font-size: 10px;
    line-height: 12px;
    width: 170px;

    .sample_str {color: #aaa;}
    .error_str {color: #ff0101; display: none;}
    }

    .calc_sum {
    width: 385px;

    .product_row {
    font-size: 12px;
    height: 16px;
    padding: 1px 0px 2px 0px;
    clear: both;
    white-space: nowrap;

    .prod_name {float: left;}
    .prod_worth {float: right;}
    }

    .calc_total {
    color: #00baf2;
    font-size: 15px;
    border-top: #c2c2c2 1px solid;
    padding-top: 5px;
    height: 20px;

    .total_name {float: left;}
    .total_worth {float: right;}
    }
    }

    .tbl_divider {
    clear: both;
    height: 1px;
    width: 100%;
    border-bottom: #dbe0e1 1px solid;
    margin: 25px 0px 20px 0px;
    }

    .tbl_row {
    clear: both;
    display: block;
    min-height: 22px;
    margin: 0px 0px 6px 0px;

    &.row-new-product {
    position: relative;
    z-index: 3;
    }

    &.tbl_headrow {
    height: 14px;
    margin: 14px 0px 2px 0px;
    }
    &.form_files {
    .cell_2 .strings {
    top: 0px;
    padding-top: 6px;
    }
    }

    .tbl_head,
    .tbl_cell {
    position: relative;
    float: left;
    font-size: 12px;

    &.cell_1 {
    width: 210px;

    input {width: 173px;}
    .strings {display: none; width: 186px; height: 15px; top: -2px;}
    }
    &.cell_2 {
    width: 202px;

    input {width: 173px; margin-bottom: 6px;}
    .select {width: 150px;}
    .strings {display: none; width: 175px; height: 15px; top: -2px;}

    &.files_list {
    display: none;
    line-height: 20px;
    padding-top: 2px;
    }
    }
    &.cell_3 {
    width: 100px;

    input {width: 35px; margin-bottom: 6px;}
    .strings {display: none; width: 132px; height: 15px; top: -2px;}
    }
    }
    }

    .matches {
    display: none;
    position: absolute;
    top: 19px;
    left: 0px;
    width: 173px;
    z-index: 13;
    background: #fff;
    border: #01a0d7 1px solid;
    border-top: 0px;
    color: #666;
    box-shadow: 0px 3px 3px #ddd;

    .match {
    border-top: #01a0d7 1px solid;
    font: 10px/18px Arial;
    padding: 0px 0px 0px 5px;
    cursor: pointer;
    }
    .over,
    .active {
    //background: #EEE;
    color: #01a0d7;
    }
    }

    .select {
    position: relative;
    top: -2px;
    left: 5px;
    height: 24px;
    width: 160px;

    .select_middle {
    background-position: 0px -196px;
    background-repeat: repeat-x;
    height: 24px;
    width: 100%;
    cursor: pointer;
    color: #fff;
    font: bold 10px Arial;
    line-height: 23px;
    padding: 0px;
    }
    .select_start {
    position: absolute;
    left: -6px;
    top: 0px;
    width: 6px;
    height: 24px;
    background-position: 0px -172px;
    }
    .select_end {
    position: absolute;
    right: -22px;
    top: 0px;
    width: 22px;
    height: 24px;
    background-position: -66px -172px;
    }

    .options {
    display: none;
    position: absolute;
    top: 21px;
    left: -5px;
    right: -21px;
    z-index: 13;
    background: #fff;
    border: #01a0d7 1px solid;
    border-top: 0px;
    color: #666;
    box-shadow: 0px 3px 3px #ddd;

    .option {
    border-top: #01a0d7 1px solid;
    font: 10px/18px Arial;
    padding: 0px 0px 0px 5px;
    cursor: pointer;
    }
    }

    &.over {
    .select_middle {
    background-position: 0px -348px;
    }
    .select_start {
    background-position: -37px -172px;
    }
    .select_end {
    background-position: -44px -172px;
    }
    }
    &.down {
    z-index: 13;

    .select_middle {
    background-position: 0px -348px;
    }
    .select_start {
    background-position: -37px -172px;
    }
    .select_end {
    background-position: -44px -172px;
    }
    .options {
    display: block;
    z-index: 113;
    }
    }
    }
    .uploadify-queue {
    position: absolute;
    top: 0px;
    left: 210px;
    width: 365px;
    }
    .uploadify-button-text {
    display: none;
    }
    .file {
    position: relative;
    top: -1px;
    left: 5px;
    width: auto;
    height: 27px;
    display: inline-block;
    margin-right: 24px;

    .file_middle {
    background-position: 0px -441px;
    background-repeat: repeat-x;
    height: 27px;
    width: 100%;
    color: #fff;
    font: bold 10px Arial;
    line-height: 26px;
    margin-right: 11px;
    }
    .file_start {
    position: absolute;
    left: -13px;
    top: 0px;
    width: 13px;
    height: 27px;
    background-position: 0px -414px;
    }
    .file_end {
    position: absolute;
    right: -13px;
    top: 0px;
    width: 13px;
    height: 27px;
    background-position: -14px -414px;
    }
    .file_remove {
    position: absolute;
    right: -4px;
    top: 6px;
    width: 12px;
    height: 12px;
    background-position: -27px -414px;
    z-index: 2;
    cursor: pointer;
    }
    }
    .button {
    position: relative;
    top: -2px;
    left: 5px;
    width: 176px;
    height: 24px;
    cursor: pointer;

    .btn_middle {
    background-position: 0px -196px;
    background-repeat: repeat-x;
    height: 24px;
    width: 100%;
    color: #fff;
    font: bold 10px Arial;
    line-height: 23px;
    }
    .btn_start {
    position: absolute;
    left: -6px;
    top: 0px;
    width: 6px;
    height: 24px;
    background-position: 0px -172px;
    }
    .btn_end {
    position: absolute;
    right: -6px;
    top: 0px;
    width: 6px;
    height: 24px;
    background-position: -7px -172px;
    }

    &.over,
    &.down {
    .btn_middle {
    background-position: 0px -348px;
    }
    .btn_start {
    background-position: -13px -172px;
    }
    .btn_end {
    background-position: -20px -172px;
    }
    }

    &.file-wrapper {
    input {
    position: absolute;
    top: 0px;
    left: 0px;
    width: 100%;
    height: 100%;
    //opacity: 0;
    }
    #uploader {
    position: absolute;
    top: 0px;
    left: 0px;
    opacity: 0;
    }
    }
    }
    .progress-track {
    display: none;
    position: relative;
    left: 10px;
    width: 365px;
    height: 13px;
    margin: 35px 0px 30px 0px;
    background-position: 0px -468px;
    background-repeat: repeat-x;

    .pt-left {
    position: absolute;
    top: 0px;
    left: -10px;
    width: 10px;
    height: 13px;
    background-position: -66px -414px;
    }
    .pt-right {
    position: absolute;
    top: 0px;
    right: -11px;
    width: 11px;
    height: 13px;
    background-position: -77px -414px;
    }

    .progress-bar {
    position: relative;
    left: -3px;
    width: 1px;
    height: 13px;
    background-position: 0px -481px;
    background-repeat: repeat-x;

    .pb-left {
    position: absolute;
    top: 0px;
    left: -7px;
    width: 7px;
    height: 13px;
    background-position: -73px -428px;
    }
    .pb-right {
    position: absolute;
    top: 0px;
    right: -7px;
    width: 7px;
    height: 13px;
    background-position: -81px -428px;
    }
    .pb-bubble {
    position: absolute;
    top: -35px;
    right: -27px;
    width: 44px;
    height: 36px;
    background-position: 0px -494px;
    line-height: 28px;
    text-align: center;
    padding: 1px 2px 0px 0px;
    }
    }
    }
    .big-btn {
    position: relative;
    left: 5px;
    width: 176px;
    height: 42px;
    cursor: pointer;

    .btn_middle {
    background-position: 0px -262px;
    background-repeat: repeat-x;
    height: 42px;
    color: #fff;
    font: 20px 'PFSquareSansProLight';
    line-height: 38px;
    text-align: center;

    img {
    position: relative;
    top: 11px;
    }
    }
    .btn_start {
    position: absolute;
    left: -6px;
    top: 0px;
    width: 6px;
    height: 42px;
    background-position: 0px -220px;
    }
    .btn_end {
    position: absolute;
    right: -6px;
    top: 0px;
    width: 6px;
    height: 42px;
    background-position: -82px -220px;
    }

    &.down {
    .btn_middle {
    background-position: -6px -372px;
    }
    .btn_start {
    background-position: -6px -220px;
    }
    .btn_end {
    background-position: -13px -220px;
    }
    }
    }

    .submit-strings {
    position: absolute;
    top: 0px;
    left: 100%;
    margin-left: 35px;
    width: 150px;

    font-family: 'PFSquareSansProRegular';
    font-size: 18px;
    line-height: 20px;
    color: #f00;

    .sample_str {display: none;}
    .error_str {display: none;}
    }

    .accept-conditions {
    position: relative;
    height: 26px;
    display: block;
    padding: 4px 0px 0px 0px;
    }
    .error_str_2 {
    display: none;
    }
    .checkbox {
    float: left;
    height: 19px;
    width: 18px;
    overflow: hidden;
    margin: 0px 3px 4px 0px;
    line-height: 10px;
    background: url(/res/img/sprite-box.png) -20px -305px no-repeat;
    cursor: pointer;
    text-align: left;
    border: #FFF 1px dotted;
    position: relative;
    top: -2px;

    &.focus {
    border-color: #00a8e2;
    }
    &.focus {
    border-color: #00a8e2;
    }
    &.checked {
    background-position: -39px -305px;
    }
    }
    .checkbox input,
    .radio input {
    //display: none;
    width: 20px!important;
    height: 20px;
    opacity: 0;
    filter: alpha(opacity=0);
    }

    }




  3. @zkenda zkenda created this gist Feb 3, 2013.
    173 changes: 173 additions & 0 deletions less-1.3.1.modifyVars.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,173 @@
    /************** LESS modifyVars 1.3 ***************
    Copyright (c) 2012, Zoran Kenda
    Licensed under the Apache 2.0 License.
    Modified version of less.js is required. I tried to keep modifications at minumum to ensure future versions compatibility.
    Modifications in less.js (v.1.3):
    ---
    function loadStyleSheets(callback, reload) {
    less.roots = []; //modification 1 ln 3224
    ---
    function loadStyleSheet(
    ...
    }).parse(data, function (e, root) {
    if (e) { return error(e, href) }
    try {
    less.roots.push({root: root, sheet : sheet}); //modification 2 ln:3267 <---
    Usage:
    var modifications= {
    "@baseRotation": function(){
    index+=3;
    return index;
    },
    "@headerColor": "#08c",
    "@footerColor":{value:"spin(@headerColor,150 + @baseRotation)",type:"expression"},
    "@focusImage":"focus1.png?a.h=@{baseRotation}"
    }
    less.modify(modifications);
    ************************************************/

    (function (window, undefined) {

    if(!less){ console.log("Less.js not loaded. exiting"); return; }

    less.modify = function(modifications){

    if(!less.roots || less.roots.length==0)
    less.refresh(true);

    if(!less.roots) { console.log("less.roots is null. Are you using an unmodified version of less.js?"); return; }

    for(var i = 0;i<less.roots.length;i++){
    var modified = false;
    var rootInfo = less.roots[i];
    var root = rootInfo.root;
    var sheet = rootInfo.sheet;

    for(var name in modifications){
    var variable = root.variable(name);
    var valx = null;

    if(variable && variable.value){
    var value = modifications[name];
    var type = typeof value;

    if(type === "function"){
    value = value();
    var type = typeof value;
    } //zanalasc ni else

    if(typeof value ==="object" && value.value && value.type){
    type = value.type;
    value = value.value;
    }

    console.log("modifiing var "+name +" value: "+value);

    try{
    //valx = variable.value.eval();
    if(type =="number"){
    variable.value = getDimension(value);
    modified = true;
    } else if((type=="color" || (type == "string" && value.length>0)) && value.charAt(0)=="#"){ //barva je
    variable.value = getColor(value);
    modified = true;
    } else if(type=="expression"){
    new( less.Parser)().parse("@tempExpr:"+value+";",function(e,f){
    variable.value = f.variable("@tempExpr").value;
    });
    modified = true;
    }
    else if(type =="string"){ //barva je
    variable.value = getLiteral(value);
    modified = true;
    }
    else{
    console.log("ni rbg, ni number, ni literal");
    }
    }catch(e){
    console.log(e);
    }
    console.log("modified var "+name);
    }
    }
    if(modified)
    createCSS(root.toCSS(), sheet);
    }
    }

    /* values to expressions */
    function getValue(val){
    return new(less.tree.Value)([new(less.tree.Expression)([val])]);
    }

    function getDimension(val){
    return getValue(new(less.tree.Dimension)(val));
    }

    function getColor(val){
    var rgb;

    if ( (val.charAt(0) === '#') && (rgb = (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/).exec(val)) ) {
    val = rgb[1];
    }
    return getValue(new(less.tree.Color)(val));
    }

    function getLiteral(val){
    return getValue(new(less.tree.Quoted)("'",val,false));
    }


    /******************* Slightly modified functions taken from less.js ***************/
    //copied from less.js and modified a little (removed cache update code)
    function createCSS(styles, sheet) {
    var css;
    // Strip the query-string
    var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';

    // If there is no title set, use the filename, minus the extension
    var id = 'less:' + (sheet.title || extractId(href));

    // If the stylesheet doesn't exist, create a new node
    if ((css = document.getElementById(id)) === null) {
    css = document.createElement('style');
    css.type = 'text/css';
    css.media = sheet.media || 'screen';
    css.id = id;
    document.getElementsByTagName('head')[0].appendChild(css);
    }

    if (css.styleSheet) { // IE
    try {
    css.styleSheet.cssText = styles;
    } catch (e) {
    throw new(Error)("Couldn't reassign styleSheet.cssText.");
    }
    } else {
    (function (node) {
    if (css.childNodes.length > 0) {
    if (css.firstChild.nodeValue !== node.nodeValue) {
    css.replaceChild(node, css.firstChild);
    }
    } else {
    css.appendChild(node);
    }
    })(document.createTextNode(styles));
    }
    }

    //copied from less.js 1.3
    function extractId(href) {
    return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' ) // Remove protocol & domain
    .replace(/^\//, '' ) // Remove root /
    .replace(/\?.*$/, '' ) // Remove query
    .replace(/\.[^\.\/]+$/, '' ) // Remove file extension
    .replace(/[^\.\w-]+/g, '-') // Replace illegal characters
    .replace(/\./g, ':'); // Replace dots with colons(for valid id)
    }



    })(window);