~ubuntu-branches/ubuntu/trusty/horizon/trusty-updates

« back to all changes in this revision

Viewing changes to bin/lib/less/browser.js

  • Committer: Package Import Robot
  • Author(s): Adam Gandelman
  • Date: 2013-09-06 11:59:43 UTC
  • mfrom: (1.1.30)
  • Revision ID: package-import@ubuntu.com-20130906115943-h3td0l7tp16mb9oc
Tags: 1:2013.2~b3-0ubuntu1
* New upstream release.
* debian/control: Minimum python-openstack-auth version >= 1.1.1.
* debian/control: Add python-troveclient.
* debian/static: Refresh static assets for 2013.2~b3.
* debian/patches: ubuntu_local_settings.patch -> ubuntu_settings.patch, also
  patch location of secret key in openstack_dashboard/settings.py

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// browser.js - client-side engine
3
 
//
4
 
 
5
 
var isFileProtocol = (location.protocol === 'file:'    ||
6
 
                      location.protocol === 'chrome:'  ||
7
 
                      location.protocol === 'chrome-extension:'  ||
8
 
                      location.protocol === 'resource:');
9
 
 
10
 
less.env = less.env || (location.hostname == '127.0.0.1' ||
11
 
                        location.hostname == '0.0.0.0'   ||
12
 
                        location.hostname == 'localhost' ||
13
 
                        location.port.length > 0         ||
14
 
                        isFileProtocol                   ? 'development'
15
 
                                                         : 'production');
16
 
 
17
 
// Load styles asynchronously (default: false)
18
 
//
19
 
// This is set to `false` by default, so that the body
20
 
// doesn't start loading before the stylesheets are parsed.
21
 
// Setting this to `true` can result in flickering.
22
 
//
23
 
less.async = false;
24
 
 
25
 
// Interval between watch polls
26
 
less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
27
 
 
28
 
//
29
 
// Watch mode
30
 
//
31
 
less.watch   = function () { return this.watchMode = true };
32
 
less.unwatch = function () { return this.watchMode = false };
33
 
 
34
 
if (less.env === 'development') {
35
 
    less.optimization = 0;
36
 
 
37
 
    if (/!watch/.test(location.hash)) {
38
 
        less.watch();
39
 
    }
40
 
    less.watchTimer = setInterval(function () {
41
 
        if (less.watchMode) {
42
 
            loadStyleSheets(function (e, root, _, sheet, env) {
43
 
                if (root) {
44
 
                    createCSS(root.toCSS(), sheet, env.lastModified);
45
 
                }
46
 
            });
47
 
        }
48
 
    }, less.poll);
49
 
} else {
50
 
    less.optimization = 3;
51
 
}
52
 
 
53
 
var cache;
54
 
 
55
 
try {
56
 
    cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
57
 
} catch (_) {
58
 
    cache = null;
59
 
}
60
 
 
61
 
//
62
 
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
63
 
//
64
 
var links = document.getElementsByTagName('link');
65
 
var typePattern = /^text\/(x-)?less$/;
66
 
 
67
 
less.sheets = [];
68
 
 
69
 
for (var i = 0; i < links.length; i++) {
70
 
    if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
71
 
       (links[i].type.match(typePattern)))) {
72
 
        less.sheets.push(links[i]);
73
 
    }
74
 
}
75
 
 
76
 
 
77
 
less.refresh = function (reload) {
78
 
    var startTime, endTime;
79
 
    startTime = endTime = new(Date);
80
 
 
81
 
    loadStyleSheets(function (e, root, _, sheet, env) {
82
 
        if (env.local) {
83
 
            log("loading " + sheet.href + " from cache.");
84
 
        } else {
85
 
            log("parsed " + sheet.href + " successfully.");
86
 
            createCSS(root.toCSS(), sheet, env.lastModified);
87
 
        }
88
 
        log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
89
 
        (env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
90
 
        endTime = new(Date);
91
 
    }, reload);
92
 
 
93
 
    loadStyles();
94
 
};
95
 
less.refreshStyles = loadStyles;
96
 
 
97
 
less.refresh(less.env === 'development');
98
 
 
99
 
function loadStyles() {
100
 
    var styles = document.getElementsByTagName('style');
101
 
    for (var i = 0; i < styles.length; i++) {
102
 
        if (styles[i].type.match(typePattern)) {
103
 
            new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) {
104
 
                var css = tree.toCSS();
105
 
                var style = styles[i];
106
 
                style.type = 'text/css';
107
 
                if (style.styleSheet) {
108
 
                    style.styleSheet.cssText = css;
109
 
                } else {
110
 
                    style.innerHTML = css;
111
 
                }
112
 
            });
113
 
        }
114
 
    }
115
 
}
116
 
 
117
 
function loadStyleSheets(callback, reload) {
118
 
    for (var i = 0; i < less.sheets.length; i++) {
119
 
        loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
120
 
    }
121
 
}
122
 
 
123
 
function loadStyleSheet(sheet, callback, reload, remaining) {
124
 
    var url       = window.location.href.replace(/[#?].*$/, '');
125
 
    var href      = sheet.href.replace(/\?.*$/, '');
126
 
    var css       = cache && cache.getItem(href);
127
 
    var timestamp = cache && cache.getItem(href + ':timestamp');
128
 
    var styles    = { css: css, timestamp: timestamp };
129
 
 
130
 
    // Stylesheets in IE don't always return the full path
131
 
    if (! /^(https?|file):/.test(href)) {
132
 
        if (href.charAt(0) == "/") {
133
 
            href = window.location.protocol + "//" + window.location.host + href;
134
 
        } else {
135
 
            href = url.slice(0, url.lastIndexOf('/') + 1) + href;
136
 
        }
137
 
    }
138
 
    var filename = href.match(/([^\/]+)$/)[1];
139
 
 
140
 
    xhr(sheet.href, sheet.type, function (data, lastModified) {
141
 
        if (!reload && styles && lastModified &&
142
 
           (new(Date)(lastModified).valueOf() ===
143
 
            new(Date)(styles.timestamp).valueOf())) {
144
 
            // Use local copy
145
 
            createCSS(styles.css, sheet);
146
 
            callback(null, null, data, sheet, { local: true, remaining: remaining });
147
 
        } else {
148
 
            // Use remote copy (re-parse)
149
 
            try {
150
 
                new(less.Parser)({
151
 
                    optimization: less.optimization,
152
 
                    paths: [href.replace(/[\w\.-]+$/, '')],
153
 
                    mime: sheet.type,
154
 
                    filename: filename
155
 
                }).parse(data, function (e, root) {
156
 
                    if (e) { return error(e, href) }
157
 
                    try {
158
 
                        callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining });
159
 
                        removeNode(document.getElementById('less-error-message:' + extractId(href)));
160
 
                    } catch (e) {
161
 
                        error(e, href);
162
 
                    }
163
 
                });
164
 
            } catch (e) {
165
 
                error(e, href);
166
 
            }
167
 
        }
168
 
    }, function (status, url) {
169
 
        throw new(Error)("Couldn't load " + url + " (" + status + ")");
170
 
    });
171
 
}
172
 
 
173
 
function extractId(href) {
174
 
    return href.replace(/^[a-z]+:\/\/?[^\/]+/, '' )  // Remove protocol & domain
175
 
               .replace(/^\//,                 '' )  // Remove root /
176
 
               .replace(/\?.*$/,               '' )  // Remove query
177
 
               .replace(/\.[^\.\/]+$/,         '' )  // Remove file extension
178
 
               .replace(/[^\.\w-]+/g,          '-')  // Replace illegal characters
179
 
               .replace(/\./g,                 ':'); // Replace dots with colons(for valid id)
180
 
}
181
 
 
182
 
function createCSS(styles, sheet, lastModified) {
183
 
    var css;
184
 
 
185
 
    // Strip the query-string
186
 
    var href = sheet.href ? sheet.href.replace(/\?.*$/, '') : '';
187
 
 
188
 
    // If there is no title set, use the filename, minus the extension
189
 
    var id = 'less:' + (sheet.title || extractId(href));
190
 
 
191
 
    // If the stylesheet doesn't exist, create a new node
192
 
    if ((css = document.getElementById(id)) === null) {
193
 
        css = document.createElement('style');
194
 
        css.type = 'text/css';
195
 
        css.media = sheet.media || 'screen';
196
 
        css.id = id;
197
 
        document.getElementsByTagName('head')[0].appendChild(css);
198
 
    }
199
 
 
200
 
    if (css.styleSheet) { // IE
201
 
        try {
202
 
            css.styleSheet.cssText = styles;
203
 
        } catch (e) {
204
 
            throw new(Error)("Couldn't reassign styleSheet.cssText.");
205
 
        }
206
 
    } else {
207
 
        (function (node) {
208
 
            if (css.childNodes.length > 0) {
209
 
                if (css.firstChild.nodeValue !== node.nodeValue) {
210
 
                    css.replaceChild(node, css.firstChild);
211
 
                }
212
 
            } else {
213
 
                css.appendChild(node);
214
 
            }
215
 
        })(document.createTextNode(styles));
216
 
    }
217
 
 
218
 
    // Don't update the local store if the file wasn't modified
219
 
    if (lastModified && cache) {
220
 
        log('saving ' + href + ' to cache.');
221
 
        cache.setItem(href, styles);
222
 
        cache.setItem(href + ':timestamp', lastModified);
223
 
    }
224
 
}
225
 
 
226
 
function xhr(url, type, callback, errback) {
227
 
    var xhr = getXMLHttpRequest();
228
 
    var async = isFileProtocol ? false : less.async;
229
 
 
230
 
    if (typeof(xhr.overrideMimeType) === 'function') {
231
 
        xhr.overrideMimeType('text/css');
232
 
    }
233
 
    xhr.open('GET', url, async);
234
 
    xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
235
 
    xhr.send(null);
236
 
 
237
 
    if (isFileProtocol) {
238
 
        if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
239
 
            callback(xhr.responseText);
240
 
        } else {
241
 
            errback(xhr.status, url);
242
 
        }
243
 
    } else if (async) {
244
 
        xhr.onreadystatechange = function () {
245
 
            if (xhr.readyState == 4) {
246
 
                handleResponse(xhr, callback, errback);
247
 
            }
248
 
        };
249
 
    } else {
250
 
        handleResponse(xhr, callback, errback);
251
 
    }
252
 
 
253
 
    function handleResponse(xhr, callback, errback) {
254
 
        if (xhr.status >= 200 && xhr.status < 300) {
255
 
            callback(xhr.responseText,
256
 
                     xhr.getResponseHeader("Last-Modified"));
257
 
        } else if (typeof(errback) === 'function') {
258
 
            errback(xhr.status, url);
259
 
        }
260
 
    }
261
 
}
262
 
 
263
 
function getXMLHttpRequest() {
264
 
    if (window.XMLHttpRequest) {
265
 
        return new(XMLHttpRequest);
266
 
    } else {
267
 
        try {
268
 
            return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
269
 
        } catch (e) {
270
 
            log("browser doesn't support AJAX.");
271
 
            return null;
272
 
        }
273
 
    }
274
 
}
275
 
 
276
 
function removeNode(node) {
277
 
    return node && node.parentNode.removeChild(node);
278
 
}
279
 
 
280
 
function log(str) {
281
 
    if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
282
 
}
283
 
 
284
 
function error(e, href) {
285
 
    var id = 'less-error-message:' + extractId(href);
286
 
    var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
287
 
    var elem = document.createElement('div'), timer, content, error = [];
288
 
    var filename = e.filename || href;
289
 
 
290
 
    elem.id        = id;
291
 
    elem.className = "less-error-message";
292
 
 
293
 
    content = '<h3>'  + (e.message || 'There is an error in your .less file') +
294
 
              '</h3>' + '<p>in <a href="' + filename   + '">' + filename + "</a> ";
295
 
 
296
 
    var errorline = function (e, i, classname) {
297
 
        if (e.extract[i]) {
298
 
            error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1))
299
 
                               .replace(/\{class\}/, classname)
300
 
                               .replace(/\{content\}/, e.extract[i]));
301
 
        }
302
 
    };
303
 
 
304
 
    if (e.stack) {
305
 
        content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
306
 
    } else if (e.extract) {
307
 
        errorline(e, 0, '');
308
 
        errorline(e, 1, 'line');
309
 
        errorline(e, 2, '');
310
 
        content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
311
 
                    '<ul>' + error.join('') + '</ul>';
312
 
    }
313
 
    elem.innerHTML = content;
314
 
 
315
 
    // CSS for error messages
316
 
    createCSS([
317
 
        '.less-error-message ul, .less-error-message li {',
318
 
            'list-style-type: none;',
319
 
            'margin-right: 15px;',
320
 
            'padding: 4px 0;',
321
 
            'margin: 0;',
322
 
        '}',
323
 
        '.less-error-message label {',
324
 
            'font-size: 12px;',
325
 
            'margin-right: 15px;',
326
 
            'padding: 4px 0;',
327
 
            'color: #cc7777;',
328
 
        '}',
329
 
        '.less-error-message pre {',
330
 
            'color: #dd6666;',
331
 
            'padding: 4px 0;',
332
 
            'margin: 0;',
333
 
            'display: inline-block;',
334
 
        '}',
335
 
        '.less-error-message pre.line {',
336
 
            'color: #ff0000;',
337
 
        '}',
338
 
        '.less-error-message h3 {',
339
 
            'font-size: 20px;',
340
 
            'font-weight: bold;',
341
 
            'padding: 15px 0 5px 0;',
342
 
            'margin: 0;',
343
 
        '}',
344
 
        '.less-error-message a {',
345
 
            'color: #10a',
346
 
        '}',
347
 
        '.less-error-message .error {',
348
 
            'color: red;',
349
 
            'font-weight: bold;',
350
 
            'padding-bottom: 2px;',
351
 
            'border-bottom: 1px dashed red;',
352
 
        '}'
353
 
    ].join('\n'), { title: 'error-message' });
354
 
 
355
 
    elem.style.cssText = [
356
 
        "font-family: Arial, sans-serif",
357
 
        "border: 1px solid #e00",
358
 
        "background-color: #eee",
359
 
        "border-radius: 5px",
360
 
        "-webkit-border-radius: 5px",
361
 
        "-moz-border-radius: 5px",
362
 
        "color: #e00",
363
 
        "padding: 15px",
364
 
        "margin-bottom: 15px"
365
 
    ].join(';');
366
 
 
367
 
    if (less.env == 'development') {
368
 
        timer = setInterval(function () {
369
 
            if (document.body) {
370
 
                if (document.getElementById(id)) {
371
 
                    document.body.replaceChild(elem, document.getElementById(id));
372
 
                } else {
373
 
                    document.body.insertBefore(elem, document.body.firstChild);
374
 
                }
375
 
                clearInterval(timer);
376
 
            }
377
 
        }, 10);
378
 
    }
379
 
}
380