updated app

This commit is contained in:
2012-05-30 23:00:06 -04:00
parent 6a753904b7
commit da6ad88d48
5545 changed files with 1101709 additions and 60 deletions

View File

@@ -22,7 +22,7 @@
names: $('#employee_name').val(),
salary: $('#employee_salary').val()
};
socket.emit('add employee', data);
socket.emit('add employee', 'data');
$('#employee_name').val('');
$('#employee_salary').val('');
});

3
first-project/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.DS_Store
public/gen
*.swp

1
first-project/README.md Normal file
View File

@@ -0,0 +1 @@
# first-project

View File

@@ -0,0 +1,83 @@
var app = require('derby').createApp(module)
, get = app.get
, view = app.view
, ready = app.ready
, start
// ROUTES //
start = +new Date()
// Derby routes can be rendered on the client and the server
get('/:roomName?', function(page, model, params) {
var roomName = params.roomName || 'home'
// Subscribes the model to any updates on this room's object. Calls back
// with a scoped model equivalent to:
// room = model.at('rooms.' + roomName)
model.subscribe('rooms.' + roomName, function(err, room) {
model.ref('_room', room)
// setNull will set a value if the object is currently null or undefined
room.setNull('welcome', 'Welcome to ' + roomName + '!')
room.incr('visits')
// This value is set for when the page initially renders
model.set('_timer', '0.0')
// Reset the counter when visiting a new route client-side
start = +new Date()
// Render will use the model data as well as an optional context object
page.render({
roomName: roomName
, randomUrl: parseInt(Math.random() * 1e9).toString(36)
})
})
})
// CONTROLLER FUNCTIONS //
ready(function(model) {
var timer
// Expose the model as a global variable in the browser. This is fun in
// development, but it should be removed when writing an app
window.model = model
// Exported functions are exposed as a global in the browser with the same
// name as the module that includes Derby. They can also be bound to DOM
// events using the "x-bind" attribute in a template.
exports.stop = function() {
// Any path name that starts with an underscore is private to the current
// client. Nothing set under a private path is synced back to the server.
model.set('_stopped', true)
clearInterval(timer)
}
exports.start = function() {
model.set('_stopped', false)
timer = setInterval(function() {
model.set('_timer', (((+new Date()) - start) / 1000).toFixed(1))
}, 100)
}
exports.start()
model.set('_showReconnect', true)
exports.connect = function() {
// Hide the reconnect link for a second after clicking it
model.set('_showReconnect', false)
setTimeout(function() {
model.set('_showReconnect', true)
}, 1000)
model.socket.socket.connect()
}
exports.reload = function() {
window.location.reload()
}
})

View File

@@ -0,0 +1,53 @@
var http = require('http')
, path = require('path')
, express = require('express')
, gzippo = require('gzippo')
, derby = require('derby')
, app = require('../app')
, serverError = require('./serverError')
// SERVER CONFIGURATION //
var ONE_YEAR = 1000 * 60 * 60 * 24 * 365
, root = path.dirname(path.dirname(__dirname))
, publicPath = path.join(root, 'public')
, expressApp, server, store
;(expressApp = express())
.use(express.favicon())
// Gzip static files and serve from memory
.use(gzippo.staticGzip(publicPath, {maxAge: ONE_YEAR}))
// Gzip dynamically rendered content
.use(express.compress())
// Uncomment to add form data parsing support
// .use(express.bodyParser())
// .use(express.methodOverride())
// Derby session middleware creates req.model and subscribes to _session
// .use(express.cookieParser('secret_sauce'))
// .use(express.session({
// cookie: {maxAge: ONE_YEAR}
// }))
// .use(app.session())
// The router method creates an express middleware from the app's routes
.use(app.router())
.use(expressApp.router)
.use(serverError(root))
module.exports = server = http.createServer(expressApp)
// SERVER ONLY ROUTES //
expressApp.all('*', function(req) {
throw '404: ' + req.url
})
// STORE SETUP //
store = app.createStore({listen: server})

View File

@@ -0,0 +1,21 @@
var derby = require('derby')
, isProduction = derby.util.isProduction
module.exports = function(root) {
var staticPages = derby.createStatic(root)
return function(err, req, res, next) {
if (err == null) return next()
console.log(err.stack ? err.stack : err)
// Customize error handling here
var message = err.message || err.toString()
, status = parseInt(message)
if (status === 404) {
staticPages.render('404', res, {url: req.url}, 404)
} else {
res.send( ((status >= 400) && (status < 600)) ? status : 500)
}
}
}

9
first-project/node_modules/.bin/derby generated vendored Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
if [ -x "`dirname "$0"`/node" ]; then
"`dirname "$0"`/node" "`dirname "$0"`/../derby/bin/derby" "$@"
ret=$?
else
node "`dirname "$0"`/../derby/bin/derby" "$@"
ret=$?
fi
exit $ret

6
first-project/node_modules/.bin/derby.cmd generated vendored Normal file
View File

@@ -0,0 +1,6 @@
:: Created by npm, please don't edit manually.
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\derby\bin\derby" %*
) ELSE (
node "%~dp0\..\derby\bin\derby" %*
)

6
first-project/node_modules/.bin/express.cmd generated vendored Normal file
View File

@@ -0,0 +1,6 @@
:: Created by npm, please don't edit manually.
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\express\bin\express" %*
) ELSE (
node "%~dp0\..\express\bin\express" %*
)

2
first-project/node_modules/derby/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules
test-output.tmp

17
first-project/node_modules/derby/Makefile generated vendored Normal file
View File

@@ -0,0 +1,17 @@
compile:
./node_modules/coffee-script/bin/coffee -bw -o ./bin/lib -c ./bin/src
MOCHA_TESTS := $(shell find test/ -name '*.mocha.*')
MOCHA := ./node_modules/racer/node_modules/mocha/bin/mocha
OUT_FILE = "test-output.tmp"
g = "."
test-mocha:
@NODE_ENV=test $(MOCHA) \
--grep "$(g)" \
$(MOCHA_TESTS) | tee $(OUT_FILE)
test: test-mocha
test!:
@perl -n -e '/\[31m 0\) (.*?).\[0m/ && print "make test g=\"$$1\$$\""' $(OUT_FILE) | sh

36
first-project/node_modules/derby/README.md generated vendored Normal file
View File

@@ -0,0 +1,36 @@
# Derby
The Derby MVC framework makes it easy to write realtime, collaborative applications that run in both Node.js and browsers.
Derby includes a powerful data synchronization engine called Racer that automatically syncs data among browsers, servers, and a database. Models subscribe to changes on specific objects, enabling granular control of data propagation without defining channels. Racer supports offline usage and conflict resolution out of the box, which greatly simplifies writing multi-user applications.
Derby applications load immediately and can be indexed by search engines, because the same templates render on both server and client. In addition, templates define bindings, which instantly update the view when the model changes and vice versa. Derby makes it simple to write applications that load as fast as a search engine, are as interactive as a document editor, and work offline.
See **http://derbyjs.com/**
## Disclaimer
Derby and Racer are alpha software. While Derby should work well enough for prototyping and weekend projects, it is still undergoing major development. APIs are subject to change.
If you have feedback, ideas, or suggestions, please message the [Google Group](http://groups.google.com/group/derbyjs) or create an Issue. If you are interested in contributing, please reach out to [Brian](https://github.com/bnoguchi) and [Nate](https://github.com/nateps).
## MIT License
Copyright (c) 2011 by Nate Smith and Brian Noguchi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

385
first-project/node_modules/derby/lib/Dom.js generated vendored Normal file
View File

@@ -0,0 +1,385 @@
var racer = require('racer')
, domShim = require('dom-shim')
, EventDispatcher = require('./EventDispatcher')
, escapeHtml = require('html-util').escapeHtml
, merge = racer.util.merge
, win = window
, doc = document
, markers = {}
, elements = {
$_win: win
, $_doc: doc
}
, addListener, removeListener;
module.exports = Dom;
function Dom(model) {
var dom = this
, fns = this.fns
// Map dom event name -> true
, listenerAdded = {}
, captureListenerAdded = {};
// DOM listener capturing allows blur and focus to be delegated
// http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
var events = this._events = new EventDispatcher({
onTrigger: onTrigger
, onBind: function(name, listener, eventName) {
if (!listenerAdded[eventName]) {
addListener(doc, eventName, trigger, true);
listenerAdded[eventName] = true;
}
}
});
var captureEvents = this._captureEvents = new EventDispatcher({
onTrigger: function(name, listener, e) {
var el = doc.getElementById(id)
, id = listener.id;
if (el.tagName === 'HTML' || el.contains(e.target)) {
onTrigger(name, listener, id, e, el);
}
}
, onBind: function(name, listener) {
if (!captureListenerAdded[name]) {
addListener(doc, name, captureTrigger, true);
captureListenerAdded[name] = true;
}
}
});
function onTrigger(name, listener, id, e, el, next) {
var delay = listener.delay
, finish = listener.fn;
if (!finish) {
// Update the model when the element's value changes
finish = function() {
var value = dom.getMethods[listener.method](el, listener.property)
, setValue = listener.setValue;
// Allow the listener to override the setting function
if (setValue) {
setValue(model, value);
return;
}
// Remove this listener if its path id is no longer registered
var path = model.__pathMap.paths[listener.pathId];
if (!path) return false;
// Set the value if changed
if (model.get(path) === value) return;
model.pass(e).set(path, value);
}
}
if (delay != null) {
setTimeout(finish, delay, e, el, next, dom);
} else {
finish(e, el, next, dom);
}
}
function trigger(e, el, noBubble, continued) {
if (!el) el = e.target;
var prefix = e.type + ':'
, id;
// Next can be called from a listener to continue bubbling
function next() {
trigger(e, el.parentNode, false, true);
}
next.firstTrigger = !continued;
if (noBubble && (id = el.id)) {
return events.trigger(prefix + id, id, e, el, next);
}
while (true) {
while (!(id = el.id)) {
if (!(el = el.parentNode)) return;
}
// Stop bubbling once the event is handled
if (events.trigger(prefix + id, id, e, el, next)) return;
if (!(el = el.parentNode)) return;
}
}
function captureTrigger(e) {
captureEvents.trigger(e.type, e);
}
this.trigger = trigger;
this.captureTrigger = captureTrigger;
this.addListener = addListener;
this.removeListener = removeListener;
this._componentListeners = [];
}
Dom.prototype = {
clear: function() {
this._events.clear();
this._captureEvents.clear();
var listeners = this._componentListeners
, i, listener;
for (i = listeners.length; i--;) {
listener = listeners[i];
removeListener(listener[0], listener[1], listener[2], listener[3]);
}
this._componentListeners = [];
markers = {};
}
, bind: function(eventName, id, listener) {
if (listener.capture) {
listener.id = id;
this._captureEvents.bind(eventName, listener);
} else {
this._events.bind("" + eventName + ":" + id, listener, eventName);
}
}
, update: function(el, method, ignore, value, property, index) {
// Don't do anything if the element is already up to date
if (value === this.getMethods[method](el, property)) return;
this.setMethods[method](el, ignore, value, property, index);
}
, item: function(id) {
return doc.getElementById(id) || elements[id] || getRange(id);
}
, componentDom: function() {
var componentListeners = this._componentListeners
, dom = Object.create(this);
dom.addListener = function(el, name, callback, captures) {
componentListeners.push(arguments);
addListener(el, name, callback, captures);
};
return dom;
}
, getMethods: {
attr: getAttr
, prop: getProp
, propPolite: getProp
, html: getHtml
// These methods return NaN, because it never equals anything else. Thus,
// when compared against the new value, the new value will always be set
, append: getNaN
, insert: getNaN
, remove: getNaN
, move: getNaN
}
, setMethods: {
attr: setAttr
, prop: setProp
, propPolite: setProp
, html: setHtml
, append: setAppend
, insert: setInsert
, remove: setRemove
, move: setMove
}
, fns: {
$forChildren: forChildren
, $forName: forName
}
}
function getAttr(el, attr) {
return el.getAttribute(attr);
}
function getProp(el, prop) {
return el[prop];
}
function getHtml(el) {
return el.innerHTML;
}
function getNaN() {
return NaN;
}
function setAttr(el, ignore, value, attr) {
if (ignore && el.id === ignore) return;
el.setAttribute(attr, value);
}
function setProp(el, ignore, value, prop) {
if (ignore && el.id === ignore) return;
el[prop] = value;
}
function propPolite(el, ignore, value, prop) {
if (ignore && el.id === ignore) return;
if (el !== doc.activeElement || !doc.hasFocus()) {
el[prop] = value;
}
}
function setHtml(obj, ignore, value, escape) {
if (escape) value = escapeHtml(value);
if (obj.nodeType) {
// Element
if (ignore && obj.id === ignore) return;
obj.innerHTML = value;
} else {
// Range
obj.deleteContents();
obj.insertNode(obj.createContextualFragment(value));
}
}
function setAppend(obj, ignore, value, escape) {
if (escape) value = escapeHtml(value);
if (obj.nodeType) {
// Element
obj.insertAdjacentHTML('beforeend', value);
} else {
// Range
var el = obj.endContainer
, ref = el.childNodes[obj.endOffset];
el.insertBefore(obj.createContextualFragment(value), ref);
}
}
function setInsert(obj, ignore, value, escape, index) {
if (escape) value = escapeHtml(value);
if (obj.nodeType) {
// Element
if (ref = obj.childNodes[index]) {
ref.insertAdjacentHTML('beforebegin', value);
} else {
obj.insertAdjacentHTML('beforeend', value);
}
} else {
// Range
var el = obj.startContainer
, ref = el.childNodes[obj.startOffset + index];
el.insertBefore(obj.createContextualFragment(value), ref);
}
}
function setRemove(el, ignore, index) {
if (!el.nodeType) {
// Range
index += el.startOffset;
el = el.startContainer;
}
var child = el.childNodes[index];
if (child) el.removeChild(child);
}
function setMove(el, ignore, from, to, howMany) {
var child, fragment, nextChild, offset, ref, toEl;
if (!el.nodeType) {
offset = el.startOffset;
from += offset;
to += offset;
el = el.startContainer;
}
child = el.childNodes[from];
// Don't move if the item at the destination is passed as the ignore
// option, since this indicates the intended item was already moved
// Also don't move if the child to move matches the ignore option
if (!child || ignore && (toEl = el.childNodes[to]) &&
toEl.id === ignore || child.id === ignore) return;
ref = el.childNodes[to > from ? to + howMany : to];
if (howMany > 1) {
fragment = document.createDocumentFragment();
while (howMany--) {
nextChild = child.nextSibling;
fragment.appendChild(child);
if (!(child = nextChild)) break;
}
el.insertBefore(fragment, ref);
return;
}
el.insertBefore(child, ref);
}
function forChildren(e, el, next, dom) {
// Prevent infinte emission
if (!next.firstTrigger) return;
// Re-trigger the event on all child elements
var children = el.childNodes;
for (var i = 0, len = children.length, child; i < len; i++) {
child = children[i];
if (child.nodeType !== 1) continue; // Node.ELEMENT_NODE
dom.trigger(e, child, true, true);
forChildren(e, child, next, dom);
}
}
function forName(e, el, next, dom) {
// Prevent infinte emission
if (!next.firstTrigger) return;
var name = el.getAttribute('name');
if (!name) return;
// Re-trigger the event on all other elements with
// the same 'name' attribute
var elements = doc.getElementsByName(name)
, len = elements.length;
if (!(len > 1)) return;
for (var i = 0, element; i < len; i++) {
element = elements[i];
if (element === el) continue;
dom.trigger(e, element, false, true);
}
}
function getRange(name) {
var start = markers[name]
, end = markers['$' + name]
, comment, commentIterator, range;
if (!(start && end)) {
// NodeFilter.SHOW_COMMENT == 128
commentIterator = doc.createTreeWalker(doc.body, 128, null, false);
while (comment = commentIterator.nextNode()) {
markers[comment.data] = comment;
}
start = markers[name];
end = markers['$' + name];
if (!(start && end)) return;
}
// Comment nodes may continue to exist even if they have been removed from
// the page. Thus, make sure they are still somewhere in the page body
if (!doc.body.contains(start)) {
delete markers[name];
delete markers['$' + name];
return;
}
range = doc.createRange();
range.setStartAfter(start);
range.setEndBefore(end);
return range;
}
if (doc.addEventListener) {
addListener = function(el, name, callback, captures) {
el.addEventListener(name, callback, captures || false);
};
removeListener = function(el, name, callback, captures) {
el.removeEventListener(name, callback, captures || false);
};
} else if (doc.attachEvent) {
addListener = function(el, name, callback) {
function listener() {
if (!event.target) event.target = event.srcElement;
callback(event);
}
callback.$derbyListener = listener;
el.attachEvent('on' + name, listener);
};
removeListener = function(el, name, callback) {
el.detachEvent('on' + name, callback.$derbyListener);
};
}

View File

@@ -0,0 +1,43 @@
function empty() {}
module.exports = EventDispatcher;
function EventDispatcher(options) {
if (options == null) options = {};
this._onTrigger = options.onTrigger || empty;
this._onBind = options.onBind || empty;
this.clear();
}
EventDispatcher.prototype = {
clear: function() {
this.names = {};
}
, bind: function(name, listener, arg0) {
this._onBind(name, listener, arg0);
var names = this.names
, obj = names[name] || {};
obj[JSON.stringify(listener)] = listener;
return names[name] = obj;
}
, trigger: function(name, value, arg0, arg1, arg2, arg3, arg4, arg5) {
var names = this.names
, listeners = names[name]
, onTrigger = this._onTrigger
, count = 0
, key, listener;
for (key in listeners) {
listener = listeners[key];
count++;
if (false !== onTrigger(name, listener, value, arg0, arg1, arg2, arg3, arg4, arg5)) {
continue;
}
delete listeners[key];
count--;
}
if (!count) delete names[name];
return count;
}
}

153
first-project/node_modules/derby/lib/PathMap.js generated vendored Normal file
View File

@@ -0,0 +1,153 @@
module.exports = PathMap
function PathMap() {
this.clear();
}
PathMap.prototype = {
clear: function() {
this.count = 0;
this.ids = {};
this.paths = {};
this.arrays = {};
}
, id: function(path) {
var id;
// Return the path for an id, or create a new id and index it
return this.ids[path] || (
id = ++this.count
, this.paths[id] = path
, this._indexArray(path, id)
, this.ids[path] = id
);
}
, _indexArray: function(path, id) {
var arr, index, match, nested, remainder, set, setArrays;
while (match = /^(.+)\.(\d+)(\*?(?:\..+|$))/.exec(path)) {
path = match[1];
index = +match[2];
remainder = match[3];
arr = this.arrays[path] || (this.arrays[path] = []);
set = arr[index] || (arr[index] = {});
if (nested) {
setArrays = set.arrays || (set.arrays = {});
setArrays[remainder] = true;
} else {
set[id] = remainder;
}
nested = true;
}
}
, _incrItems: function(path, map, start, end, byNum, oldArrays, oldPath) {
var arrayMap, arrayPath, arrayPathTo, i, id, ids, itemPath, remainder;
if (oldArrays == null) oldArrays = {};
for (i = start; i < end; i++) {
ids = map[i];
if (!ids) continue;
for (id in ids) {
remainder = ids[id];
if (id === 'arrays') {
for (remainder in ids[id]) {
arrayPath = (oldPath || path) + '.' + i + remainder;
arrayMap = oldArrays[arrayPath] || this.arrays[arrayPath];
if (arrayMap) {
arrayPathTo = path + '.' + (i + byNum) + remainder;
this.arrays[arrayPathTo] = arrayMap;
this._incrItems(arrayPathTo, arrayMap, 0, arrayMap.length, 0, oldArrays, arrayPath);
}
}
continue;
}
itemPath = path + '.' + (i + byNum) + remainder;
this.paths[id] = itemPath;
this.ids[itemPath] = +id;
}
}
}
, _delItems: function(path, map, start, end, len, oldArrays) {
var arrayLen, arrayMap, arrayPath, i, id, ids, itemPath, remainder;
if (oldArrays == null) oldArrays = {};
for (i = start; i < len; i++) {
ids = map[i];
if (!ids) continue;
for (id in ids) {
if (id === 'arrays') {
for (remainder in ids[id]) {
arrayPath = path + '.' + i + remainder;
if (arrayMap = this.arrays[arrayPath]) {
arrayLen = arrayMap.length;
this._delItems(arrayPath, arrayMap, 0, arrayLen, arrayLen, oldArrays);
oldArrays[arrayPath] = arrayMap;
delete this.arrays[arrayPath];
}
}
continue;
}
itemPath = this.paths[id];
delete this.ids[itemPath];
if (i > end) continue;
delete this.paths[id];
}
}
return oldArrays;
}
, onRemove: function(path, start, howMany) {
var map = this.arrays[path]
, end, len, oldArrays;
if (!map) return;
end = start + howMany;
len = map.length;
// Delete indicies for removed items
oldArrays = this._delItems(path, map, start, end + 1, len);
// Decrement indicies of later items
this._incrItems(path, map, end, len, -howMany, oldArrays);
map.splice(start, howMany);
}
, onInsert: function(path, start, howMany) {
var map = this.arrays[path]
, end, len, oldArrays;
if (!map) return;
end = start + howMany;
len = map.length;
// Delete indicies for items in inserted positions
oldArrays = this._delItems(path, map, start, end + 1, len);
// Increment indicies of later items
this._incrItems(path, map, start, len, howMany, oldArrays);
while (howMany--) {
map.splice(start, 0, {});
}
}
, onMove: function(path, from, to, howMany) {
var map = this.arrays[path]
, afterFrom, afterTo, items, oldArrays;
if (!map) return;
afterFrom = from + howMany;
afterTo = to + howMany;
// Adjust paths for items between from and to
if (from > to) {
oldArrays = this._delItems(path, map, to, afterFrom, afterFrom);
this._incrItems(path, map, to, from, howMany, oldArrays);
} else {
oldArrays = this._delItems(path, map, from, afterTo, afterTo);
this._incrItems(path, map, afterFrom, afterTo, -howMany, oldArrays);
}
// Adjust paths for the moved item(s)
this._incrItems(path, map, from, afterFrom, to - from, oldArrays);
// Fix the array index
items = map.splice(from, howMany);
map.splice.apply(map, [to, 0].concat(items));
}
}

1125
first-project/node_modules/derby/lib/View.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

322
first-project/node_modules/derby/lib/View.server.js generated vendored Normal file
View File

@@ -0,0 +1,322 @@
var EventDispatcher = require('./EventDispatcher')
, racer = require('racer')
, Promise = racer.util.Promise
, isProduction = racer.util.isProduction
, merge = racer.util.merge
, finishAfter = racer.util.async.finishAfter
, Model = racer["protected"].Model
, uglify = require('racer/node_modules/uglify-js')
, files = require('./files')
, htmlUtil = require('html-util')
, escapeHtml = htmlUtil.escapeHtml
, trimLeading = htmlUtil.trimLeading
, refresh = require('./refresh.server')
, errorHtml = refresh.errorHtml
, cssError = refresh.cssError
, templateError = refresh.templateError
, View = module.exports = require('./View')
, emptyModel = new Model
, emptyRes = {
getHeader: empty
, setHeader: empty
, write: empty
, end: empty
}
, emptyPathMap = {
id: empty
}
, emptyEventDispatcher = {
bind: empty
}
emptyModel._commit = empty;
emptyModel.bundle = empty;
function empty() {}
function escapeInlineScript(s) {
return s.replace(/<\//g, '<\\/');
}
function loadTemplatesScript(requirePath, templates, instances, libraryData) {
return '(function() {\n' +
'var view = require("' + requirePath + '").view;\n' +
'view._makeAll(\n' +
JSON.stringify(templates, null, 2) + ', ' +
JSON.stringify(instances, null, 2) + ');\n' +
'view._makeComponents(\n' +
JSON.stringify(libraryData, null, 2) + ');\n' +
'})();';
}
View.prototype.isServer = true;
View.prototype.inline = function(fn) {
return this._inline += uglify("(" + fn + ")()") + ';';
};
View.prototype._load = function(isStatic, callback) {
var view = this
, appFilename, clientName, count, errors, finish, js, options
, promise, requirePath, root, libraries, fileInfo, loadTemplates;
if (isProduction) {
this._watch = false;
this._load = function(isStatic, callback) {
callback();
};
} else {
this._watch = true;
}
// Use a promise to avoid simultaneously loading multiple times
if (promise = this._loadPromise) {
return promise.on(callback);
}
promise = this._loadPromise = (new Promise).on(callback);
// Once loading is complete, make the files reload from disk the next time
promise.on(function() {
delete view._loadPromise;
});
errors = {};
if (isStatic) {
root = this._root;
clientName = this._clientName;
count = 2;
finish = function() {
if (--count) return;
promise.resolve();
};
} else {
appFilename = this._appFilename;
options = this._derbyOptions || {};
fileInfo = files.parseName(appFilename, options);
this._root = root = fileInfo.root;
this._requirePath = requirePath = fileInfo.require;
this._clientName = clientName = fileInfo.clientName;
if (!clientName) promise.resolve();
count = 3;
finish = function() {
if (--count) return;
// Templates are appended to the js bundle here so that it does
// not have to be regenerated if only the template files are modified
if (isProduction) loadTemplates = uglify(loadTemplates);
js += ';' + loadTemplates;
view._errors = errorHtml(errors) || '';
files.writeJs(root, js, options, function(err, jsFile, appHash) {
if (err) throw err;
view._jsFile = jsFile;
view._appHash = appHash;
promise.resolve();
});
};
if (this._js) {
js = this._js;
finish();
} else {
files.js(appFilename, function(err, value, inline) {
if (err) throw err;
js = value;
if (!isProduction) view._js = value;
if (inline) view.inline("function(){" + inline + "}");
finish();
});
}
}
this._loadCss(root, clientName, function(err, css) {
if (err) {
css = '<style id=$_css></style>';
errors['CSS'] = cssError(err);
} else {
css = css ? '<style id=$_css>' + css + '</style>' : '';
}
view._css = css;
finish();
});
libraries = this._libraries;
this._loadTemplates(root, clientName, function(err, templates, instances, libraryData) {
if (err) errors['Template'] = templateError(err);
loadTemplates = loadTemplatesScript(requirePath, templates, instances, libraryData);
view._makeAll(templates, instances);
view._makeComponents(libraryData);
finish();
});
};
View.prototype._loadCss = function(root, clientName, callback) {
files.css(root, clientName, isProduction, function(err, value) {
value = isProduction ? trimLeading(value) : '\n' + value;
callback(err, value);
});
};
View.prototype._loadTemplates = function(root, clientName, callback) {
var count = 1
, libraries = this._libraries
, libraryData = {}
, templates, instances, finish, libraryName, library
for (libraryName in libraries) count++;
finish = finishAfter(count, function(err) {
callback(err, templates, instances, libraryData);
});
files.templates(root, clientName, function(err, _templates, _instances) {
if (err) {
templates = {};
instances = {};
} else {
templates = _templates;
instances = _instances;
}
finish(err);
});
for (libraryName in libraries) {
library = libraries[libraryName];
files.library(library.root, function(err, components) {
if (err) return finish(err);
var libraryTemplates = {}
, libraryInstances = {}
, componentName, component;
for (componentName in components) {
component = components[componentName];
// TODO: Namespace component partials of each component
merge(libraryTemplates, component.templates);
merge(libraryInstances, component.instances);
}
libraryData[libraryName] = {
templates: libraryTemplates
, instances: libraryInstances
};
finish();
});
}
};
View.prototype.render = function(res) {
var view = this
, i, arg, ctx, isStatic, model, ns;
if (res == null) res = emptyRes;
for (i = 1; i <= 5; i++) {
arg = arguments[i];
if (arg instanceof Model) {
model = arg;
} else if (typeof arg === 'object') {
ctx = arg;
} else if (typeof arg === 'string') {
ns = arg;
} else if (typeof arg === 'number') {
res.statusCode = arg;
} else if (typeof arg === 'boolean') {
isStatic = arg;
}
}
if (model == null) model = emptyModel;
// Load templates, css, and scripts from files
this._load(isStatic, function() {
view._render(res, model, ns, ctx, isStatic);
});
};
View.prototype._init = function(model) {
// Initialize view & model for rendering
model.__events = emptyEventDispatcher;
model.__blockPaths = {};
model.__pathMap = emptyPathMap;
this.model = model;
this._idCount = 0;
var libraries = this._libraries
, name
for (name in libraries) {
libraries[name].view._init(model);
}
};
View.prototype._render = function(res, model, ns, ctx, isStatic) {
this._init(model);
if (!res.getHeader('content-type')) {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
}
try {
// The view.get function renders and sets event listeners
var doctype = this.get('doctype', ns, ctx)
, root = this.get('root', ns, ctx)
, charset = this.get('charset', ns, ctx)
, title = escapeHtml(this.get('title$s', ns, ctx))
, head = this.get('head', ns, ctx)
, header = this.get('header', ns, ctx)
, view = this
, body, scripts, tail;
// The first chunk includes everything through header. Head should contain
// any meta tags and script tags, since it is included before CSS.
// If there is a small amount of header HTML that will display well by itself,
// it is a good idea to add this to the Header view so that it renders ASAP.
res.write(doctype + root + charset + "<title>" + title + "</title>" + head + this._css + header);
// Remaining HTML
body = this.get('body', ns, ctx) + this.get('footer', ns, ctx);
if (body.slice(0, 4) === '<!--') {
body = '&shy;' + body;
}
res.write(body);
} catch (err) {
var errText = templateError(err);
if (!this._errors) this._errors = errorHtml({Template: errText});
res.write('<!DOCTYPE html><meta charset=utf-8><title></title>' + this._css);
}
tail = this.get('tail', ns, ctx);
// Wait for transactions to finish and package up the racer model data
// TODO: There is a potential race condition with rendering based on the
// model before it is bundled. However, components may want to run init
// code that performs model mutations, so we can't bundle until after that.
// Figure out some solution to make sure that the client will have exactly
// the same model data when rendering to set up browser events, etc.
model.bundle(function(bundle) {
view._renderScripts(res, ns, ctx, isStatic, tail, bundle);
});
};
View.prototype._renderScripts = function(res, ns, ctx, isStatic, tail, bundle) {
var clientName = this._clientName;
// Inline scripts and external scripts
scripts = "<script>";
if (!isStatic) {
scripts += "function " + clientName + "(){" + clientName + "=1}";
}
scripts += escapeInlineScript(this._inline) + "</script>" + this.get('scripts', ns, ctx);
if (!isStatic) {
scripts += "<script defer async onload=" + clientName + "() src=" + this._jsFile + "></script>";
}
res.write(scripts);
// Initialization script and Tail
if (isStatic) return res.end(tail);
res.end("<script>(function(){function f(){setTimeout(function(){" + clientName +
"=require('" + this._requirePath + "')(" + escapeInlineScript(bundle) + ",'" +
this._appHash + "'," + (+this._watch) + ",'" + (ns || '') + "'" +
(ctx ? ',' + escapeInlineScript(JSON.stringify(ctx)) : '') + ")},0)}" +
clientName + "===1?f():" + clientName + "=f})()</script>" + tail + this._errors);
};

277
first-project/node_modules/derby/lib/derby.Model.js generated vendored Normal file
View File

@@ -0,0 +1,277 @@
var EventDispatcher = require('./EventDispatcher')
, PathMap = require('./PathMap')
, Model = require('racer')["protected"].Model
, arraySlice = [].slice;
exports.init = init;
// Add support for creating a model alias from a DOM node or jQuery object
Model.prototype.__at = Model.prototype.at;
Model.prototype.at = function(node, absolute) {
var isNode = node && (node.parentNode || node.jquery && (node = node[0]));
if (!isNode) return this.__at(node, absolute);
updateMarkers();
var blockPaths = this.__blockPaths
, pathMap = this.__pathMap
, child, i, id, isArray, last, path, pathId, children, len;
while (node) {
if (node.$derbyMarkerParent) {
node = last;
while (node = node.previousSibling) {
if (!(id = node.$derbyMarkerId)) continue;
pathId = blockPaths[id];
if (node.$derbyMarkerEnd || !pathId) break;
path = pathMap.paths[pathId];
if (pathMap.arrays[path] && last) {
i = 0;
while (node = node.nextSibling) {
if (node === last) {
path = path + '.' + i;
break;
}
i++;
}
}
return this.__at(path, absolute);
}
last = last.parentNode;
node = last.parentNode;
continue;
}
if ((id = node.id) && (pathId = blockPaths[id])) {
path = pathMap.paths[pathId];
isArray = pathMap.arrays[path] || Array.isArray(this.get(path));
if (isArray && last) {
children = node.childNodes;
for (i = 0, len = children.length; i < len; i++) {
child = children[i];
if (child === last) {
path = path + '.' + i;
break;
}
}
}
return this.__at(path, absolute);
}
last = node;
node = node.parentNode;
}
// Just return the model if a path can't be found
return this;
}
function updateMarkers() {
// NodeFilter.SHOW_COMMENT == 128
var commentIterator = document.createTreeWalker(document.body, 128, null, false)
, comment, id;
while (comment = commentIterator.nextNode()) {
if (comment.$derbyChecked) continue;
comment.$derbyChecked = true;
id = comment.data;
if (id.charAt(0) !== '$') continue;
if (id.charAt(1) === '$') {
comment.$derbyMarkerEnd = true;
id = id.slice(1);
}
comment.$derbyMarkerId = id;
comment.parentNode.$derbyMarkerParent = true;
}
}
function init(model, dom, view) {
var pathMap = model.__pathMap = new PathMap;
var events = model.__events = new EventDispatcher({
onTrigger: function(pathId, listener, type, local, options, value, index, arg) {
var id = listener[0]
, el = dom.item(id);
// Fail and remove the listener if the element can't be found
if (!el) return false;
var method = listener[1]
, property = listener[2]
, partial = listener.partial
, path = pathMap.paths[pathId]
, triggerId;
if (method === 'propPolite' && local) method = 'prop';
if (partial) {
triggerId = id;
if (method === 'html' && type) {
// Handle array updates
method = type;
if (type === 'append') {
path += '.' + (index = model.get(path).length - 1);
triggerId = null;
} else if (type === 'insert') {
path += '.' + index;
triggerId = null;
} else if (type === 'remove') {
partial = null;
} else if (type === 'move') {
partial = null;
property = arg;
}
}
}
if (listener.getValue) {
value = listener.getValue(model, path);
}
if (partial) {
value = partial(listener.ctx, model, path, triggerId, value, index, listener);
if (value == null) return;
}
dom.update(el, method, options && options.ignore, value, property, index);
}
});
// Derby's mutator listeners are added via unshift instead of model.on, because
// it needs to handle events in the same order that racer applies mutations.
// If there is a listener to an event that applies a mutation, event listeners
// later in the listeners queues could receive events in a different order
model.listeners('set').unshift(function(args, out, local, pass) {
var arrayPath, i, index, path, value;
model.emit('pre:set', args, out, local, pass);
path = args[0], value = args[1];
// For set operations on array items, also emit a remove and insert in case the
// array is bound
if (/\.\d+$/.test(path)) {
i = path.lastIndexOf('.');
arrayPath = path.slice(0, i);
index = path.slice(i + 1);
triggerEach(events, pathMap, arrayPath, 'remove', local, pass, index);
triggerEach(events, pathMap, arrayPath, 'insert', local, pass, value, index);
}
return triggerEach(events, pathMap, path, 'html', local, pass, value);
});
model.listeners('del').unshift(function(args, out, local, pass) {
model.emit('pre:del', args, out, local, pass);
var path = args[0];
return triggerEach(events, pathMap, path, 'html', local, pass);
});
model.listeners('push').unshift(function(args, out, local, pass) {
model.emit('pre:push', args, out, local, pass);
var path = args[0]
, values = arraySlice.call(args, 1);
for (var i = 0, len = values.length, value; i < len; i++) {
value = values[i];
triggerEach(events, pathMap, path, 'append', local, pass, value);
}
});
model.listeners('move').unshift(function(args, out, local, pass) {
model.emit('pre:move', args, out, local, pass);
var path = args[0]
, from = args[1]
, to = args[2]
, howMany = args[3]
, len = model.get(path).length;
from = refIndex(from);
to = refIndex(to);
if (from < 0) from += len;
if (to < 0) to += len;
if (from === to) return;
// Update indicies in pathMap
pathMap.onMove(path, from, to, howMany);
triggerEach(events, pathMap, path, 'move', local, pass, from, howMany, to);
});
model.listeners('unshift').unshift(function(args, out, local, pass) {
model.emit('pre:unshift', args, out, local, pass);
var path = args[0]
, values = arraySlice.call(args, 1);
insert(events, pathMap, path, 0, values, local, pass);
});
model.listeners('insert').unshift(function(args, out, local, pass) {
model.emit('pre:insert', args, out, local, pass);
var path = args[0]
, index = args[1]
, values = arraySlice.call(args, 2);
insert(events, pathMap, path, index, values, local, pass);
});
model.listeners('remove').unshift(function(args, out, local, pass) {
model.emit('pre:remove', args, out, local, pass);
var path = args[0]
, start = args[1]
, howMany = args[2];
remove(events, pathMap, path, start, howMany, local, pass);
});
model.listeners('pop').unshift(function(args, out, local, pass) {
model.emit('pre:pop', args, out, local, pass);
var path = args[0];
remove(events, pathMap, path, model.get(path).length, 1, local, pass);
});
model.listeners('shift').unshift(function(args, out, local, pass) {
model.emit('pre:shift', args, out, local, pass);
var path = args[0];
remove(events, pathMap, path, 0, 1, local, pass);
});
['connected', 'canConnect'].forEach(function(event) {
model.listeners(event).unshift(function(value) {
triggerEach(events, pathMap, event, null, true, null, value);
});
});
model.on('reInit', function() {
view.history.refresh();
});
return model;
}
function triggerEach(events, pathMap, path, arg0, arg1, arg2, arg3, arg4, arg5) {
var id = pathMap.ids[path]
, segments = path.split('.')
, i, pattern;
// Trigger an event on the path if it has a pathMap ID
if (id) events.trigger(id, arg0, arg1, arg2, arg3, arg4, arg5);
// Also trigger a pattern event for the path and each of its parent paths
// This is used by view helper functions to match updates on a path
// or any of its child segments
i = segments.length + 1;
while (--i) {
pattern = segments.slice(0, i).join('.') + '*';
if (id = pathMap.ids[pattern]) {
events.trigger(id, arg0, arg1, arg2, arg3, arg4, arg5);
}
}
}
// Get index if event was from refList id object
function refIndex(obj) {
return typeof obj === 'object' ? obj.index : +obj;
}
function insert(events, pathMap, path, start, values, local, pass) {
start = refIndex(start);
// Update indicies in pathMap
pathMap.onInsert(path, start, values.length);
for (var i = 0, len = values.length, value; i < len; i++) {
value = values[i];
triggerEach(events, pathMap, path, 'insert', local, pass, value, start + i);
}
}
function remove(events, pathMap, path, start, howMany, local, pass) {
start = refIndex(start);
var end = start + howMany;
// Update indicies in pathMap
pathMap.onRemove(path, start, howMany);
for (var i = start; i < end; i++) {
triggerEach(events, pathMap, path, 'remove', local, pass, start);
}
}

78
first-project/node_modules/derby/lib/derby.browser.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
var racer = require('racer')
, tracks = require('tracks')
, derbyModel = require('./derby.Model')
, Dom = require('./Dom')
, View = require('./View')
, autoRefresh = require('./refresh').autoRefresh;
module.exports = derbyBrowser;
function derbyBrowser(derby) {
derby.createApp = createApp;
}
derbyBrowser.decorate = 'derby';
derbyBrowser.useWith = {server: false, browser: true};
function createApp(appModule) {
var appExports = appModule.exports
, view, model;
appModule.exports = function(modelBundle, appHash, debug, ns, ctx) {
tracks.set('debug', debug);
// The init event is fired after the model data is initialized but
// before the socket object is set
racer.on('init', function(_model) {
model = view.model = _model;
var dom = view.dom = new Dom(model);
derbyModel.init(model, dom, view);
// Ignore errors thrown when rendering; these will also be thrown
// on the server, and throwing here causes the app not to connect
try {
// Render immediately upon initialization so that the page is in
// the same state it was when rendered on the server
view.render(model, ns, ctx, true);
} catch (err) {
console.error(err);
}
});
// The ready event is fired after the model data is initialized and
// the socket object is set
if (debug) {
racer.on('ready', function(model) {
autoRefresh(view, model, appHash);
});
}
racer.init(modelBundle);
return appExports;
};
// Expose methods on the application module. Note that view must added
// to both appModule.exports and appExports, since it is used before
// the initialization function to make templates
appModule.exports.view = appExports.view = view =
new View(this._libraries, appExports);
function createPage() {
return {
render: function(ns, ctx) {
view.render(model, ns, ctx);
}
};
}
function onRoute(callback, page, params, next, isTransitional) {
if (isTransitional) {
callback(model, params, next);
} else {
callback(page, model, params, next);
}
}
tracks.setup(appExports, createPage, onRoute);
view.history = appExports.history;
appExports.ready = function(fn) {
racer.on('ready', fn);
};
return appExports;
}

34
first-project/node_modules/derby/lib/derby.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
var path = require('path')
, racer = require('racer')
, View = require('./View')
, derby = module.exports = Object.create(racer)
, derbyPlugin = racer.util.isServer ?
__dirname + '/derby.server' : require('./derby.browser');
// Allow derby object to be targeted via plugin.decorate
racer._makePlugable('derby', derby);
// Shared methods for both server and browser
derby._libraries = {};
derby.createLibrary = createLibrary;
// Add appropriate server-side or browser-side methods
derby.use(derbyPlugin);
function createLibrary(filename, scripts, options) {
if (!options) options = {};
var root = path.dirname(filename)
, name = options.name || path.basename(root)
, view = new View;
// This is needed, since component names are all lowercased
for (scriptName in scripts) {
scripts[scriptName.toLowerCase()] = scripts[scriptName];
}
this._libraries[name] = {
root: root
, view: view
, scripts: scripts
};
}

166
first-project/node_modules/derby/lib/derby.server.js generated vendored Normal file
View File

@@ -0,0 +1,166 @@
var fs = require('fs')
, path = require('path')
, http = require('http')
, racer = require('racer')
, tracks = require('tracks')
, up = require('up')
, View = require('./View.server')
, autoRefresh = require('./refresh.server').autoRefresh
, util = racer.util
, merge = util.merge
, isProduction = util.isProduction
, proto;
module.exports = derbyServer;
function derbyServer(derby) {
merge(derby, proto);
Object.defineProperty(derby, 'version', {
get: function() {
return require('../package.json').version;
}
});
}
derbyServer.decorate = 'derby';
derbyServer.useWith = {server: true, browser: false};
proto = {
// TODO: Remove in lieu of get / set methods
options: {}
, run: function(file, port, options) {
var master, onMessage, server, upService;
// Resolve relative filenames
file = path.resolve(file);
if (port == null) port = isProduction ? 80 : 3000;
if (options == null) options = {numWorkers: 1};
try {
server = require(file);
} catch (e) {
console.error('Error requiring server module from `%s`', file);
throw e;
}
if (!(server instanceof http.Server)) {
throw new Error('`' + file + '` does not export a valid `http.Server`');
}
if (!isProduction) {
// TODO: This extends the internal API of Up. It would be better
// if Up supported workers being able to force a global reload
onMessage = up.Worker.prototype.onMessage;
up.Worker.prototype.onMessage = function(message) {
if (message.type === 'reload') {
return upService.reload();
}
onMessage.call(this, message);
};
}
master = http.createServer().listen(port);
upService = up(master, file, options);
process.on('SIGUSR2', function() {
console.log('SIGUSR2 signal detected - reloading');
upService.reload();
});
console.log('Starting cluster with %d workers in %s mode',
options.numWorkers, process.env.NODE_ENV);
console.log('`kill -s SIGUSR2 %s` to force cluster reload', process.pid);
console.log('Go to: http://localhost:%d/', port);
}
, createApp: function(appModule) {
var appExports = appModule.exports
, view = new View(this._libraries)
, options = this.options
, session, store;
view._derbyOptions = options;
view._appFilename = appModule.filename;
function setStore(_store) {
autoRefresh(_store, options, view);
if (session != null) session._setStore(_store);
return store = _store;
}
// Expose methods on the application module
function Page(model, res) {
this._model = model;
this._res = res;
}
Page.prototype.render = function(ns, ctx, status) {
view.render(this._res, this._model, ns, ctx, status);
};
function createPage(req, res) {
var model = req.model || store.createModel();
return new Page(model, res);
}
function onRoute(callback, page, params, next, isTransitional) {
if (isTransitional) {
callback(page._model, params, next);
} else {
callback(page, page._model, params, next);
}
}
tracks.setup(appExports, createPage, onRoute);
appExports._setStore = setStore;
appExports.view = view;
appExports.ready = function() {};
appExports.createStore = function(options) {
return setStore(racer.createStore(options));
};
appExports.session = function() {
return session = racer.session(store);
};
appExports.render = function(res, model, ns, ctx, status) {
return view.render(res, model, ns, ctx, status);
};
// Render immediately upon creating the app so that files
// will be cached for the first render
process.nextTick(function() {
view.render();
});
return appExports;
}
, createStatic: function(root) {
return new Static(root, this._libraries);
}
, createStore: function() {
var len = arguments.length
, last = arguments[len - 1]
, options, app, store;
// Last argument may be a createStore options object
if (!last.view) {
options = last;
len--;
}
store = racer.createStore(options);
for (var i = len; i--;) {
app = arguments[i];
app._setStore(store);
}
return store;
}
};
function Static(root, libraries) {
this.root = root;
this.libraries = libraries;
this.views = {};
}
Static.prototype.render = function(name, res, model, ns, ctx, status) {
var view = this.views[name];
if (!view) {
view = this.views[name] = new View(this.libraries);
view._root = this.root;
view._clientName = name;
}
view.render(res, model, ns, ctx, status, true);
};

109
first-project/node_modules/derby/lib/eventBinding.js generated vendored Normal file
View File

@@ -0,0 +1,109 @@
var util = require('racer').util
, lookup = require('racer/lib/path').lookup
, merge = util.merge
, viewPath = require('./viewPath')
, ctxPath = viewPath.ctxPath
, pathFnArgs = viewPath.pathFnArgs
, setBoundFn = viewPath.setBoundFn;
exports.splitEvents = splitEvents;
exports.containsEvent = containsEvent;
exports.addDomEvent = util.isServer ? empty : addDomEvent;
function splitEvents(eventNames) {
var pairs = eventNames.replace(/\s/g, '').split(',')
, eventList = []
, pair, segments, name, eventName, delay, fn;
for (var i = pairs.length; i--;) {
pair = pairs[i];
segments = pair.split(':');
name = segments[0].split('/');
eventName = name[0];
delay = name[1];
fn = segments[1] || '';
eventList.push([eventName, delay, fn]);
}
return eventList;
}
function containsEvent(eventNames, expected) {
var eventList = splitEvents(eventNames)
, eventName;
for (var i = eventList.length; i--;) {
eventName = eventList[i][0];
if (eventName === expected) return true;
}
return false;
}
function addDomEvent(events, attrs, eventNames, name, options) {
var eventList = splitEvents(eventNames)
, args;
if (name) {
if (~name.indexOf('(')) {
args = pathFnArgs(name);
if (!args.length) return;
events.push(function(ctx, modelEvents, dom, pathMap, view) {
var id = attrs._id || attrs.id
, paths = []
, arg, path, pathId, event, eventName, eventOptions, i, j;
options.setValue = function(model, value) {
return setBoundFn(view, ctx, model, name, value);
}
for (i = args.length; i--;) {
arg = args[i];
path = ctxPath(ctx, arg);
paths.push(path);
pathId = pathMap.id(path);
for (j = eventList.length; j--;) {
event = eventList[j];
eventName = event[0];
eventOptions = merge({pathId: pathId, delay: event[1]}, options);
dom.bind(eventName, id, eventOptions);
}
}
});
return;
}
events.push(function(ctx, modelEvents, dom, pathMap) {
var id = attrs._id || attrs.id
, pathId = pathMap.id(ctxPath(ctx, name))
, event, eventName, eventOptions, i;
for (i = eventList.length; i--;) {
event = eventList[i];
eventName = event[0];
eventOptions = merge({pathId: pathId, delay: event[1]}, options);
dom.bind(eventName, id, eventOptions);
}
});
return;
}
events.push(function(ctx, modelEvents, dom, pathMap, view) {
var id = attrs._id || attrs.id
, fnCtx = ctx.$fnCtx || view._appExports
, event, eventName, eventOptions, i, fnName;
for (i = eventList.length; i--;) {
event = eventList[i];
eventName = event[0];
eventOptions = fnListener(dom, fnCtx, event[1], event[2]);
merge(eventOptions, options);
dom.bind(eventName, id, eventOptions);
}
});
}
function fnListener(dom, fnCtx, delay, fnName) {
var listener = {
delay: delay
, fn: function() {
listener.fn = dom.fns[fnName] || fnCtx[fnName] || lookup(fnName, fnCtx);
listener.fn.apply(null, arguments);
}
};
return listener;
}
function empty() {}

460
first-project/node_modules/derby/lib/files.js generated vendored Normal file
View File

@@ -0,0 +1,460 @@
var pathUtil = require('path')
, dirname = pathUtil.dirname
, basename = pathUtil.basename
, join = pathUtil.join
, exists = pathUtil.exists
, relative = pathUtil.relative
, fs = require('fs')
, crypto = require('crypto')
, stylus = require('stylus')
, nib = require('nib')
, less = require('less')
, racer = require('racer')
, Promise = racer.util.Promise
, finishAfter = racer.util.async.finishAfter
, asyncForEach = racer.util.async.forEach
, htmlUtil = require('html-util')
, parseHtml = htmlUtil.parse
, minifyHtml = htmlUtil.minify
, styleCompilers = {
stylus: stylusCompiler
, less: lessCompiler
}
, onlyWhitespace = /^[\s\n]*$/;
exports.css = css;
exports.templates = templates;
exports.js = js;
exports.library = library;
exports.parseName = parseName;
exports.hashFile = hashFile;
exports.writeJs = writeJs;
exports.watch = watch;
function css(root, clientName, compress, callback) {
// TODO: Set default configuration options in a single place
var styles = require('./derby').settings.styles || ['less', 'stylus']
, compiled = []
, finish;
if (!Array.isArray(styles)) styles = [styles];
finish = finishAfter(styles.length, function(err) {
callback(err, compiled.join(''));
});
styles.forEach(function(style, i) {
var compiler = styleCompilers[style];
if (!compiler) finish(new Error('Unable to find compiler for: ' + style));
compiler(root, clientName, compress, function(err, value) {
compiled[i] = value || '';
finish(err);
});
});
}
function stylusCompiler(root, clientName, compress, callback) {
findPath(root + '/styles', clientName, '.styl', function(path) {
if (!path) return callback('');
fs.readFile(path, 'utf8', function(err, styl) {
if (err) return callback(err);
stylus(styl)
.use(nib())
.set('filename', path)
.set('compress', compress)
.render(callback);
});
});
}
function lessCompiler(root, clientName, compress, callback) {
findPath(root + '/styles', clientName, '.less', function(path) {
if (!path) return callback('');
fs.readFile(path, 'utf8', function(err, lessFile) {
if (err) return callback(err);
var parser = new less.Parser({
paths: [root + '/styles']
, filename: path
});
parser.parse(lessFile, function(err, tree) {
var compiled;
if (err) return callback(err);
try {
compiled = tree.toCSS({compress: compress});
} catch (err) {
return callback(err);
}
callback(null, compiled);
});
});
});
}
function templates(root, clientName, callback) {
loadTemplates(root + '/views', clientName, callback);
}
function js(parentFilename, options, callback) {
var finish, inline, inlineFile, js;
// Needed for tests
if (!parentFilename) return;
if (typeof options === 'function') {
callback = options;
options = {};
}
// TODO: Move this to config:
// Express will try to include mime, which won't work in the browser
// It doesn't actually need this for routing, so we just ignore it
if (options.ignore) {
options.ignore.push('mime');
} else {
options.ignore = ['mime'];
}
if (options.require) {
options.require.push(parentFilename);
} else {
options.require = [parentFilename];
}
inlineFile = join(dirname(parentFilename), 'inline.js');
finish = finishAfter(2, function(err) {
callback(err, js, inline);
});
racer.js(options, function(err, value) {
js = value;
finish(err);
});
fs.readFile(inlineFile, 'utf8', function(err, value) {
inline = value;
// Ignore file not found error
if (err && err.code === 'ENOENT') err = null;
finish(err);
});
}
function library(root, callback) {
var components = {};
fs.readdir(root, function(err, files) {
if (err) return callback(err);
asyncForEach(files, libraryFile, function(err) {
if (err) return callback(err);
callback(null, components);
});
});
function libraryFile(file, callback) {
var path = root + '/' + file
fs.stat(path, function(err, stats) {
if (err) return callback(err);
if (stats.isDirectory()) {
return addComponent(root, file, callback);
}
if (extensions['html'].test(file)) {
file = file.replace(extensions['html'], '');
return addComponent(root, file, callback);
}
callback();
});
}
function addComponent(root, name, callback) {
loadTemplates(root, name, function(err, templates, instances) {
components[name] = {
templates: templates
, instances: instances
};
callback(err);
});
}
}
function parseName(parentFilename, options) {
var parentDir = dirname(parentFilename)
, root = parentDir
, base = basename(parentFilename, '.js');
if (base === 'index') {
base = basename(parentDir);
root = dirname(dirname(parentDir));
} else if (basename(parentDir) === 'lib') {
root = dirname(parentDir);
}
return {
root: root
, clientName: options.name || base
, require: './' + basename(parentFilename)
};
}
function hashFile(file) {
var hash = crypto.createHash('md5').update(file).digest('base64');
// Base64 uses characters reserved in URLs and adds extra padding charcters.
// Replace "/" and "+" with the unreserved "-" and "_" and remove "=" padding
return hash.replace(/[\/\+=]/g, function(match) {
switch (match) {
case '/': return '-';
case '+': return '_';
case '=': return '';
}
});
}
function writeJs(root, js, options, callback) {
var staticRoot = options.staticRoot || join(root, 'public')
, staticDir = options.staticDir || 'gen'
, staticPath = join(staticRoot, staticDir)
, hash = hashFile(js)
, filename = hash + '.js'
, jsFile = join('/', staticDir, filename)
, filePath = join(staticPath, filename);
function finish() {
fs.writeFile(filePath, js, function(err) {
callback(err, jsFile, hash);
});
}
exists(staticPath, function(value) {
if (value) return finish();
exists(staticRoot, function(value) {
if (value) {
fs.mkdir(staticPath, '0777', function(err) {
finish();
})
return;
}
fs.mkdir(staticRoot, '0777', function(err) {
fs.mkdir(staticPath, '0777', function(err) {
finish();
});
});
});
});
}
function watch(dir, type, onChange) {
var extension = extensions[type]
, watchFn = fs.watch ? systemWatch : pollWatch;
files(dir, extension).forEach(watchFn);
function systemWatch(file) {
fs.watch(file, function() {
onChange(file);
});
}
function pollWatch(file) {
fs.watchFile(file, {interval: 100}, function(curr, prev) {
if (prev.mtime < curr.mtime) {
onChange(file);
}
});
}
}
function findPath(root, name, extension, callback) {
if (name.charAt(0) !== '/') {
name = join(root, name);
}
var path = name + extension;
exists(path, function(value) {
if (value) return callback(path);
path = join(name, 'index' + extension);
exists(path, function(value) {
callback(value ? path : null);
});
});
}
function loadTemplates(root, fileName, callback) {
var count = 0
, calls = {incr: incr, finish: finish};
function incr() {
count++;
}
function finish(err, templates, instances) {
if (err) {
calls.finish = function() {};
return callback(err);
}
--count || callback(null, templates, instances);
}
forTemplate(root, fileName, 'import', calls);
}
function forTemplate(root, fileName, get, calls, files, templates, instances, alias, currentNs) {
if (currentNs == null) currentNs = '';
calls.incr();
findPath(root, fileName, '.html', function(path) {
var getCount, got, matchesGet, promise;
if (path === null) {
if (!files) {
// Return without doing anything if the path isn't found, and this is the
// initial automatic lookup based on the clientName
return calls.finish(null, {}, {});
} else {
return calls.finish(new Error("Can't find file " + fileName));
}
}
files || (files = {});
templates || (templates = {});
instances || (instances = {});
got = false;
if (get === 'import') {
matchesGet = function() {
return got = true;
}
} else if (Array.isArray(get)) {
getCount = get.length;
matchesGet = function(name) {
--getCount || (got = true);
return ~get.indexOf(name);
}
} else {
matchesGet = function(name) {
got = true;
return get === name;
}
}
promise = files[path];
if (!promise) {
promise = files[path] = new Promise;
fs.readFile(path, 'utf8', function(err, file) {
promise.resolve(err, file);
});
}
promise.on(function(err, file) {
if (err) calls.finish(err);
parseTemplateFile(root, dirname(path), path, calls, files, templates, instances, alias, currentNs, matchesGet, file);
if (!got) {
calls.finish(new Error("Can't find template '" + get + "' in " + path));
}
calls.finish(null, templates, instances);
});
});
}
function parseTemplateFile(root, dir, path, calls, files, templates, instances, alias, currentNs, matchesGet, file) {
var relativePath = relative(root, path)
, as, importTemplates, name, ns, src, templateOptions;
parseHtml(file, {
// Force template tags to be treated as raw tags,
// meaning their contents are not parsed as HTML
rawTags: /^(?:[^\s=\/>]+:|style|script)$/i
, matchEnd: matchEnd
, start: start
, text: text
});
function matchEnd(tagName) {
if (tagName.slice(-1) === ':') {
return /<\/?[^\s=\/>]+:[\s>]/;
}
return new RegExp('</' + tagName, 'i');
}
function start(tag, tagName, attrs) {
var i = tagName.length - 1
, srcNs, template;
as, importTemplates, ns, src = null;
name = (tagName.charAt(i) === ':' ? tagName.slice(0, i) : '').toLowerCase();
if (name === 'import') {
src = attrs.src, ns = attrs.ns, as = attrs.as, template = attrs.template;
if (!src) {
calls.finish(new Error("Template import in " + path +
" must have a 'src' attribute"));
}
if (template) {
importTemplates = template.toLowerCase().split(' ');
if (importTemplates.length > 1 && (as != null)) {
calls.finish(new Error("Template import of '" + src + "' in " +
path + " can't specify multiple 'template' values with 'as'"));
}
}
if ('ns' in attrs) {
if (as) calls.finish(new Error("Template import of '" + src +
"' in " + path + " can't specifiy both 'ns' and 'as' attributes"));
// Import into the namespace specified via 'ns' underneath
// the current namespace
ns = ns
? currentNs ? currentNs + ':' + ns : ns
: currentNs;
} else if (as) {
// If 'as' is specified, import into the current namespace
ns = currentNs;
} else {
// If no namespace is specified, use the src as a namespace.
// Remove leading '.' and '/' characters
srcNs = src.replace(/^[.\/]*/, '');
ns = currentNs ? currentNs + ':' + srcNs : srcNs;
}
ns = ns.toLowerCase();
} else {
templateOptions = attrs;
}
}
function text(text, isRawText) {
var instanceName, templateName, toGet;
if (!matchesGet(name)) return;
if (src) {
if (!onlyWhitespace.test(text)) {
calls.finish(new Error("Template import of '" + src + "' in " +
path + " can't contain content: " + text));
}
toGet = importTemplates || 'import';
return forTemplate(root, join(dir, src), toGet, calls, files, templates, instances, as, ns);
}
templateName = relativePath + ':' + name;
instanceName = alias || name;
if (currentNs) {
instanceName = currentNs + ':' + instanceName;
}
instances[instanceName] = [templateName, templateOptions];
if (templates[templateName]) return;
if (!(name && isRawText)) {
if (onlyWhitespace.test(text)) return;
calls.finish(new Error("Can't read template in " + path +
" near the text: " + text));
}
templates[templateName] = minifyHtml(text);
}
}
// TODO: These should be set as configuration options
var extensions = {
html: /\.html$/i
, css: /\.styl$|\.css|\.less$/i
, js: /\.js$/i
};
var ignoreDirectories = ['node_modules', '.git', 'gen'];
function ignored(path) {
return ignoreDirectories.indexOf(path) === -1;
}
function files(dir, extension, out) {
if (out == null) out = [];
fs.readdirSync(dir).filter(ignored).forEach(function(p) {
p = join(dir, p);
if (fs.statSync(p).isDirectory()) {
files(p, extension, out);
} else if (extension.test(p)) {
out.push(p);
}
});
return out;
}

173
first-project/node_modules/derby/lib/markup.js generated vendored Normal file
View File

@@ -0,0 +1,173 @@
var eventBinding = require('./eventBinding')
, splitEvents = eventBinding.splitEvents
, containsEvent = eventBinding.containsEvent
, addDomEvent = eventBinding.addDomEvent
, TEXT_EVENTS = 'keyup,keydown,paste/0,dragover/0,blur'
, AUTOCOMPLETE_OFF = {
checkbox: true
, radio: true
}
, onBindA, onBindForm;
module.exports = {
bound: {
'value': {
'input': function(events, attrs, name) {
var type = attrs.type
, eventNames, method;
if (type === 'radio' || type === 'checkbox') return;
if (type === 'range' || 'x-blur' in attrs) {
// Only update after the element loses focus
delete attrs['x-blur'];
eventNames = 'change,blur';
} else {
// By default, update as the user types
eventNames = TEXT_EVENTS;
}
if ('x-ignore-focus' in attrs) {
// Update value regardless of focus
delete attrs['x-ignore-focus'];
method = 'prop';
} else {
// Update value unless window and element are focused
method = 'propPolite';
}
addDomEvent(events, attrs, eventNames, name, {
method: 'prop'
, property: 'value'
});
return {method: method};
}
}
, 'checked': {
'*': function(events,  attrs, name) {
addDomEvent(events, attrs, 'change', name, {
method: 'prop'
, property: 'checked'
});
return {method: 'prop'};
}
}
, 'selected': {
'*': function(events, attrs, name) {
addDomEvent(events, attrs, 'change', name, {
method: 'prop'
, property: 'selected'
});
return {method: 'prop'};
}
}
, 'disabled': {
'*': function() {
return {method: 'prop'};
}
}
}
, boundParent: {
'contenteditable': {
'*': function(events, attrs, name) {
addDomEvent(events, attrs, TEXT_EVENTS, name, {
method: 'html'
});
}
}
, '*': {
'textarea': function(events, attrs, name) {
addDomEvent(events, attrs, TEXT_EVENTS, name, {
method: 'prop'
, property: 'value'
});
return {method: 'prop', property: 'value'};
}
}
}
, element: {
'select': function(events, attrs) {
// Distribute change event to child nodes of select elements
addDomEvent(events, attrs, 'change:$forChildren');
return {addId: true};
}
, 'input': function(events, attrs) {
if (AUTOCOMPLETE_OFF[attrs.type] && !('autocomplete' in attrs)) {
attrs.autocomplete = 'off';
}
if (attrs.type === 'radio') {
// Distribute change events to other elements with the same name
addDomEvent(events, attrs, 'change:$forName');
}
}
}
, attr: {
'x-bind': {
'*': function(events, attrs, eventNames) {
addDomEvent(events, attrs, eventNames);
return {addId: true, del: true};
}
, 'a': onBindA = function(events, attrs, eventNames) {
if (containsEvent(eventNames, 'click') && !('href' in attrs)) {
attrs.href = '#';
if (!('onclick' in attrs)) {
attrs.onclick = 'return false';
}
}
}
, 'form': onBindForm = function(events, attrs, eventNames) {
if (containsEvent(eventNames, 'submit')) {
if (!('onsubmit' in attrs)) {
attrs.onsubmit = 'return false';
}
}
}
}
, 'x-capture': {
'*': function(events, attrs, eventNames) {
addDomEvent(events, attrs, eventNames, null, {capture: true});
return {addId: true, del: true};
}
, 'a': onBindA
, 'form': onBindForm
}
, 'x-as': {
'*': function(events, attrs, name) {
events.push(function(ctx) {
var elements = ctx.$elements || (ctx.$elements = {});
elements[name] = attrs._id || attrs.id;
});
return {addId: true, del: true}
}
}
, 'checked': {
'*': function() {
return {bool: true};
}
}
, 'selected': {
'*': function() {
return {bool: true};
}
}
, 'disabled': {
'*': function() {
return {bool: true};
}
}
}
, TEXT_EVENTS: TEXT_EVENTS
, AUTOCOMPLETE_OFF: AUTOCOMPLETE_OFF
};

70
first-project/node_modules/derby/lib/refresh.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
exports.errorHtml = errorHtml;
exports.autoRefresh = autoRefresh;
var errors = {};
function errorHtml(errors) {
var text = ''
, type, err;
for (type in errors) {
err = errors[type];
text += '<h3>' + type + ' Error</h3><pre>' + err + '</pre>';
}
if (!text) return;
return '<div id=$_derbyError style="position:absolute;background:rgba(0,0,0,.7);top:0;left:0;right:0;bottom:0;text-align:center">' +
'<div style="background:#fff;padding:20px 40px;margin:60px;display:inline-block;text-align:left">' +
text + '</div></div>';
}
function autoRefresh(view, model, appHash) {
var socket = model.socket;
model.on('connectionStatus', function(connected, canConnect) {
if (!canConnect) window.location.reload(true);
});
socket.on('connect', function() {
socket.emit('derbyClient', appHash, function(reload) {
if (reload) window.location.reload(true);
});
});
socket.on('refreshCss', function(err, css) {
var el = document.getElementById('$_css');
if (el) el.innerHTML = css;
updateError('CSS', err);
});
socket.on('refreshHtml', function(err, templates, instances, libraryData) {
view._makeAll(templates, instances);
view._makeComponents(libraryData);
try {
view.history.refresh();
} catch (_err) {
err || (err = _err.stack);
}
updateError('Template', err);
});
}
function updateError(type, err) {
if (err) {
errors[type] = err;
} else {
delete errors[type];
}
var el = document.getElementById('$_derbyError')
, html = errorHtml(errors)
, fragment, range;
if (html) {
if (el) {
el.outerHTML = html;
} else {
range = document.createRange();
range.selectNode(document.body);
fragment = range.createContextualFragment(html);
document.body.appendChild(fragment);
}
} else {
if (el) el.parentNode.removeChild(el);
}
}

75
first-project/node_modules/derby/lib/refresh.server.js generated vendored Normal file
View File

@@ -0,0 +1,75 @@
var isProduction = require('racer').util.isProduction
, files = require('./files')
, refresh = module.exports = require('./refresh');
refresh.cssError = cssError;
refresh.templateError = templateError;
refresh.autoRefresh = autoRefresh;
function cssError(err) {
if (err.stack) {
console.error('\nCSS PARSE ERROR\n' + err.stack);
return err.stack;
} else {
console.error('\nCSS PARSE ERROR\n' + err.message + '\n' + err.filename);
return err.message + '\n' + err.filename;
}
}
function templateError(err) {
console.error('\nTEMPLATE ERROR\n' + err.stack);
return err.stack;
}
function autoRefresh(store, options, view) {
if (isProduction || store._derbySocketsSetup) return;
store._derbySocketsSetup = true;
var listeners = {};
store.sockets.on('connection', function(socket) {
socket.on('derbyClient', function(appHash, callback) {
var appFilename, reload, sockets;
reload = appHash !== view._appHash;
callback(reload);
if (reload) return;
appFilename = view._appFilename;
if (listeners[appFilename]) {
return listeners[appFilename].push(socket);
}
sockets = listeners[appFilename] = [socket];
addWatches(appFilename, options, sockets, view);
});
});
}
function addWatches(appFilename, options, sockets, view) {
var parsed = files.parseName(appFilename, options)
, root = parsed.root
, clientName = parsed.clientName;
files.watch(root, 'css', function() {
view._loadCss(root, clientName, function(err, css) {
var errText;
if (err) errText = cssError(err);
for (var i = sockets.length; i--;) {
sockets[i].emit('refreshCss', errText, css);
}
});
});
files.watch(root, 'html', function() {
view._loadTemplates(root, clientName, function(err, templates, instances, libraryData) {
var errText;
if (err) errText = templateError(err);
for (var i = sockets.length; i--;) {
sockets[i].emit('refreshHtml', errText, templates, instances, libraryData);
}
});
});
files.watch(root, 'js', function() {
process.send({type: 'reload'});
});
}

269
first-project/node_modules/derby/lib/viewPath.js generated vendored Normal file
View File

@@ -0,0 +1,269 @@
var lookup = require('racer/lib/path').lookup
, trimLeading = require('html-util').trimLeading;
exports.wrapRemainder = wrapRemainder;
exports.extractPlaceholder = extractPlaceholder;
exports.pathFnArgs = pathFnArgs;
exports.ctxPath = ctxPath;
exports.dataValue = dataValue;
exports.setBoundFn = setBoundFn;
function wrapRemainder(tagName, remainder) {
if (!remainder) return false;
return !(new RegExp('^<\/' + tagName, 'i')).test(remainder);
}
var openPlaceholder = /^([\s\S]*?)(\{{1,3})([\s\S]*)/
, placeholderContent = /^\s*([\#\/]?)(?:(else\sif|if|else|unless|each|with|unescaped)(?!\())?\s*([^\s(>]*(?:\s*\([\s\S]*\))?)(?:\s+as\s+:([^\s>]+))?/;
function extractPlaceholder(text) {
var match = openPlaceholder.exec(text);
if (!match) return;
var pre = match[1]
, open = match[2]
, remainder = match[3]
, openLen = open.length
, bound = openLen === 1
, macro = openLen === 3
, end = matchBraces(remainder, openLen, 0, '{', '}')
, endInner = end - openLen
, inner = remainder.slice(0, endInner)
, post = remainder.slice(end)
, content = placeholderContent.exec(inner)
, escaped, name, type;
if (!content) return;
type = content[2];
escaped = true;
if (type === 'unescaped') {
escaped = false;
type = '';
}
name = content[3];
if (bound) name = name.replace(/\bthis\b/, '.');
if (macro && name === 'content') escaped = false;
return {
pre: trimLeading(pre)
, post: trimLeading(post)
, bound: bound
, macro: macro
, hash: content[1]
, escaped: escaped
, type: type
, name: name
, alias: content[4]
};
}
function matchBraces(text, num, i, openChar, closeChar) {
var close, hasClose, hasOpen, open;
i++;
while (num) {
close = text.indexOf(closeChar, i);
open = text.indexOf(openChar, i);
hasClose = ~close;
hasOpen = ~open;
if (hasClose && (!hasOpen || (close < open))) {
i = close + 1;
num--;
continue;
} else if (hasOpen) {
i = open + 1;
num++;
continue;
} else {
return;
}
}
return i;
}
var fnCall = /^([^(]+)\s*\(\s*([\s\S]*?)\s*\)\s*$/
, argSeparator = /\s*([,(])\s*/g
, notSeparator = /[^,\s]/g
, notPathArg = /(?:^['"\d\-[{])|(?:^null$)|(?:^true$)|(?:^false$)/;
function fnArgs(inner) {
var args = []
, lastIndex = 0
, match, end, last;
while (match = argSeparator.exec(inner)) {
if (match[1] === '(') {
end = matchBraces(inner, 1, argSeparator.lastIndex, '(', ')');
args.push(inner.slice(lastIndex, end));
notSeparator.lastIndex = end;
lastIndex = argSeparator.lastIndex =
notSeparator.test(inner) ? notSeparator.lastIndex - 1 : end;
continue;
}
args.push(inner.slice(lastIndex, match.index));
lastIndex = argSeparator.lastIndex;
}
last = inner.slice(lastIndex);
if (last) args.push(last);
return args;
}
function fnCallError(name) {
throw new Error('malformed view function call: ' + name);
}
function fnArgValue(view, ctx, model, name, macro, arg) {
if (arg === 'null') return null;
if (arg === 'true') return true;
if (arg === 'false') return false;
var firstChar = arg.charAt(0)
, match;
if (firstChar === "'") {
match = /^'(.*)'$/.exec(arg) || fnCallError(name);
return match[1];
}
if (firstChar === '"') {
match = /^"(.*)"$/.exec(arg) || fnCallError(name);
return match[1];
}
if (/^[\d\-]/.test(firstChar) && !isNaN(arg)) {
return +arg;
}
if (firstChar === '[' || firstChar === '{') {
throw new Error('object literals not supported in view function call: ' + name);
}
return dataValue(view, ctx, model, arg, macro);
}
function fnValue(view, ctx, model, name, macro) {
var match = fnCall.exec(name) || fnCallError(name)
, fnName = match[1]
, args = fnArgs(match[2])
, fn, fnName, i;
for (i = args.length; i--;) {
args[i] = fnArgValue(view, ctx, model, name, macro, args[i]);
}
if (!(fn = view.getFns[fnName])) {
throw new Error('view function "' + fnName + '" not found for call: ' + name);
}
return fn.apply(null, args);
}
function pathFnArgs(name, paths) {
var match = fnCall.exec(name) || fnCallError(name)
, args = fnArgs(match[2])
, i, arg;
if (paths == null) paths = [];
for (i = args.length; i--;) {
arg = args[i];
if (notPathArg.test(arg)) continue;
if (~arg.indexOf('(')) {
pathFnArgs(arg, paths);
continue;
}
paths.push(arg);
}
return paths;
}
function macroName(ctx, name, noReplace) {
var macroCtx = ctx.$macroCtx
, path = ctxPath(macroCtx, name, false, noReplace)
, segments = path.split('.')
, base = segments[0].toLowerCase()
, remainder = segments[1]
, value = lookup(base, macroCtx)
, macroVar = value && value.$macroVar;
if (!macroVar) return remainder ? base + '.' + remainder : base;
return remainder ?
(/\.+/.test(macroVar) ? macroVar.slice(1) : macroVar) + '.' + remainder :
macroVar;
}
function ctxPath(ctx, name, macro, noReplace) {
if (macro) name = macroName(ctx, name, noReplace);
var firstChar = name.charAt(0)
, i, aliasName, firstChar, indices;
if (firstChar === ':') {
if (~(i = name.indexOf('.'))) {
aliasName = name.slice(1, i);
name = name.slice(i);
} else {
aliasName = name.slice(1);
name = '';
}
i = ctx.$depth - ctx.$aliases[aliasName];
if (i !== i) throw new Error("Can't find alias for " + aliasName);
} else if (firstChar === '.') {
i = 0;
while (name.charAt(i) === '.') {
i++;
}
name = i === name.length ? '' : name.slice(i - 1);
}
if (i && (name = ctx.$paths[i - 1] + name) && !noReplace) {
indices = ctx.$indices;
i = indices.length;
name = name.replace(/\$#/g, function() {
return indices[--i];
});
}
return name.replace(/\[([^\]]+)\]/g, function(match, name) {
return lookup(name, ctx);
});
}
function dataValue(view, ctx, model, name, macro) {
var path, value;
if (~name.indexOf('(')) {
return fnValue(view, ctx, model, name, macro);
}
if (macro) {
// Get macro content sections
value = lookup(name.toLowerCase(), ctx.$macroCtx);
if (value && !value.$macroVar) {
return typeof value === 'function' ? value(ctx, model) : value;
}
}
path = ctxPath(ctx, name, macro);
value = lookup(path, ctx);
if (value !== void 0) return value;
value = model.get(path);
return value !== void 0 ? value : model[path];
}
function setBoundFn(view, ctx, model, name, value) {
var match = fnCall.exec(name) || fnCallError(name)
, fnName = match[1]
, args = fnArgs(match[2])
, get = view.getFns[fnName]
, set = view.setFns[fnName]
, macro = false
, numInputs = set.length - 1
, arg, i, inputs, out, path, len;
if (!(get && set)) {
throw new Error('view function "' + fnName + '" not found for binding to: ' + name);
}
if (numInputs) {
inputs = [value];
i = 0;
while (i < numInputs) {
inputs.push(fnArgValue(view, ctx, model, name, macro, args[i++]));
}
out = set.apply(null, inputs);
} else {
out = set(value);
}
if (!out) return;
for (i = 0, len = out.length; i < len; i++) {
value = out[i];
arg = args[i + numInputs];
if (~arg.indexOf('(')) {
setBoundFn(view, ctx, model, arg, value);
continue;
}
if (value === void 0 || notPathArg.test(arg)) continue;
path = ctxPath(ctx, arg);
if (model.get(path) === value) continue;
model.set(path, value);
}
}

View File

@@ -0,0 +1,9 @@
#!/bin/sh
if [ -x "`dirname "$0"`/node" ]; then
"`dirname "$0"`/node" "`dirname "$0"`/../less/bin/lessc" "$@"
ret=$?
else
node "`dirname "$0"`/../less/bin/lessc" "$@"
ret=$?
fi
exit $ret

View File

@@ -0,0 +1,6 @@
:: Created by npm, please don't edit manually.
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\less\bin\lessc" %*
) ELSE (
node "%~dp0\..\less\bin\lessc" %*
)

View File

@@ -0,0 +1,9 @@
#!/bin/sh
if [ -x "`dirname "$0"`/node" ]; then
"`dirname "$0"`/node" "`dirname "$0"`/../stylus/bin/stylus" "$@"
ret=$?
else
node "`dirname "$0"`/../stylus/bin/stylus" "$@"
ret=$?
fi
exit $ret

View File

@@ -0,0 +1,6 @@
:: Created by npm, please don't edit manually.
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\stylus\bin\stylus" %*
) ELSE (
node "%~dp0\..\stylus\bin\stylus" %*
)

View File

@@ -0,0 +1,9 @@
#!/bin/sh
if [ -x "`dirname "$0"`/node" ]; then
"`dirname "$0"`/node" "`dirname "$0"`/../up/bin/up" "$@"
ret=$?
else
node "`dirname "$0"`/../up/bin/up" "$@"
ret=$?
fi
exit $ret

View File

@@ -0,0 +1,6 @@
:: Created by npm, please don't edit manually.
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\up\bin\up" %*
) ELSE (
node "%~dp0\..\up\bin\up" %*
)

View File

@@ -0,0 +1,4 @@
support
test
examples
*.sock

View File

@@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.4
- 0.6

View File

@@ -0,0 +1,101 @@
0.6.0 / 2012-04-10
==================
* Added `.prompt(obj, callback)` support. Closes #49
* Added default support to .choose(). Closes #41
* Fixed the choice example
0.5.1 / 2011-12-20
==================
* Fixed `password()` for recent nodes. Closes #36
0.5.0 / 2011-12-04
==================
* Added sub-command option support [itay]
0.4.3 / 2011-12-04
==================
* Fixed custom help ordering. Closes #32
0.4.2 / 2011-11-24
==================
* Added travis support
* Fixed: line-buffered input automatically trimmed. Closes #31
0.4.1 / 2011-11-18
==================
* Removed listening for "close" on --help
0.4.0 / 2011-11-15
==================
* Added support for `--`. Closes #24
0.3.3 / 2011-11-14
==================
* Fixed: wait for close event when writing help info [Jerry Hamlet]
0.3.2 / 2011-11-01
==================
* Fixed long flag definitions with values [felixge]
0.3.1 / 2011-10-31
==================
* Changed `--version` short flag to `-V` from `-v`
* Changed `.version()` so it's configurable [felixge]
0.3.0 / 2011-10-31
==================
* Added support for long flags only. Closes #18
0.2.1 / 2011-10-24
==================
* "node": ">= 0.4.x < 0.7.0". Closes #20
0.2.0 / 2011-09-26
==================
* Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
0.1.0 / 2011-08-24
==================
* Added support for custom `--help` output
0.0.5 / 2011-08-18
==================
* Changed: when the user enters nothing prompt for password again
* Fixed issue with passwords beginning with numbers [NuckChorris]
0.0.4 / 2011-08-15
==================
* Fixed `Commander#args`
0.0.3 / 2011-08-15
==================
* Added default option value support
0.0.2 / 2011-08-15
==================
* Added mask support to `Command#password(str[, mask], fn)`
* Added `Command#password(str, fn)`
0.0.1 / 2010-01-03
==================
* Initial release

View File

@@ -0,0 +1,7 @@
TESTS = $(shell find test/test.*.js)
test:
@./test/run $(TESTS)
.PHONY: test

View File

@@ -0,0 +1,263 @@
# Commander.js
The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).
[![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)
## Installation
$ npm install commander
## Option parsing
Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.0.1')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineappe');
if (program.bbq) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);
```
Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
## Automated --help
The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
```
$ ./examples/pizza --help
Usage: pizza [options]
Options:
-v, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineappe
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese [marble]
-h, --help output usage information
```
## Coercion
```js
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
program
.version('0.0.1')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' args: %j', program.args);
```
## Custom help
You can display arbitrary `-h, --help` information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviours, for example
in the following executable "stuff" will not output when
`--help` is used.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('../');
function list(val) {
return val.split(',').map(Number);
}
program
.version('0.0.1')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log(' Examples:');
console.log('');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
console.log('');
});
program.parse(process.argv);
console.log('stuff');
```
yielding the following help output:
```
Usage: custom-help [options]
Options:
-h, --help output usage information
-v, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
```
## .prompt(msg, fn)
Single-line prompt:
```js
program.prompt('name: ', function(name){
console.log('hi %s', name);
});
```
Multi-line prompt:
```js
program.prompt('description:', function(name){
console.log('hi %s', name);
});
```
Coercion:
```js
program.prompt('Age: ', Number, function(age){
console.log('age: %j', age);
});
```
```js
program.prompt('Birthdate: ', Date, function(date){
console.log('date: %s', date);
});
```
## .password(msg[, mask], fn)
Prompt for password without echoing:
```js
program.password('Password: ', function(pass){
console.log('got "%s"', pass);
process.stdin.destroy();
});
```
Prompt for password with mask char "*":
```js
program.password('Password: ', '*', function(pass){
console.log('got "%s"', pass);
process.stdin.destroy();
});
```
## .confirm(msg, fn)
Confirm with the given `msg`:
```js
program.confirm('continue? ', function(ok){
console.log(' got %j', ok);
});
```
## .choose(list, fn)
Let the user choose from a `list`:
```js
var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
console.log('Choose the coolest pet:');
program.choose(list, function(i){
console.log('you chose %d "%s"', i, list[i]);
});
```
## Links
- [API documentation](http://visionmedia.github.com/commander.js/)
- [ascii tables](https://github.com/LearnBoost/cli-table)
- [progress bars](https://github.com/visionmedia/node-progress)
- [more progress bars](https://github.com/substack/node-multimeter)
- [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
## License
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,2 @@
module.exports = require('./lib/commander');

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
{
"name": "commander",
"version": "0.6.0",
"description": "the complete solution for node.js command-line programs",
"keywords": [
"command",
"option",
"parser",
"prompt",
"stdin"
],
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"repository": {
"type": "git",
"url": "git://github.com/visionmedia/commander.js.git"
},
"dependencies": {},
"devDependencies": {
"should": ">= 0.0.1"
},
"scripts": {
"test": "make test"
},
"main": "index",
"engines": {
"node": ">= 0.4.x < 0.7.0"
},
"_id": "commander@0.6.0",
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"_from": "commander@>=0.5.2"
}

View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -0,0 +1,12 @@
ROOT := $(shell pwd)
MOCHA_TESTS := $(shell find test/ -name '*.mocha.coffee')
MOCHA := ./node_modules/mocha/bin/mocha
g = "."
test-mocha:
@NODE_ENV=test $(MOCHA) \
--grep "$(g)" \
$(MOCHA_TESTS)
test: test-mocha

View File

@@ -0,0 +1,24 @@
# dom-shim
Shim newer DOM features in older browsers
## MIT License
Copyright (c) 2012 by Nate Smith and Brian Noguchi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,43 @@
var doc = document
, elementProto = HTMLElement.prototype
, nodeProto = Node.prototype
// Add support for Node.contains for Firefox < 9
if (!doc.contains) {
nodeProto.contains = function(node) {
return !!(this.compareDocumentPosition(node) & 16)
}
}
// Add support for insertAdjacentHTML for Firefox < 8
// Based on insertAdjacentHTML.js by Eli Grey, http://eligrey.com
if (!doc.body.insertAdjacentHTML) {
elementProto.insertAdjacentHTML = function(position, html) {
var position = position.toLowerCase()
, ref = this
, parent = ref.parentNode
, container = doc.createElement(parent.tagName)
, firstChild, nextSibling, node
container.innerHTML = html
if (position === 'beforeend') {
while (node = container.firstChild) {
ref.appendChild(node)
}
} else if (position === 'beforebegin') {
while (node = container.firstChild) {
parent.insertBefore(node, ref)
}
} else if (position === 'afterend') {
nextSibling = ref.nextSibling
while (node = container.lastChild) {
nextSibling = parent.insertBefore(node, nextSibling)
}
} else if (position === 'afterbegin') {
firstChild = ref.firstChild
while (node = container.lastChild) {
firstChild = ref.insertBefore(node, firstChild)
}
}
}
}

View File

@@ -0,0 +1,26 @@
{
"name": "dom-shim",
"description": "Shim newer DOM features in older browsers",
"repository": {
"type": "git",
"url": "git://github.com/codeparty/dom-shim.git"
},
"version": "0.1.0",
"main": "./lib/index.js",
"dependencies": {},
"devDependencies": {
"mocha": ">=1",
"expect.js": ">=0.1.2",
"coffee-script": ">=1.3.1"
},
"engines": {
"node": ">=0.4.0"
},
"optionalDependencies": {},
"_id": "dom-shim@0.1.0",
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"_from": "dom-shim@>=0.1.0"
}

View File

@@ -0,0 +1,6 @@
--colors
--reporter spec
--timeout 500
--growl
--debug
--compilers coffee:coffee-script

View File

@@ -0,0 +1 @@
node_modules/

View File

@@ -0,0 +1,12 @@
ROOT := $(shell pwd)
MOCHA_TESTS := $(shell find test/ -name '*.mocha.coffee')
MOCHA := ./node_modules/mocha/bin/mocha
g = "."
test-mocha:
@NODE_ENV=test $(MOCHA) \
--grep "$(g)" \
$(MOCHA_TESTS)
test: test-mocha

View File

@@ -0,0 +1,24 @@
# html-util
HTML utilities for simple parsing and escaping
## MIT License
Copyright (c) 2012 by Nate Smith and Brian Noguchi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,257 @@
module.exports = {
quot: 0x0022
, amp: 0x0026
, apos: 0x0027
, lpar: 0x0028
, rpar: 0x0029
, lt: 0x003C
, gt: 0x003E
, nbsp: 0x00A0
, iexcl: 0x00A1
, cent: 0x00A2
, pound: 0x00A3
, curren: 0x00A4
, yen: 0x00A5
, brvbar: 0x00A6
, sect: 0x00A7
, uml: 0x00A8
, copy: 0x00A9
, ordf: 0x00AA
, laquo: 0x00AB
, not: 0x00AC
, shy: 0x00AD
, reg: 0x00AE
, macr: 0x00AF
, deg: 0x00B0
, plusmn: 0x00B1
, sup2: 0x00B2
, sup3: 0x00B3
, acute: 0x00B4
, micro: 0x00B5
, para: 0x00B6
, middot: 0x00B7
, cedil: 0x00B8
, sup1: 0x00B9
, ordm: 0x00BA
, raquo: 0x00BB
, frac14: 0x00BC
, frac12: 0x00BD
, frac34: 0x00BE
, iquest: 0x00BF
, Agrave: 0x00C0
, Aacute: 0x00C1
, Acirc: 0x00C2
, Atilde: 0x00C3
, Auml: 0x00C4
, Aring: 0x00C5
, AElig: 0x00C6
, Ccedil: 0x00C7
, Egrave: 0x00C8
, Eacute: 0x00C9
, Ecirc: 0x00CA
, Euml: 0x00CB
, Igrave: 0x00CC
, Iacute: 0x00CD
, Icirc: 0x00CE
, Iuml: 0x00CF
, ETH: 0x00D0
, Ntilde: 0x00D1
, Ograve: 0x00D2
, Oacute: 0x00D3
, Ocirc: 0x00D4
, Otilde: 0x00D5
, Ouml: 0x00D6
, times: 0x00D7
, Oslash: 0x00D8
, Ugrave: 0x00D9
, Uacute: 0x00DA
, Ucirc: 0x00DB
, Uuml: 0x00DC
, Yacute: 0x00DD
, THORN: 0x00DE
, szlig: 0x00DF
, agrave: 0x00E0
, aacute: 0x00E1
, acirc: 0x00E2
, atilde: 0x00E3
, auml: 0x00E4
, aring: 0x00E5
, aelig: 0x00E6
, ccedil: 0x00E7
, egrave: 0x00E8
, eacute: 0x00E9
, ecirc: 0x00EA
, euml: 0x00EB
, igrave: 0x00EC
, iacute: 0x00ED
, icirc: 0x00EE
, iuml: 0x00EF
, eth: 0x00F0
, ntilde: 0x00F1
, ograve: 0x00F2
, oacute: 0x00F3
, ocirc: 0x00F4
, otilde: 0x00F5
, ouml: 0x00F6
, divide: 0x00F7
, oslash: 0x00F8
, ugrave: 0x00F9
, uacute: 0x00FA
, ucirc: 0x00FB
, uuml: 0x00FC
, yacute: 0x00FD
, thorn: 0x00FE
, yuml: 0x00FF
, OElig: 0x0152
, oelig: 0x0153
, Scaron: 0x0160
, scaron: 0x0161
, Yuml: 0x0178
, fnof: 0x0192
, circ: 0x02C6
, tilde: 0x02DC
, Alpha: 0x0391
, Beta: 0x0392
, Gamma: 0x0393
, Delta: 0x0394
, Epsilon: 0x0395
, Zeta: 0x0396
, Eta: 0x0397
, Theta: 0x0398
, Iota: 0x0399
, Kappa: 0x039A
, Lambda: 0x039B
, Mu: 0x039C
, Nu: 0x039D
, Xi: 0x039E
, Omicron: 0x039F
, Pi: 0x03A0
, Rho: 0x03A1
, Sigma: 0x03A3
, Tau: 0x03A4
, Upsilon: 0x03A5
, Phi: 0x03A6
, Chi: 0x03A7
, Psi: 0x03A8
, Omega: 0x03A9
, alpha: 0x03B1
, beta: 0x03B2
, gamma: 0x03B3
, delta: 0x03B4
, epsilon: 0x03B5
, zeta: 0x03B6
, eta: 0x03B7
, theta: 0x03B8
, iota: 0x03B9
, kappa: 0x03BA
, lambda: 0x03BB
, mu: 0x03BC
, nu: 0x03BD
, xi: 0x03BE
, omicron: 0x03BF
, pi: 0x03C0
, rho: 0x03C1
, sigmaf: 0x03C2
, sigma: 0x03C3
, tau: 0x03C4
, upsilon: 0x03C5
, phi: 0x03C6
, chi: 0x03C7
, psi: 0x03C8
, omega: 0x03C9
, thetasym: 0x03D1
, upsih: 0x03D2
, piv: 0x03D6
, ensp: 0x2002
, emsp: 0x2003
, thinsp: 0x2009
, zwnj: 0x200C
, zwj: 0x200D
, lrm: 0x200E
, rlm: 0x200F
, ndash: 0x2013
, mdash: 0x2014
, lsquo: 0x2018
, rsquo: 0x2019
, sbquo: 0x201A
, ldquo: 0x201C
, rdquo: 0x201D
, bdquo: 0x201E
, dagger: 0x2020
, Dagger: 0x2021
, bull: 0x2022
, hellip: 0x2026
, permil: 0x2030
, prime: 0x2032
, Prime: 0x2033
, lsaquo: 0x2039
, rsaquo: 0x203A
, oline: 0x203E
, frasl: 0x2044
, euro: 0x20AC
, image: 0x2111
, weierp: 0x2118
, real: 0x211C
, trade: 0x2122
, alefsym: 0x2135
, larr: 0x2190
, uarr: 0x2191
, rarr: 0x2192
, darr: 0x2193
, harr: 0x2194
, crarr: 0x21B5
, lArr: 0x21D0
, uArr: 0x21D1
, rArr: 0x21D2
, dArr: 0x21D3
, hArr: 0x21D4
, forall: 0x2200
, part: 0x2202
, exist: 0x2203
, empty: 0x2205
, nabla: 0x2207
, isin: 0x2208
, notin: 0x2209
, ni: 0x220B
, prod: 0x220F
, sum: 0x2211
, minus: 0x2212
, lowast: 0x2217
, radic: 0x221A
, prop: 0x221D
, infin: 0x221E
, ang: 0x2220
, and: 0x2227
, or: 0x2228
, cap: 0x2229
, cup: 0x222A
, int: 0x222B
, there4: 0x2234
, sim: 0x223C
, cong: 0x2245
, asymp: 0x2248
, ne: 0x2260
, equiv: 0x2261
, le: 0x2264
, ge: 0x2265
, sub: 0x2282
, sup: 0x2283
, nsub: 0x2284
, sube: 0x2286
, supe: 0x2287
, oplus: 0x2295
, otimes: 0x2297
, perp: 0x22A5
, sdot: 0x22C5
, lceil: 0x2308
, rceil: 0x2309
, lfloor: 0x230A
, rfloor: 0x230B
, lang: 0x2329
, rang: 0x232A
, loz: 0x25CA
, spades: 0x2660
, clubs: 0x2663
, hearts: 0x2665
, diams: 0x2666
}

View File

@@ -0,0 +1,116 @@
var entityCode = require('./entityCode')
, parse = require('./parse')
module.exports = {
parse: parse
, escapeHtml: escapeHtml
, escapeAttribute: escapeAttribute
, unescapeEntities: unescapeEntities
, isVoid: isVoid
, conditionalComment: conditionalComment
, trimLeading: trimLeading
, trimTag: trimTag
, minify: minify
}
function escapeHtml(value) {
if (value == null) return ''
return value
.toString()
.replace(/&(?!\s)|</g, function(match) {
return match === '&' ? '&amp;' : '&lt;'
})
}
function escapeAttribute(value) {
if (value == null || value === '') return '""'
value = value
.toString()
.replace(/&(?!\s)|"/g, function(match) {
return match === '&' ? '&amp;' : '&quot;'
})
return /[ =<>']/.test(value) ? '"' + value + '"' : value
}
// Based on:
// http://code.google.com/p/jslibs/wiki/JavascriptTips#Escape_and_unescape_HTML_entities
function unescapeEntities(html) {
return html.replace(/&([^;]+);/g, function(match, entity) {
var charCode = entity.charAt(0) === '#'
? entity.charAt(1) === 'x'
? entity.slice(2, 17)
: entity.slice(1)
: entityCode[entity]
return String.fromCharCode(charCode)
})
}
var voidElement = {
area: 1
, base: 1
, br: 1
, col: 1
, command: 1
, embed: 1
, hr: 1
, img: 1
, input: 1
, keygen: 1
, link: 1
, meta: 1
, param: 1
, source: 1
, track: 1
, wbr: 1
}
function isVoid(name) {
return name in voidElement
}
// Assume any HTML comment that starts with `<!--[` or ends with `]-->`
// is a conditional comment. This can also be used to keep comments in
// minified HTML, such as `<!--[ Copyright John Doe, MIT Licensed ]-->`
function conditionalComment(tag) {
return /(?:^<!--\[)|(?:\]-->$)/.test(tag)
}
// Remove leading whitespace and newlines from a string. Note that trailing
// whitespace is not removed in case whitespace is desired between lines
function trimLeading(text) {
return text ? text.replace(/\n\s*/g, '') : ''
}
// Within a tag, remove leading whitespace. Keep a linebreak, since this
// could be the separator between attributes
function trimTag(tag) {
return tag.replace(/(?:\n\s*)+/g, '\n')
}
// Remove linebreaks, leading space, and comments. Maintain a linebreak between
// HTML tag attributes and maintain conditional comments.
function minify(html) {
var minified = ''
, minifyContent = true
parse(html, {
start: function(tag, tagName, attrs) {
minifyContent = !('x-no-minify' in attrs)
minified += trimTag(tag)
}
, end: function(tag) {
minified += trimTag(tag)
}
, text: function(text) {
minified += minifyContent ? trimLeading(text) : text
}
, comment: function(tag) {
if (conditionalComment(tag)) minified += tag
}
, other: function(tag) {
minified += tag
}
})
return minified
}

View File

@@ -0,0 +1,112 @@
var startTag = /^<([^\s=\/!>]+)((?:\s+[^\s=\/>]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+)?)?)*)\s*(\/?)\s*>/
, endTag = /^<\/([^\s=\/!>]+)[^>]*>/
, comment = /^<!--([\s\S]*?)-->/
, other = /^<([\s\S]*?)>/
, attr = /([^\s=]+)(?:\s*(=)\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+))?)?/g
, rawTagsDefault = /^(style|script)$/i
function empty() {}
function matchEndDefault(tagName) {
return new RegExp('</' + tagName, 'i')
}
function onStartTag(html, match, handler) {
var attrs = {}
, tag = match[0]
, tagName = match[1]
, remainder = match[2]
html = html.slice(tag.length)
remainder.replace(attr, function(match, name, equals, attr0, attr1, attr2) {
attrs[name.toLowerCase()] = attr0 || attr1 || attr2 || (equals ? '' : null)
})
handler(tag, tagName.toLowerCase(), attrs, html)
return html
}
function onTag(html, match, handler) {
var tag = match[0]
, data = match[1]
html = html.slice(tag.length)
handler(tag, data, html)
return html
}
function onText(html, index, isRawText, handler) {
var text
if (~index) {
text = html.slice(0, index)
html = html.slice(index)
} else {
text = html
html = ''
}
if (text) handler(text, isRawText, html)
return html
}
module.exports = function(html, options) {
if (options == null) options = {}
if (!html) return
var startHandler = options.start || empty
, endHandler = options.end || empty
, textHandler = options.text || empty
, commentHandler = options.comment || empty
, otherHandler = options.other || empty
, matchEnd = options.matchEnd || matchEndDefault
, errorHandler = options.error
, rawTags = options.rawTags || rawTagsDefault
, index, last, match, tagName, err
while (html) {
if (html === last) {
err = new Error('HTML parse error: ' + html)
if (errorHandler) {
errorHandler(err)
} else {
throw err
}
}
last = html
if (html[0] === '<') {
if (match = html.match(startTag)) {
html = onStartTag(html, match, startHandler)
tagName = match[1]
if (rawTags.test(tagName)) {
index = html.search(matchEnd(tagName))
html = onText(html, index, true, textHandler)
}
continue
}
if (match = html.match(endTag)) {
match[1] = match[1].toLowerCase() // tagName
html = onTag(html, match, endHandler)
continue
}
if (match = html.match(comment)) {
html = onTag(html, match, commentHandler)
continue
}
if (match = html.match(other)) {
html = onTag(html, match, otherHandler)
continue
}
}
index = html.indexOf('<')
html = onText(html, index, false, textHandler)
}
}

View File

@@ -0,0 +1,26 @@
{
"name": "html-util",
"description": "Simple and fast html utilities for parsing and escaping",
"repository": {
"type": "git",
"url": "git://github.com/codeparty/html.git"
},
"version": "0.1.2",
"main": "./lib/index.js",
"dependencies": {},
"devDependencies": {
"mocha": ">=1",
"expect.js": ">=0.1.2",
"coffee-script": ">=1.3.1"
},
"engines": {
"node": ">=0.4.0"
},
"optionalDependencies": {},
"_id": "html-util@0.1.2",
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"_from": "html-util@>=0.1.2"
}

View File

@@ -0,0 +1,35 @@
expect = require 'expect.js'
html = require '../lib'
describe 'minify', ->
it 'should minify HTML', ->
test = '''
<!DOCTYPE html>
<!-- This comment is removed -->
<title></title>
<!--[if gt IE 6]>
IE greater than 6
<![endif]-->
<!--[if !IE]> -->
Not IE
<!-- <![endif]-->
<b>
Hi there
</b>
<script x-no-minify>
stuff: rocks
other: salt
</script>
'''
expected = '<!DOCTYPE html>' +
'<title></title><!--[if gt IE 6]>\n' +
'IE greater than 6\n' +
'<![endif]-->' +
'<!--[if !IE]> -->Not IE<!-- <![endif]-->' +
'<b> Hi there</b><script x-no-minify>\n' +
' stuff: rocks\n' +
' other: salt\n' +
'</script>'
expect(html.minify(test)).to.equal expected

View File

@@ -0,0 +1,6 @@
--colors
--reporter spec
--timeout 500
--growl
--debug
--compilers coffee:coffee-script

View File

@@ -0,0 +1,82 @@
expect = require 'expect.js'
html = require '../lib'
describe 'parse', ->
it 'should parse with no handlers', ->
html.parse '<p id=stuff>Heyo</p>'
it 'should parse basic HTML', ->
s =
'<!DOCTYPE html>' + # doctype
'<h1>Willow ' + # Tag containing chars
'<EM ID=h1 CLASS=head>' + # Nested tag, attributes, uppercase
'tree' +
'</em>' +
'</h1>' +
'<script>' + # Scripts should be passed through as rawText
'<b></b>' +
'</script>' +
'<!-- here is a comment\n cool beans!-->\n\t ' +
'<b><b><b></b></b></b>' + # Nested tags, no contents
'<form action= \'javascript:alert("cows")\' >' + # Single quote attr
'<input type = "checkbox" disabled data-stuff=hey>' + # double quotes attr, empty attr, and data attribute
'<input type="submit" value=>' + # While invalid HTML, value should be an empty string
'</FORM>' + # Uppercase end
'<img src=/img/stuff.png alt=""/>' + # Don't choke on void element with slash
'<p>Flowers ' + # Trailing whitespace on implicitly closed tag
'<p>Flight</p>\n' + # Explicitly closed tag
' \t<p>Fight</p>\t \n' + # New line and leading whitespace
'<p>Blight\nSight</p> <p / >' # Whitespace between tags
expected = [
['other', '!DOCTYPE html']
['start', 'h1', {}]
['text', 'Willow ']
['start', 'em', { id: 'h1', 'class': 'head' }]
['text', 'tree']
['end', 'em']
['end', 'h1']
['start', 'script', {}]
['text', '<b></b>']
['end', 'script']
['comment', ' here is a comment\n cool beans!']
['text', '\n\t ']
['start', 'b', {}]
['start', 'b', {}]
['start', 'b', {}]
['end', 'b']
['end', 'b']
['end', 'b']
['start', 'form', {action: 'javascript:alert("cows")'}]
['start', 'input', {type: 'checkbox', disabled: null, 'data-stuff': 'hey'}]
['start', 'input', {type: 'submit', value: ''}]
['end', 'form']
['start', 'img', {src: '/img/stuff.png', alt: ''}]
['start', 'p', {}]
['text', 'Flowers ']
['start', 'p', {}]
['text', 'Flight']
['end', 'p']
['text', '\n \t']
['start', 'p', {}]
['text', 'Fight']
['end', 'p']
['text', '\t \n']
['start', 'p', {}]
['text', 'Blight\nSight']
['end', 'p']
['text', ' ']
['start', 'p', {}]
]
stack = []
html.parse s,
start: (tag, tagName, attrs) -> stack.push ['start', tagName, attrs]
end: (tag, tagName) -> stack.push ['end', tagName]
text: (text) -> stack.push ['text', text]
comment: (tag, data) -> stack.push ['comment', data]
other: (tag, data) -> stack.push ['other', data]
for item, index in expected
expect(stack[index]).to.eql item
expect(stack.length).to.equal expected.length

View File

@@ -0,0 +1,2 @@
*.less

View File

@@ -0,0 +1,26 @@
1.2.1
fix imports on browser
improve error reporting on browser
fix Runtime error reports from imported files
fix 'File not found' import error reporting
1.2.0
- mixin guards
- new function `percentage`
- new `color` function to parse hex color strings
- new type-checking stylesheet functions
- fix Rhino support
- fix bug in string arguments to mixin call
- fix error reporting when index is 0
- fix browser support in webkit and IE
- fix string interpolation bug when var is empty
- support '!important' after mixin calls
- support vanilla @keyframes directive
- support variables in certain css selectors, like 'nth-child'
- support @media and @import features properly
- improve @import support with media features
- improve error reports from imported files
- improve function call error reporting
- improve error-reporting

View File

@@ -0,0 +1,179 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright (c) 2009-2010 Alexis Sellier

View File

@@ -0,0 +1,75 @@
#
# Run all tests
#
test:
node test/less-test.js
#
# Run benchmark
#
benchmark:
node benchmark/less-benchmark.js
#
# Build less.js
#
SRC = lib/less
HEADER = build/header.js
VERSION = `cat package.json | grep version \
| grep -o '[0-9]\.[0-9]\.[0-9]\+'`
DIST = dist/less-${VERSION}.js
RHINO = dist/less-rhino-${VERSION}.js
DIST_MIN = dist/less-${VERSION}.min.js
less:
@@mkdir -p dist
@@touch ${DIST}
@@cat ${HEADER} | sed s/@VERSION/${VERSION}/ > ${DIST}
@@echo "(function (window, undefined) {" >> ${DIST}
@@cat build/require.js\
build/amd.js\
build/ecma-5.js\
${SRC}/parser.js\
${SRC}/functions.js\
${SRC}/colors.js\
${SRC}/tree/*.js\
${SRC}/tree.js\
${SRC}/browser.js >> ${DIST}
@@echo "})(window);" >> ${DIST}
@@echo ${DIST} built.
rhino:
@@mkdir -p dist
@@touch ${RHINO}
@@cat build/require-rhino.js\
build/ecma-5.js\
${SRC}/parser.js\
${SRC}/functions.js\
${SRC}/tree/*.js\
${SRC}/tree.js\
${SRC}/rhino.js > ${RHINO}
@@echo ${RHINO} built.
min: less
@@echo minifying...
@@uglifyjs ${DIST} > ${DIST_MIN}
@@echo ${DIST_MIN} built.
server: less
cp dist/less-${VERSION}.js test/html/
cd test/html && python -m SimpleHTTPServer
clean:
git rm dist/*
dist: clean min
git add dist/*
git commit -a -m "(dist) build ${VERSION}"
git archive master --prefix=less/ -o less-${VERSION}.tar.gz
npm publish less-${VERSION}.tar.gz
stable:
npm tag less ${VERSION} stable
.PHONY: test benchmark

View File

@@ -0,0 +1,20 @@
less.js
=======
The **dynamic** stylesheet language.
<http://lesscss.org>
about
-----
This is the JavaScript, and now official, stable version of LESS.
For more information, visit <http://lesscss.org>.
license
-------
See `LICENSE` file.
> Copyright (c) 2009-2011 Alexis Sellier

View File

@@ -0,0 +1,47 @@
var path = require('path'),
fs = require('fs'),
sys = require('util');
var less = require('../lib/less');
var file = path.join(__dirname, 'benchmark.less');
if (process.argv[2]) { file = path.join(process.cwd(), process.argv[2]) }
fs.readFile(file, 'utf8', function (e, data) {
var tree, css, start, end, total;
sys.puts("Benchmarking...\n", path.basename(file) + " (" +
parseInt(data.length / 1024) + " KB)", "");
start = new(Date);
new(less.Parser)({ optimization: 2 }).parse(data, function (err, tree) {
end = new(Date);
total = end - start;
sys.puts("Parsing: " +
total + " ms (" +
parseInt(1000 / total *
data.length / 1024) + " KB\/s)");
start = new(Date);
css = tree.toCSS();
end = new(Date);
sys.puts("Generation: " + (end - start) + " ms (" +
parseInt(1000 / (end - start) *
data.length / 1024) + " KB\/s)");
total += end - start;
sys.puts("Total: " + total + "ms (" +
parseInt(1000 / total * data.length / 1024) + " KB/s)");
if (err) {
less.writeError(err);
process.exit(3);
}
});
});

View File

@@ -0,0 +1,10 @@
<html>
<head>
<link rel="stylesheet/less" type="text/x-less" href="styles/x.less"/>
<script src="dist/less-1.2.1.js"></script>
</head>
<body>
HELLO
</body>
</html>

View File

@@ -0,0 +1,380 @@
//
// browser.js - client-side engine
//
var isFileProtocol = (location.protocol === 'file:' ||
location.protocol === 'chrome:' ||
location.protocol === 'chrome-extension:' ||
location.protocol === 'resource:');
less.env = less.env || (location.hostname == '127.0.0.1' ||
location.hostname == '0.0.0.0' ||
location.hostname == 'localhost' ||
location.port.length > 0 ||
isFileProtocol ? 'development'
: 'production');
// Load styles asynchronously (default: false)
//
// This is set to `false` by default, so that the body
// doesn't start loading before the stylesheets are parsed.
// Setting this to `true` can result in flickering.
//
less.async = false;
// Interval between watch polls
less.poll = less.poll || (isFileProtocol ? 1000 : 1500);
//
// Watch mode
//
less.watch = function () { return this.watchMode = true };
less.unwatch = function () { return this.watchMode = false };
if (less.env === 'development') {
less.optimization = 0;
if (/!watch/.test(location.hash)) {
less.watch();
}
less.watchTimer = setInterval(function () {
if (less.watchMode) {
loadStyleSheets(function (e, root, _, sheet, env) {
if (root) {
createCSS(root.toCSS(), sheet, env.lastModified);
}
});
}
}, less.poll);
} else {
less.optimization = 3;
}
var cache;
try {
cache = (typeof(window.localStorage) === 'undefined') ? null : window.localStorage;
} catch (_) {
cache = null;
}
//
// Get all <link> tags with the 'rel' attribute set to "stylesheet/less"
//
var links = document.getElementsByTagName('link');
var typePattern = /^text\/(x-)?less$/;
less.sheets = [];
for (var i = 0; i < links.length; i++) {
if (links[i].rel === 'stylesheet/less' || (links[i].rel.match(/stylesheet/) &&
(links[i].type.match(typePattern)))) {
less.sheets.push(links[i]);
}
}
less.refresh = function (reload) {
var startTime, endTime;
startTime = endTime = new(Date);
loadStyleSheets(function (e, root, _, sheet, env) {
if (env.local) {
log("loading " + sheet.href + " from cache.");
} else {
log("parsed " + sheet.href + " successfully.");
createCSS(root.toCSS(), sheet, env.lastModified);
}
log("css for " + sheet.href + " generated in " + (new(Date) - endTime) + 'ms');
(env.remaining === 0) && log("css generated in " + (new(Date) - startTime) + 'ms');
endTime = new(Date);
}, reload);
loadStyles();
};
less.refreshStyles = loadStyles;
less.refresh(less.env === 'development');
function loadStyles() {
var styles = document.getElementsByTagName('style');
for (var i = 0; i < styles.length; i++) {
if (styles[i].type.match(typePattern)) {
new(less.Parser)().parse(styles[i].innerHTML || '', function (e, tree) {
var css = tree.toCSS();
var style = styles[i];
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.innerHTML = css;
}
});
}
}
}
function loadStyleSheets(callback, reload) {
for (var i = 0; i < less.sheets.length; i++) {
loadStyleSheet(less.sheets[i], callback, reload, less.sheets.length - (i + 1));
}
}
function loadStyleSheet(sheet, callback, reload, remaining) {
var url = window.location.href.replace(/[#?].*$/, '');
var href = sheet.href.replace(/\?.*$/, '');
var css = cache && cache.getItem(href);
var timestamp = cache && cache.getItem(href + ':timestamp');
var styles = { css: css, timestamp: timestamp };
// Stylesheets in IE don't always return the full path
if (! /^(https?|file):/.test(href)) {
if (href.charAt(0) == "/") {
href = window.location.protocol + "//" + window.location.host + href;
} else {
href = url.slice(0, url.lastIndexOf('/') + 1) + href;
}
}
var filename = href.match(/([^\/]+)$/)[1];
xhr(sheet.href, sheet.type, function (data, lastModified) {
if (!reload && styles && lastModified &&
(new(Date)(lastModified).valueOf() ===
new(Date)(styles.timestamp).valueOf())) {
// Use local copy
createCSS(styles.css, sheet);
callback(null, null, data, sheet, { local: true, remaining: remaining });
} else {
// Use remote copy (re-parse)
try {
new(less.Parser)({
optimization: less.optimization,
paths: [href.replace(/[\w\.-]+$/, '')],
mime: sheet.type,
filename: filename
}).parse(data, function (e, root) {
if (e) { return error(e, href) }
try {
callback(e, root, data, sheet, { local: false, lastModified: lastModified, remaining: remaining });
removeNode(document.getElementById('less-error-message:' + extractId(href)));
} catch (e) {
error(e, href);
}
});
} catch (e) {
error(e, href);
}
}
}, function (status, url) {
throw new(Error)("Couldn't load " + url + " (" + status + ")");
});
}
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)
}
function createCSS(styles, sheet, lastModified) {
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));
}
// Don't update the local store if the file wasn't modified
if (lastModified && cache) {
log('saving ' + href + ' to cache.');
cache.setItem(href, styles);
cache.setItem(href + ':timestamp', lastModified);
}
}
function xhr(url, type, callback, errback) {
var xhr = getXMLHttpRequest();
var async = isFileProtocol ? false : less.async;
if (typeof(xhr.overrideMimeType) === 'function') {
xhr.overrideMimeType('text/css');
}
xhr.open('GET', url, async);
xhr.setRequestHeader('Accept', type || 'text/x-less, text/css; q=0.9, */*; q=0.5');
xhr.send(null);
if (isFileProtocol) {
if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 300)) {
callback(xhr.responseText);
} else {
errback(xhr.status, url);
}
} else if (async) {
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
handleResponse(xhr, callback, errback);
}
};
} else {
handleResponse(xhr, callback, errback);
}
function handleResponse(xhr, callback, errback) {
if (xhr.status >= 200 && xhr.status < 300) {
callback(xhr.responseText,
xhr.getResponseHeader("Last-Modified"));
} else if (typeof(errback) === 'function') {
errback(xhr.status, url);
}
}
}
function getXMLHttpRequest() {
if (window.XMLHttpRequest) {
return new(XMLHttpRequest);
} else {
try {
return new(ActiveXObject)("MSXML2.XMLHTTP.3.0");
} catch (e) {
log("browser doesn't support AJAX.");
return null;
}
}
}
function removeNode(node) {
return node && node.parentNode.removeChild(node);
}
function log(str) {
if (less.env == 'development' && typeof(console) !== "undefined") { console.log('less: ' + str) }
}
function error(e, href) {
var id = 'less-error-message:' + extractId(href);
var template = '<li><label>{line}</label><pre class="{class}">{content}</pre></li>';
var elem = document.createElement('div'), timer, content, error = [];
var filename = e.filename || href;
elem.id = id;
elem.className = "less-error-message";
content = '<h3>' + (e.message || 'There is an error in your .less file') +
'</h3>' + '<p>in <a href="' + filename + '">' + filename + "</a> ";
var errorline = function (e, i, classname) {
if (e.extract[i]) {
error.push(template.replace(/\{line\}/, parseInt(e.line) + (i - 1))
.replace(/\{class\}/, classname)
.replace(/\{content\}/, e.extract[i]));
}
};
if (e.stack) {
content += '<br/>' + e.stack.split('\n').slice(1).join('<br/>');
} else if (e.extract) {
errorline(e, 0, '');
errorline(e, 1, 'line');
errorline(e, 2, '');
content += 'on line ' + e.line + ', column ' + (e.column + 1) + ':</p>' +
'<ul>' + error.join('') + '</ul>';
}
elem.innerHTML = content;
// CSS for error messages
createCSS([
'.less-error-message ul, .less-error-message li {',
'list-style-type: none;',
'margin-right: 15px;',
'padding: 4px 0;',
'margin: 0;',
'}',
'.less-error-message label {',
'font-size: 12px;',
'margin-right: 15px;',
'padding: 4px 0;',
'color: #cc7777;',
'}',
'.less-error-message pre {',
'color: #dd6666;',
'padding: 4px 0;',
'margin: 0;',
'display: inline-block;',
'}',
'.less-error-message pre.line {',
'color: #ff0000;',
'}',
'.less-error-message h3 {',
'font-size: 20px;',
'font-weight: bold;',
'padding: 15px 0 5px 0;',
'margin: 0;',
'}',
'.less-error-message a {',
'color: #10a',
'}',
'.less-error-message .error {',
'color: red;',
'font-weight: bold;',
'padding-bottom: 2px;',
'border-bottom: 1px dashed red;',
'}'
].join('\n'), { title: 'error-message' });
elem.style.cssText = [
"font-family: Arial, sans-serif",
"border: 1px solid #e00",
"background-color: #eee",
"border-radius: 5px",
"-webkit-border-radius: 5px",
"-moz-border-radius: 5px",
"color: #e00",
"padding: 15px",
"margin-bottom: 15px"
].join(';');
if (less.env == 'development') {
timer = setInterval(function () {
if (document.body) {
if (document.getElementById(id)) {
document.body.replaceChild(elem, document.getElementById(id));
} else {
document.body.insertBefore(elem, document.body.firstChild);
}
clearInterval(timer);
}
}, 10);
}
}

View File

@@ -0,0 +1,151 @@
(function (tree) {
tree.colors = {
'aliceblue':'#f0f8ff',
'antiquewhite':'#faebd7',
'aqua':'#00ffff',
'aquamarine':'#7fffd4',
'azure':'#f0ffff',
'beige':'#f5f5dc',
'bisque':'#ffe4c4',
'black':'#000000',
'blanchedalmond':'#ffebcd',
'blue':'#0000ff',
'blueviolet':'#8a2be2',
'brown':'#a52a2a',
'burlywood':'#deb887',
'cadetblue':'#5f9ea0',
'chartreuse':'#7fff00',
'chocolate':'#d2691e',
'coral':'#ff7f50',
'cornflowerblue':'#6495ed',
'cornsilk':'#fff8dc',
'crimson':'#dc143c',
'cyan':'#00ffff',
'darkblue':'#00008b',
'darkcyan':'#008b8b',
'darkgoldenrod':'#b8860b',
'darkgray':'#a9a9a9',
'darkgrey':'#a9a9a9',
'darkgreen':'#006400',
'darkkhaki':'#bdb76b',
'darkmagenta':'#8b008b',
'darkolivegreen':'#556b2f',
'darkorange':'#ff8c00',
'darkorchid':'#9932cc',
'darkred':'#8b0000',
'darksalmon':'#e9967a',
'darkseagreen':'#8fbc8f',
'darkslateblue':'#483d8b',
'darkslategray':'#2f4f4f',
'darkslategrey':'#2f4f4f',
'darkturquoise':'#00ced1',
'darkviolet':'#9400d3',
'deeppink':'#ff1493',
'deepskyblue':'#00bfff',
'dimgray':'#696969',
'dimgrey':'#696969',
'dodgerblue':'#1e90ff',
'firebrick':'#b22222',
'floralwhite':'#fffaf0',
'forestgreen':'#228b22',
'fuchsia':'#ff00ff',
'gainsboro':'#dcdcdc',
'ghostwhite':'#f8f8ff',
'gold':'#ffd700',
'goldenrod':'#daa520',
'gray':'#808080',
'grey':'#808080',
'green':'#008000',
'greenyellow':'#adff2f',
'honeydew':'#f0fff0',
'hotpink':'#ff69b4',
'indianred':'#cd5c5c',
'indigo':'#4b0082',
'ivory':'#fffff0',
'khaki':'#f0e68c',
'lavender':'#e6e6fa',
'lavenderblush':'#fff0f5',
'lawngreen':'#7cfc00',
'lemonchiffon':'#fffacd',
'lightblue':'#add8e6',
'lightcoral':'#f08080',
'lightcyan':'#e0ffff',
'lightgoldenrodyellow':'#fafad2',
'lightgray':'#d3d3d3',
'lightgrey':'#d3d3d3',
'lightgreen':'#90ee90',
'lightpink':'#ffb6c1',
'lightsalmon':'#ffa07a',
'lightseagreen':'#20b2aa',
'lightskyblue':'#87cefa',
'lightslategray':'#778899',
'lightslategrey':'#778899',
'lightsteelblue':'#b0c4de',
'lightyellow':'#ffffe0',
'lime':'#00ff00',
'limegreen':'#32cd32',
'linen':'#faf0e6',
'magenta':'#ff00ff',
'maroon':'#800000',
'mediumaquamarine':'#66cdaa',
'mediumblue':'#0000cd',
'mediumorchid':'#ba55d3',
'mediumpurple':'#9370d8',
'mediumseagreen':'#3cb371',
'mediumslateblue':'#7b68ee',
'mediumspringgreen':'#00fa9a',
'mediumturquoise':'#48d1cc',
'mediumvioletred':'#c71585',
'midnightblue':'#191970',
'mintcream':'#f5fffa',
'mistyrose':'#ffe4e1',
'moccasin':'#ffe4b5',
'navajowhite':'#ffdead',
'navy':'#000080',
'oldlace':'#fdf5e6',
'olive':'#808000',
'olivedrab':'#6b8e23',
'orange':'#ffa500',
'orangered':'#ff4500',
'orchid':'#da70d6',
'palegoldenrod':'#eee8aa',
'palegreen':'#98fb98',
'paleturquoise':'#afeeee',
'palevioletred':'#d87093',
'papayawhip':'#ffefd5',
'peachpuff':'#ffdab9',
'peru':'#cd853f',
'pink':'#ffc0cb',
'plum':'#dda0dd',
'powderblue':'#b0e0e6',
'purple':'#800080',
'red':'#ff0000',
'rosybrown':'#bc8f8f',
'royalblue':'#4169e1',
'saddlebrown':'#8b4513',
'salmon':'#fa8072',
'sandybrown':'#f4a460',
'seagreen':'#2e8b57',
'seashell':'#fff5ee',
'sienna':'#a0522d',
'silver':'#c0c0c0',
'skyblue':'#87ceeb',
'slateblue':'#6a5acd',
'slategray':'#708090',
'slategrey':'#708090',
'snow':'#fffafa',
'springgreen':'#00ff7f',
'steelblue':'#4682b4',
'tan':'#d2b48c',
'teal':'#008080',
'thistle':'#d8bfd8',
'tomato':'#ff6347',
'turquoise':'#40e0d0',
'violet':'#ee82ee',
'wheat':'#f5deb3',
'white':'#ffffff',
'whitesmoke':'#f5f5f5',
'yellow':'#ffff00',
'yellowgreen':'#9acd32'
};
})(require('./tree'));

View File

@@ -0,0 +1,355 @@
/**
* cssmin.js
* Author: Stoyan Stefanov - http://phpied.com/
* This is a JavaScript port of the CSS minification tool
* distributed with YUICompressor, itself a port
* of the cssmin utility by Isaac Schlueter - http://foohack.com/
* Permission is hereby granted to use the JavaScript version under the same
* conditions as the YUICompressor (original YUICompressor note below).
*/
/*
* YUI Compressor
* http://developer.yahoo.com/yui/compressor/
* Author: Julien Lecomte - http://www.julienlecomte.net/
* Copyright (c) 2011 Yahoo! Inc. All rights reserved.
* The copyrights embodied in the content of this file are licensed
* by Yahoo! Inc. under the BSD (revised) open source license.
*/
var YAHOO = YAHOO || {};
YAHOO.compressor = YAHOO.compressor || {};
/**
* Utility method to replace all data urls with tokens before we start
* compressing, to avoid performance issues running some of the subsequent
* regexes against large strings chunks.
*
* @private
* @method _extractDataUrls
* @param {String} css The input css
* @param {Array} The global array of tokens to preserve
* @returns String The processed css
*/
YAHOO.compressor._extractDataUrls = function (css, preservedTokens) {
// Leave data urls alone to increase parse performance.
var maxIndex = css.length - 1,
appendIndex = 0,
startIndex,
endIndex,
terminator,
foundTerminator,
sb = [],
m,
preserver,
token,
pattern = /url\(\s*(["']?)data\:/g;
// Since we need to account for non-base64 data urls, we need to handle
// ' and ) being part of the data string. Hence switching to indexOf,
// to determine whether or not we have matching string terminators and
// handling sb appends directly, instead of using matcher.append* methods.
while ((m = pattern.exec(css)) !== null) {
startIndex = m.index + 4; // "url(".length()
terminator = m[1]; // ', " or empty (not quoted)
if (terminator.length === 0) {
terminator = ")";
}
foundTerminator = false;
endIndex = pattern.lastIndex - 1;
while(foundTerminator === false && endIndex+1 <= maxIndex) {
endIndex = css.indexOf(terminator, endIndex + 1);
// endIndex == 0 doesn't really apply here
if ((endIndex > 0) && (css.charAt(endIndex - 1) !== '\\')) {
foundTerminator = true;
if (")" != terminator) {
endIndex = css.indexOf(")", endIndex);
}
}
}
// Enough searching, start moving stuff over to the buffer
sb.push(css.substring(appendIndex, m.index));
if (foundTerminator) {
token = css.substring(startIndex, endIndex);
token = token.replace(/\s+/g, "");
preservedTokens.push(token);
preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___)";
sb.push(preserver);
appendIndex = endIndex + 1;
} else {
// No end terminator found, re-add the whole match. Should we throw/warn here?
sb.push(css.substring(m.index, pattern.lastIndex));
appendIndex = pattern.lastIndex;
}
}
sb.push(css.substring(appendIndex));
return sb.join("");
};
/**
* Utility method to compress hex color values of the form #AABBCC to #ABC.
*
* DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
* e.g. #AddressForm { ... }
*
* DOES NOT compress IE filters, which have hex color values (which would break things).
* e.g. filter: chroma(color="#FFFFFF");
*
* DOES NOT compress invalid hex values.
* e.g. background-color: #aabbccdd
*
* @private
* @method _compressHexColors
* @param {String} css The input css
* @returns String The processed css
*/
YAHOO.compressor._compressHexColors = function(css) {
// Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
var pattern = /(\=\s*?["']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/gi,
m,
index = 0,
isFilter,
sb = [];
while ((m = pattern.exec(css)) !== null) {
sb.push(css.substring(index, m.index));
isFilter = m[1];
if (isFilter) {
// Restore, maintain case, otherwise filter will break
sb.push(m[1] + "#" + (m[2] + m[3] + m[4] + m[5] + m[6] + m[7]));
} else {
if (m[2].toLowerCase() == m[3].toLowerCase() &&
m[4].toLowerCase() == m[5].toLowerCase() &&
m[6].toLowerCase() == m[7].toLowerCase()) {
// Compress.
sb.push("#" + (m[3] + m[5] + m[7]).toLowerCase());
} else {
// Non compressible color, restore but lower case.
sb.push("#" + (m[2] + m[3] + m[4] + m[5] + m[6] + m[7]).toLowerCase());
}
}
index = pattern.lastIndex = pattern.lastIndex - m[8].length;
}
sb.push(css.substring(index));
return sb.join("");
};
YAHOO.compressor.cssmin = function (css, linebreakpos) {
var startIndex = 0,
endIndex = 0,
i = 0, max = 0,
preservedTokens = [],
comments = [],
token = '',
totallen = css.length,
placeholder = '';
css = this._extractDataUrls(css, preservedTokens);
// collect all comment blocks...
while ((startIndex = css.indexOf("/*", startIndex)) >= 0) {
endIndex = css.indexOf("*/", startIndex + 2);
if (endIndex < 0) {
endIndex = totallen;
}
token = css.slice(startIndex + 2, endIndex);
comments.push(token);
css = css.slice(0, startIndex + 2) + "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + (comments.length - 1) + "___" + css.slice(endIndex);
startIndex += 2;
}
// preserve strings so their content doesn't get accidentally minified
css = css.replace(/("([^\\"]|\\.|\\)*")|('([^\\']|\\.|\\)*')/g, function (match) {
var i, max, quote = match.substring(0, 1);
match = match.slice(1, -1);
// maybe the string contains a comment-like substring?
// one, maybe more? put'em back then
if (match.indexOf("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_") >= 0) {
for (i = 0, max = comments.length; i < max; i = i + 1) {
match = match.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", comments[i]);
}
}
// minify alpha opacity in filter strings
match = match.replace(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/gi, "alpha(opacity=");
preservedTokens.push(match);
return quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___" + quote;
});
// strings are safe, now wrestle the comments
for (i = 0, max = comments.length; i < max; i = i + 1) {
token = comments[i];
placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___";
// ! in the first position of the comment means preserve
// so push to the preserved tokens keeping the !
if (token.charAt(0) === "!") {
preservedTokens.push(token);
css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
continue;
}
// \ in the last position looks like hack for Mac/IE5
// shorten that to /*\*/ and the next one to /**/
if (token.charAt(token.length - 1) === "\\") {
preservedTokens.push("\\");
css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
i = i + 1; // attn: advancing the loop
preservedTokens.push("");
css = css.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
continue;
}
// keep empty comments after child selectors (IE7 hack)
// e.g. html >/**/ body
if (token.length === 0) {
startIndex = css.indexOf(placeholder);
if (startIndex > 2) {
if (css.charAt(startIndex - 3) === '>') {
preservedTokens.push("");
css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.length - 1) + "___");
}
}
}
// in all other cases kill the comment
css = css.replace("/*" + placeholder + "*/", "");
}
// Normalize all whitespace strings to single spaces. Easier to work with that way.
css = css.replace(/\s+/g, " ");
// Remove the spaces before the things that should not have spaces before them.
// But, be careful not to turn "p :link {...}" into "p:link{...}"
// Swap out any pseudo-class colons with the token, and then swap back.
css = css.replace(/(^|\})(([^\{:])+:)+([^\{]*\{)/g, function (m) {
return m.replace(":", "___YUICSSMIN_PSEUDOCLASSCOLON___");
});
css = css.replace(/\s+([!{};:>+\(\)\],])/g, '$1');
css = css.replace(/___YUICSSMIN_PSEUDOCLASSCOLON___/g, ":");
// retain space for special IE6 cases
css = css.replace(/:first-(line|letter)(\{|,)/g, ":first-$1 $2");
// no space after the end of a preserved comment
css = css.replace(/\*\/ /g, '*/');
// If there is a @charset, then only allow one, and push to the top of the file.
css = css.replace(/^(.*)(@charset "[^"]*";)/gi, '$2$1');
css = css.replace(/^(\s*@charset [^;]+;\s*)+/gi, '$1');
// Put the space back in some cases, to support stuff like
// @media screen and (-webkit-min-device-pixel-ratio:0){
css = css.replace(/\band\(/gi, "and (");
// Remove the spaces after the things that should not have spaces after them.
css = css.replace(/([!{}:;>+\(\[,])\s+/g, '$1');
// remove unnecessary semicolons
css = css.replace(/;+\}/g, "}");
// Replace 0(px,em,%) with 0.
css = css.replace(/([\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)/gi, "$1$2");
// Replace 0 0 0 0; with 0.
css = css.replace(/:0 0 0 0(;|\})/g, ":0$1");
css = css.replace(/:0 0 0(;|\})/g, ":0$1");
css = css.replace(/:0 0(;|\})/g, ":0$1");
// Replace background-position:0; with background-position:0 0;
// same for transform-origin
css = css.replace(/(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|\})/gi, function(all, prop, tail) {
return prop.toLowerCase() + ":0 0" + tail;
});
// Replace 0.6 to .6, but only when preceded by : or a white-space
css = css.replace(/(:|\s)0+\.(\d+)/g, "$1.$2");
// Shorten colors from rgb(51,102,153) to #336699
// This makes it more likely that it'll get further compressed in the next step.
css = css.replace(/rgb\s*\(\s*([0-9,\s]+)\s*\)/gi, function () {
var i, rgbcolors = arguments[1].split(',');
for (i = 0; i < rgbcolors.length; i = i + 1) {
rgbcolors[i] = parseInt(rgbcolors[i], 10).toString(16);
if (rgbcolors[i].length === 1) {
rgbcolors[i] = '0' + rgbcolors[i];
}
}
return '#' + rgbcolors.join('');
});
// Shorten colors from #AABBCC to #ABC.
css = this._compressHexColors(css);
// border: none -> border:0
css = css.replace(/(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|\})/gi, function(all, prop, tail) {
return prop.toLowerCase() + ":0" + tail;
});
// shorter opacity IE filter
css = css.replace(/progid:DXImageTransform\.Microsoft\.Alpha\(Opacity=/gi, "alpha(opacity=");
// Remove empty rules.
css = css.replace(/[^\};\{\/]+\{\}/g, "");
if (linebreakpos >= 0) {
// Some source control tools don't like it when files containing lines longer
// than, say 8000 characters, are checked in. The linebreak option is used in
// that case to split long lines after a specific column.
startIndex = 0;
i = 0;
while (i < css.length) {
i = i + 1;
if (css[i - 1] === '}' && i - startIndex > linebreakpos) {
css = css.slice(0, i) + '\n' + css.slice(i);
startIndex = i;
}
}
}
// Replace multiple semi-colons in a row by a single one
// See SF bug #1980989
css = css.replace(/;;+/g, ";");
// restore preserved comments and strings
for (i = 0, max = preservedTokens.length; i < max; i = i + 1) {
css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens[i]);
}
// Trim the final string (for any leading or trailing white spaces)
css = css.replace(/^\s+|\s+$/g, "");
return css;
};
exports.compressor = YAHOO.compressor;

View File

@@ -0,0 +1,228 @@
(function (tree) {
tree.functions = {
rgb: function (r, g, b) {
return this.rgba(r, g, b, 1.0);
},
rgba: function (r, g, b, a) {
var rgb = [r, g, b].map(function (c) { return number(c) }),
a = number(a);
return new(tree.Color)(rgb, a);
},
hsl: function (h, s, l) {
return this.hsla(h, s, l, 1.0);
},
hsla: function (h, s, l, a) {
h = (number(h) % 360) / 360;
s = number(s); l = number(l); a = number(a);
var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
var m1 = l * 2 - m2;
return this.rgba(hue(h + 1/3) * 255,
hue(h) * 255,
hue(h - 1/3) * 255,
a);
function hue(h) {
h = h < 0 ? h + 1 : (h > 1 ? h - 1 : h);
if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
else if (h * 2 < 1) return m2;
else if (h * 3 < 2) return m1 + (m2 - m1) * (2/3 - h) * 6;
else return m1;
}
},
hue: function (color) {
return new(tree.Dimension)(Math.round(color.toHSL().h));
},
saturation: function (color) {
return new(tree.Dimension)(Math.round(color.toHSL().s * 100), '%');
},
lightness: function (color) {
return new(tree.Dimension)(Math.round(color.toHSL().l * 100), '%');
},
alpha: function (color) {
return new(tree.Dimension)(color.toHSL().a);
},
saturate: function (color, amount) {
var hsl = color.toHSL();
hsl.s += amount.value / 100;
hsl.s = clamp(hsl.s);
return hsla(hsl);
},
desaturate: function (color, amount) {
var hsl = color.toHSL();
hsl.s -= amount.value / 100;
hsl.s = clamp(hsl.s);
return hsla(hsl);
},
lighten: function (color, amount) {
var hsl = color.toHSL();
hsl.l += amount.value / 100;
hsl.l = clamp(hsl.l);
return hsla(hsl);
},
darken: function (color, amount) {
var hsl = color.toHSL();
hsl.l -= amount.value / 100;
hsl.l = clamp(hsl.l);
return hsla(hsl);
},
fadein: function (color, amount) {
var hsl = color.toHSL();
hsl.a += amount.value / 100;
hsl.a = clamp(hsl.a);
return hsla(hsl);
},
fadeout: function (color, amount) {
var hsl = color.toHSL();
hsl.a -= amount.value / 100;
hsl.a = clamp(hsl.a);
return hsla(hsl);
},
fade: function (color, amount) {
var hsl = color.toHSL();
hsl.a = amount.value / 100;
hsl.a = clamp(hsl.a);
return hsla(hsl);
},
spin: function (color, amount) {
var hsl = color.toHSL();
var hue = (hsl.h + amount.value) % 360;
hsl.h = hue < 0 ? 360 + hue : hue;
return hsla(hsl);
},
//
// Copyright (c) 2006-2009 Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein
// http://sass-lang.com
//
mix: function (color1, color2, weight) {
var p = weight.value / 100.0;
var w = p * 2 - 1;
var a = color1.toHSL().a - color2.toHSL().a;
var w1 = (((w * a == -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
var w2 = 1 - w1;
var rgb = [color1.rgb[0] * w1 + color2.rgb[0] * w2,
color1.rgb[1] * w1 + color2.rgb[1] * w2,
color1.rgb[2] * w1 + color2.rgb[2] * w2];
var alpha = color1.alpha * p + color2.alpha * (1 - p);
return new(tree.Color)(rgb, alpha);
},
greyscale: function (color) {
return this.desaturate(color, new(tree.Dimension)(100));
},
e: function (str) {
return new(tree.Anonymous)(str instanceof tree.JavaScript ? str.evaluated : str);
},
escape: function (str) {
return new(tree.Anonymous)(encodeURI(str.value).replace(/=/g, "%3D").replace(/:/g, "%3A").replace(/#/g, "%23").replace(/;/g, "%3B").replace(/\(/g, "%28").replace(/\)/g, "%29"));
},
'%': function (quoted /* arg, arg, ...*/) {
var args = Array.prototype.slice.call(arguments, 1),
str = quoted.value;
for (var i = 0; i < args.length; i++) {
str = str.replace(/%[sda]/i, function(token) {
var value = token.match(/s/i) ? args[i].value : args[i].toCSS();
return token.match(/[A-Z]$/) ? encodeURIComponent(value) : value;
});
}
str = str.replace(/%%/g, '%');
return new(tree.Quoted)('"' + str + '"', str);
},
round: function (n) {
return this._math('round', n);
},
ceil: function (n) {
return this._math('ceil', n);
},
floor: function (n) {
return this._math('floor', n);
},
_math: function (fn, n) {
if (n instanceof tree.Dimension) {
return new(tree.Dimension)(Math[fn](number(n)), n.unit);
} else if (typeof(n) === 'number') {
return Math[fn](n);
} else {
throw { type: "Argument", message: "argument must be a number" };
}
},
argb: function (color) {
return new(tree.Anonymous)(color.toARGB());
},
percentage: function (n) {
return new(tree.Dimension)(n.value * 100, '%');
},
color: function (n) {
if (n instanceof tree.Quoted) {
return new(tree.Color)(n.value.slice(1));
} else {
throw { type: "Argument", message: "argument must be a string" };
}
},
iscolor: function (n) {
return this._isa(n, tree.Color);
},
isnumber: function (n) {
return this._isa(n, tree.Dimension);
},
isstring: function (n) {
return this._isa(n, tree.Quoted);
},
iskeyword: function (n) {
return this._isa(n, tree.Keyword);
},
isurl: function (n) {
return this._isa(n, tree.URL);
},
ispixel: function (n) {
return (n instanceof tree.Dimension) && n.unit === 'px' ? tree.True : tree.False;
},
ispercentage: function (n) {
return (n instanceof tree.Dimension) && n.unit === '%' ? tree.True : tree.False;
},
isem: function (n) {
return (n instanceof tree.Dimension) && n.unit === 'em' ? tree.True : tree.False;
},
_isa: function (n, Type) {
return (n instanceof Type) ? tree.True : tree.False;
}
};
function hsla(hsla) {
return tree.functions.hsla(hsla.h, hsla.s, hsla.l, hsla.a);
}
function number(n) {
if (n instanceof tree.Dimension) {
return parseFloat(n.unit == '%' ? n.value / 100 : n.value);
} else if (typeof(n) === 'number') {
return n;
} else {
throw {
error: "RuntimeError",
message: "color functions take numbers as parameters"
};
}
}
function clamp(val) {
return Math.min(1, Math.max(0, val));
}
})(require('./tree'));

View File

@@ -0,0 +1,148 @@
var path = require('path'),
sys = require('util'),
fs = require('fs');
var less = {
version: [1, 3, 0],
Parser: require('./parser').Parser,
importer: require('./parser').importer,
tree: require('./tree'),
render: function (input, options, callback) {
options = options || {};
if (typeof(options) === 'function') {
callback = options, options = {};
}
var parser = new(less.Parser)(options),
ee;
if (callback) {
parser.parse(input, function (e, root) {
callback(e, root && root.toCSS && root.toCSS(options));
});
} else {
ee = new(require('events').EventEmitter);
process.nextTick(function () {
parser.parse(input, function (e, root) {
if (e) { ee.emit('error', e) }
else { ee.emit('success', root.toCSS(options)) }
});
});
return ee;
}
},
writeError: function (ctx, options) {
options = options || {};
var message = "";
var extract = ctx.extract;
var error = [];
var stylize = options.color ? less.stylize : function (str) { return str };
if (options.silent) { return }
if (ctx.stack) { return sys.error(stylize(ctx.stack, 'red')) }
if (!ctx.hasOwnProperty('index')) {
return sys.error(ctx.stack || ctx.message);
}
if (typeof(extract[0]) === 'string') {
error.push(stylize((ctx.line - 1) + ' ' + extract[0], 'grey'));
}
if (extract[1]) {
error.push(ctx.line + ' ' + extract[1].slice(0, ctx.column)
+ stylize(stylize(stylize(extract[1][ctx.column], 'bold')
+ extract[1].slice(ctx.column + 1), 'red'), 'inverse'));
}
if (typeof(extract[2]) === 'string') {
error.push(stylize((ctx.line + 1) + ' ' + extract[2], 'grey'));
}
error = error.join('\n') + '\033[0m\n';
message += stylize(ctx.type + 'Error: ' + ctx.message, 'red');
ctx.filename && (message += stylize(' in ', 'red') + ctx.filename +
stylize(':' + ctx.line + ':' + ctx.column, 'grey'));
sys.error(message, error);
if (ctx.callLine) {
sys.error(stylize('from ', 'red') + (ctx.filename || ''));
sys.error(stylize(ctx.callLine, 'grey') + ' ' + ctx.callExtract);
}
}
};
['color', 'directive', 'operation', 'dimension',
'keyword', 'variable', 'ruleset', 'element',
'selector', 'quoted', 'expression', 'rule',
'call', 'url', 'alpha', 'import',
'mixin', 'comment', 'anonymous', 'value',
'javascript', 'assignment', 'condition', 'paren',
'media'
].forEach(function (n) {
require('./tree/' + n);
});
less.Parser.importer = function (file, paths, callback, env) {
var pathname;
// TODO: Undo this at some point,
// or use different approach.
paths.unshift('.');
for (var i = 0; i < paths.length; i++) {
try {
pathname = path.join(paths[i], file);
fs.statSync(pathname);
break;
} catch (e) {
pathname = null;
}
}
if (pathname) {
fs.readFile(pathname, 'utf-8', function(e, data) {
if (e) return callback(e);
new(less.Parser)({
paths: [path.dirname(pathname)].concat(paths),
filename: pathname
}).parse(data, function (e, root) {
callback(e, root, data);
});
});
} else {
if (typeof(env.errback) === "function") {
env.errback(file, paths, callback);
} else {
callback({ type: 'File', message: "'" + file + "' wasn't found.\n" });
}
}
}
require('./functions');
require('./colors');
for (var k in less) { exports[k] = less[k] }
// Stylize a string
function stylize(str, style) {
var styles = {
'bold' : [1, 22],
'inverse' : [7, 27],
'underline' : [4, 24],
'yellow' : [33, 39],
'green' : [32, 39],
'red' : [31, 39],
'grey' : [90, 39]
};
return '\033[' + styles[style][0] + 'm' + str +
'\033[' + styles[style][1] + 'm';
}
less.stylize = stylize;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,62 @@
var name;
function loadStyleSheet(sheet, callback, reload, remaining) {
var sheetName = name.slice(0, name.lastIndexOf('/') + 1) + sheet.href;
var input = readFile(sheetName);
var parser = new less.Parser({
paths: [sheet.href.replace(/[\w\.-]+$/, '')]
});
parser.parse(input, function (e, root) {
if (e) {
print("Error: " + e);
quit(1);
}
callback(root, sheet, { local: false, lastModified: 0, remaining: remaining });
});
// callback({}, sheet, { local: true, remaining: remaining });
}
function writeFile(filename, content) {
var fstream = new java.io.FileWriter(filename);
var out = new java.io.BufferedWriter(fstream);
out.write(content);
out.close();
}
// Command line integration via Rhino
(function (args) {
name = args[0];
var output = args[1];
if (!name) {
print('No files present in the fileset; Check your pattern match in build.xml');
quit(1);
}
path = name.split("/");path.pop();path=path.join("/")
var input = readFile(name);
if (!input) {
print('lesscss: couldn\'t open file ' + name);
quit(1);
}
var result;
var parser = new less.Parser();
parser.parse(input, function (e, root) {
if (e) {
quit(1);
} else {
result = root.toCSS();
if (output) {
writeFile(output, result);
print("Written to " + output);
} else {
print(result);
}
quit(0);
}
});
print("done");
}(arguments));

View File

@@ -0,0 +1,17 @@
(function (tree) {
tree.find = function (obj, fun) {
for (var i = 0, r; i < obj.length; i++) {
if (r = fun.call(obj, obj[i])) { return r }
}
return null;
};
tree.jsify = function (obj) {
if (Array.isArray(obj.value) && (obj.value.length > 1)) {
return '[' + obj.value.map(function (v) { return v.toCSS(false) }).join(', ') + ']';
} else {
return obj.toCSS(false);
}
};
})(require('./tree'));

View File

@@ -0,0 +1,17 @@
(function (tree) {
tree.Alpha = function (val) {
this.value = val;
};
tree.Alpha.prototype = {
toCSS: function () {
return "alpha(opacity=" +
(this.value.toCSS ? this.value.toCSS() : this.value) + ")";
},
eval: function (env) {
if (this.value.eval) { this.value = this.value.eval(env) }
return this;
}
};
})(require('../tree'));

View File

@@ -0,0 +1,13 @@
(function (tree) {
tree.Anonymous = function (string) {
this.value = string.value || string;
};
tree.Anonymous.prototype = {
toCSS: function () {
return this.value;
},
eval: function () { return this }
};
})(require('../tree'));

View File

@@ -0,0 +1,17 @@
(function (tree) {
tree.Assignment = function (key, val) {
this.key = key;
this.value = val;
};
tree.Assignment.prototype = {
toCSS: function () {
return this.key + '=' + (this.value.toCSS ? this.value.toCSS() : this.value);
},
eval: function (env) {
if (this.value.eval) { this.value = this.value.eval(env) }
return this;
}
};
})(require('../tree'));

View File

@@ -0,0 +1,48 @@
(function (tree) {
//
// A function call node.
//
tree.Call = function (name, args, index, filename) {
this.name = name;
this.args = args;
this.index = index;
this.filename = filename;
};
tree.Call.prototype = {
//
// When evaluating a function call,
// we either find the function in `tree.functions` [1],
// in which case we call it, passing the evaluated arguments,
// or we simply print it out as it appeared originally [2].
//
// The *functions.js* file contains the built-in functions.
//
// The reason why we evaluate the arguments, is in the case where
// we try to pass a variable to a function, like: `saturate(@color)`.
// The function should receive the value, not the variable.
//
eval: function (env) {
var args = this.args.map(function (a) { return a.eval(env) });
if (this.name in tree.functions) { // 1.
try {
return tree.functions[this.name].apply(tree.functions, args);
} catch (e) {
throw { type: e.type || "Runtime",
message: "error evaluating function `" + this.name + "`" +
(e.message ? ': ' + e.message : ''),
index: this.index, filename: this.filename };
}
} else { // 2.
return new(tree.Anonymous)(this.name +
"(" + args.map(function (a) { return a.toCSS() }).join(', ') + ")");
}
},
toCSS: function (env) {
return this.eval(env).toCSS();
}
};
})(require('../tree'));

View File

@@ -0,0 +1,101 @@
(function (tree) {
//
// RGB Colors - #ff0014, #eee
//
tree.Color = function (rgb, a) {
//
// The end goal here, is to parse the arguments
// into an integer triplet, such as `128, 255, 0`
//
// This facilitates operations and conversions.
//
if (Array.isArray(rgb)) {
this.rgb = rgb;
} else if (rgb.length == 6) {
this.rgb = rgb.match(/.{2}/g).map(function (c) {
return parseInt(c, 16);
});
} else {
this.rgb = rgb.split('').map(function (c) {
return parseInt(c + c, 16);
});
}
this.alpha = typeof(a) === 'number' ? a : 1;
};
tree.Color.prototype = {
eval: function () { return this },
//
// If we have some transparency, the only way to represent it
// is via `rgba`. Otherwise, we use the hex representation,
// which has better compatibility with older browsers.
// Values are capped between `0` and `255`, rounded and zero-padded.
//
toCSS: function () {
if (this.alpha < 1.0) {
return "rgba(" + this.rgb.map(function (c) {
return Math.round(c);
}).concat(this.alpha).join(', ') + ")";
} else {
return '#' + this.rgb.map(function (i) {
i = Math.round(i);
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
return i.length === 1 ? '0' + i : i;
}).join('');
}
},
//
// Operations have to be done per-channel, if not,
// channels will spill onto each other. Once we have
// our result, in the form of an integer triplet,
// we create a new Color node to hold the result.
//
operate: function (op, other) {
var result = [];
if (! (other instanceof tree.Color)) {
other = other.toColor();
}
for (var c = 0; c < 3; c++) {
result[c] = tree.operate(op, this.rgb[c], other.rgb[c]);
}
return new(tree.Color)(result, this.alpha + other.alpha);
},
toHSL: function () {
var r = this.rgb[0] / 255,
g = this.rgb[1] / 255,
b = this.rgb[2] / 255,
a = this.alpha;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2, d = max - min;
if (max === min) {
h = s = 0;
} else {
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h * 360, s: s, l: l, a: a };
},
toARGB: function () {
var argb = [Math.round(this.alpha * 255)].concat(this.rgb);
return '#' + argb.map(function (i) {
i = Math.round(i);
i = (i > 255 ? 255 : (i < 0 ? 0 : i)).toString(16);
return i.length === 1 ? '0' + i : i;
}).join('');
}
};
})(require('../tree'));

View File

@@ -0,0 +1,14 @@
(function (tree) {
tree.Comment = function (value, silent) {
this.value = value;
this.silent = !!silent;
};
tree.Comment.prototype = {
toCSS: function (env) {
return env.compress ? '' : this.value;
},
eval: function () { return this }
};
})(require('../tree'));

View File

@@ -0,0 +1,42 @@
(function (tree) {
tree.Condition = function (op, l, r, i, negate) {
this.op = op.trim();
this.lvalue = l;
this.rvalue = r;
this.index = i;
this.negate = negate;
};
tree.Condition.prototype.eval = function (env) {
var a = this.lvalue.eval(env),
b = this.rvalue.eval(env);
var i = this.index, result;
var result = (function (op) {
switch (op) {
case 'and':
return a && b;
case 'or':
return a || b;
default:
if (a.compare) {
result = a.compare(b);
} else if (b.compare) {
result = b.compare(a);
} else {
throw { type: "Type",
message: "Unable to perform comparison",
index: i };
}
switch (result) {
case -1: return op === '<' || op === '=<';
case 0: return op === '=' || op === '>=' || op === '=<';
case 1: return op === '>' || op === '>=';
}
}
})(this.op);
return this.negate ? !result : result;
};
})(require('../tree'));

View File

@@ -0,0 +1,49 @@
(function (tree) {
//
// A number with a unit
//
tree.Dimension = function (value, unit) {
this.value = parseFloat(value);
this.unit = unit || null;
};
tree.Dimension.prototype = {
eval: function () { return this },
toColor: function () {
return new(tree.Color)([this.value, this.value, this.value]);
},
toCSS: function () {
var css = this.value + this.unit;
return css;
},
// In an operation between two Dimensions,
// we default to the first Dimension's unit,
// so `1px + 2em` will yield `3px`.
// In the future, we could implement some unit
// conversions such that `100cm + 10mm` would yield
// `101cm`.
operate: function (op, other) {
return new(tree.Dimension)
(tree.operate(op, this.value, other.value),
this.unit || other.unit);
},
// TODO: Perform unit conversion before comparing
compare: function (other) {
if (other instanceof tree.Dimension) {
if (other.value > this.value) {
return -1;
} else if (other.value < this.value) {
return 1;
} else {
return 0;
}
} else {
return -1;
}
}
};
})(require('../tree'));

View File

@@ -0,0 +1,35 @@
(function (tree) {
tree.Directive = function (name, value, features) {
this.name = name;
if (Array.isArray(value)) {
this.ruleset = new(tree.Ruleset)([], value);
this.ruleset.allowImports = true;
} else {
this.value = value;
}
};
tree.Directive.prototype = {
toCSS: function (ctx, env) {
if (this.ruleset) {
this.ruleset.root = true;
return this.name + (env.compress ? '{' : ' {\n ') +
this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
(env.compress ? '}': '\n}\n');
} else {
return this.name + ' ' + this.value.toCSS() + ';\n';
}
},
eval: function (env) {
env.frames.unshift(this);
this.ruleset = this.ruleset && this.ruleset.eval(env);
env.frames.shift();
return this;
},
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) }
};
})(require('../tree'));

View File

@@ -0,0 +1,47 @@
(function (tree) {
tree.Element = function (combinator, value, index) {
this.combinator = combinator instanceof tree.Combinator ?
combinator : new(tree.Combinator)(combinator);
if (typeof(value) === 'string') {
this.value = value.trim();
} else if (value) {
this.value = value;
} else {
this.value = "";
}
this.index = index;
};
tree.Element.prototype.eval = function (env) {
return new(tree.Element)(this.combinator,
this.value.eval ? this.value.eval(env) : this.value,
this.index);
};
tree.Element.prototype.toCSS = function (env) {
return this.combinator.toCSS(env || {}) + (this.value.toCSS ? this.value.toCSS(env) : this.value);
};
tree.Combinator = function (value) {
if (value === ' ') {
this.value = ' ';
} else if (value === '& ') {
this.value = '& ';
} else {
this.value = value ? value.trim() : "";
}
};
tree.Combinator.prototype.toCSS = function (env) {
return {
'' : '',
' ' : ' ',
'&' : '',
'& ' : ' ',
':' : ' :',
'+' : env.compress ? '+' : ' + ',
'~' : env.compress ? '~' : ' ~ ',
'>' : env.compress ? '>' : ' > '
}[this.value];
};
})(require('../tree'));

View File

@@ -0,0 +1,23 @@
(function (tree) {
tree.Expression = function (value) { this.value = value };
tree.Expression.prototype = {
eval: function (env) {
if (this.value.length > 1) {
return new(tree.Expression)(this.value.map(function (e) {
return e.eval(env);
}));
} else if (this.value.length === 1) {
return this.value[0].eval(env);
} else {
return this;
}
},
toCSS: function (env) {
return this.value.map(function (e) {
return e.toCSS ? e.toCSS(env) : '';
}).join(' ');
}
};
})(require('../tree'));

View File

@@ -0,0 +1,79 @@
(function (tree) {
//
// CSS @import node
//
// The general strategy here is that we don't want to wait
// for the parsing to be completed, before we start importing
// the file. That's because in the context of a browser,
// most of the time will be spent waiting for the server to respond.
//
// On creation, we push the import path to our import queue, though
// `import,push`, we also pass it a callback, which it'll call once
// the file has been fetched, and parsed.
//
tree.Import = function (path, imports, features, index) {
var that = this;
this.index = index;
this._path = path;
this.features = features && new(tree.Value)(features);
// The '.less' extension is optional
if (path instanceof tree.Quoted) {
this.path = /\.(le?|c)ss(\?.*)?$/.test(path.value) ? path.value : path.value + '.less';
} else {
this.path = path.value.value || path.value;
}
this.css = /css(\?.*)?$/.test(this.path);
// Only pre-compile .less files
if (! this.css) {
imports.push(this.path, function (e, root) {
if (e) { e.index = index }
that.root = root || new(tree.Ruleset)([], []);
});
}
};
//
// The actual import node doesn't return anything, when converted to CSS.
// The reason is that it's used at the evaluation stage, so that the rules
// it imports can be treated like any other rules.
//
// In `eval`, we make sure all Import nodes get evaluated, recursively, so
// we end up with a flat structure, which can easily be imported in the parent
// ruleset.
//
tree.Import.prototype = {
toCSS: function (env) {
var features = this.features ? ' ' + this.features.toCSS(env) : '';
if (this.css) {
return "@import " + this._path.toCSS() + features + ';\n';
} else {
return "";
}
},
eval: function (env) {
var ruleset, features = this.features && this.features.eval(env);
if (this.css) {
return this;
} else {
ruleset = new(tree.Ruleset)([], this.root.rules.slice(0));
for (var i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.Import) {
Array.prototype
.splice
.apply(ruleset.rules,
[i, 1].concat(ruleset.rules[i].eval(env)));
}
}
return this.features ? new(tree.Media)(ruleset.rules, this.features.value) : ruleset.rules;
}
}
};
})(require('../tree'));

View File

@@ -0,0 +1,51 @@
(function (tree) {
tree.JavaScript = function (string, index, escaped) {
this.escaped = escaped;
this.expression = string;
this.index = index;
};
tree.JavaScript.prototype = {
eval: function (env) {
var result,
that = this,
context = {};
var expression = this.expression.replace(/@\{([\w-]+)\}/g, function (_, name) {
return tree.jsify(new(tree.Variable)('@' + name, that.index).eval(env));
});
try {
expression = new(Function)('return (' + expression + ')');
} catch (e) {
throw { message: "JavaScript evaluation error: `" + expression + "`" ,
index: this.index };
}
for (var k in env.frames[0].variables()) {
context[k.slice(1)] = {
value: env.frames[0].variables()[k].value,
toJS: function () {
return this.value.eval(env).toCSS();
}
};
}
try {
result = expression.call(context);
} catch (e) {
throw { message: "JavaScript evaluation error: '" + e.name + ': ' + e.message + "'" ,
index: this.index };
}
if (typeof(result) === 'string') {
return new(tree.Quoted)('"' + result + '"', result, this.escaped, this.index);
} else if (Array.isArray(result)) {
return new(tree.Anonymous)(result.join(', '));
} else {
return new(tree.Anonymous)(result);
}
}
};
})(require('../tree'));

View File

@@ -0,0 +1,19 @@
(function (tree) {
tree.Keyword = function (value) { this.value = value };
tree.Keyword.prototype = {
eval: function () { return this },
toCSS: function () { return this.value },
compare: function (other) {
if (other instanceof tree.Keyword) {
return other.value === this.value ? 0 : 1;
} else {
return -1;
}
}
};
tree.True = new(tree.Keyword)('true');
tree.False = new(tree.Keyword)('false');
})(require('../tree'));

View File

@@ -0,0 +1,114 @@
(function (tree) {
tree.Media = function (value, features) {
var el = new(tree.Element)('&', null, 0),
selectors = [new(tree.Selector)([el])];
this.features = new(tree.Value)(features);
this.ruleset = new(tree.Ruleset)(selectors, value);
this.ruleset.allowImports = true;
};
tree.Media.prototype = {
toCSS: function (ctx, env) {
var features = this.features.toCSS(env);
this.ruleset.root = (ctx.length === 0 || ctx[0].multiMedia);
return '@media ' + features + (env.compress ? '{' : ' {\n ') +
this.ruleset.toCSS(ctx, env).trim().replace(/\n/g, '\n ') +
(env.compress ? '}': '\n}\n');
},
eval: function (env) {
if (!env.mediaBlocks) {
env.mediaBlocks = [];
env.mediaPath = [];
}
var blockIndex = env.mediaBlocks.length;
env.mediaPath.push(this);
env.mediaBlocks.push(this);
var media = new(tree.Media)([], []);
media.features = this.features.eval(env);
env.frames.unshift(this.ruleset);
media.ruleset = this.ruleset.eval(env);
env.frames.shift();
env.mediaBlocks[blockIndex] = media;
env.mediaPath.pop();
return env.mediaPath.length === 0 ? media.evalTop(env) :
media.evalNested(env)
},
variable: function (name) { return tree.Ruleset.prototype.variable.call(this.ruleset, name) },
find: function () { return tree.Ruleset.prototype.find.apply(this.ruleset, arguments) },
rulesets: function () { return tree.Ruleset.prototype.rulesets.apply(this.ruleset) },
evalTop: function (env) {
var result = this;
// Render all dependent Media blocks.
if (env.mediaBlocks.length > 1) {
var el = new(tree.Element)('&', null, 0);
var selectors = [new(tree.Selector)([el])];
result = new(tree.Ruleset)(selectors, env.mediaBlocks);
result.multiMedia = true;
}
delete env.mediaBlocks;
delete env.mediaPath;
return result;
},
evalNested: function (env) {
var i, value,
path = env.mediaPath.concat([this]);
// Extract the media-query conditions separated with `,` (OR).
for (i = 0; i < path.length; i++) {
value = path[i].features instanceof tree.Value ?
path[i].features.value : path[i].features;
path[i] = Array.isArray(value) ? value : [value];
}
// Trace all permutations to generate the resulting media-query.
//
// (a, b and c) with nested (d, e) ->
// a and d
// a and e
// b and c and d
// b and c and e
this.features = new(tree.Value)(this.permute(path).map(function (path) {
path = path.map(function (fragment) {
return fragment.toCSS ? fragment : new(tree.Anonymous)(fragment);
});
for(i = path.length - 1; i > 0; i--) {
path.splice(i, 0, new(tree.Anonymous)("and"));
}
return new(tree.Expression)(path);
}));
// Fake a tree-node that doesn't output anything.
return new(tree.Ruleset)([], []);
},
permute: function (arr) {
if (arr.length === 0) {
return [];
} else if (arr.length === 1) {
return arr[0];
} else {
var result = [];
var rest = this.permute(arr.slice(1));
for (var i = 0; i < rest.length; i++) {
for (var j = 0; j < arr[0].length; j++) {
result.push([arr[0][j]].concat(rest[i]));
}
}
return result;
}
}
};
})(require('../tree'));

View File

@@ -0,0 +1,135 @@
(function (tree) {
tree.mixin = {};
tree.mixin.Call = function (elements, args, index, filename, important) {
this.selector = new(tree.Selector)(elements);
this.arguments = args;
this.index = index;
this.filename = filename;
this.important = important;
};
tree.mixin.Call.prototype = {
eval: function (env) {
var mixins, args, rules = [], match = false;
for (var i = 0; i < env.frames.length; i++) {
if ((mixins = env.frames[i].find(this.selector)).length > 0) {
args = this.arguments && this.arguments.map(function (a) { return a.eval(env) });
for (var m = 0; m < mixins.length; m++) {
if (mixins[m].match(args, env)) {
try {
Array.prototype.push.apply(
rules, mixins[m].eval(env, this.arguments, this.important).rules);
match = true;
} catch (e) {
throw { message: e.message, index: this.index, filename: this.filename, stack: e.stack };
}
}
}
if (match) {
return rules;
} else {
throw { type: 'Runtime',
message: 'No matching definition was found for `' +
this.selector.toCSS().trim() + '(' +
this.arguments.map(function (a) {
return a.toCSS();
}).join(', ') + ")`",
index: this.index, filename: this.filename };
}
}
}
throw { type: 'Name',
message: this.selector.toCSS().trim() + " is undefined",
index: this.index, filename: this.filename };
}
};
tree.mixin.Definition = function (name, params, rules, condition, variadic) {
this.name = name;
this.selectors = [new(tree.Selector)([new(tree.Element)(null, name)])];
this.params = params;
this.condition = condition;
this.variadic = variadic;
this.arity = params.length;
this.rules = rules;
this._lookups = {};
this.required = params.reduce(function (count, p) {
if (!p.name || (p.name && !p.value)) { return count + 1 }
else { return count }
}, 0);
this.parent = tree.Ruleset.prototype;
this.frames = [];
};
tree.mixin.Definition.prototype = {
toCSS: function () { return "" },
variable: function (name) { return this.parent.variable.call(this, name) },
variables: function () { return this.parent.variables.call(this) },
find: function () { return this.parent.find.apply(this, arguments) },
rulesets: function () { return this.parent.rulesets.apply(this) },
evalParams: function (env, args) {
var frame = new(tree.Ruleset)(null, []), varargs;
for (var i = 0, val, name; i < this.params.length; i++) {
if (name = this.params[i].name) {
if (this.params[i].variadic && args) {
varargs = [];
for (var j = i; j < args.length; j++) {
varargs.push(args[j].eval(env));
}
frame.rules.unshift(new(tree.Rule)(name, new(tree.Expression)(varargs).eval(env)));
} else if (val = (args && args[i]) || this.params[i].value) {
frame.rules.unshift(new(tree.Rule)(name, val.eval(env)));
} else {
throw { type: 'Runtime', message: "wrong number of arguments for " + this.name +
' (' + args.length + ' for ' + this.arity + ')' };
}
}
}
return frame;
},
eval: function (env, args, important) {
var frame = this.evalParams(env, args), context, _arguments = [], rules, start;
for (var i = 0; i < Math.max(this.params.length, args && args.length); i++) {
_arguments.push(args[i] || this.params[i].value);
}
frame.rules.unshift(new(tree.Rule)('@arguments', new(tree.Expression)(_arguments).eval(env)));
rules = important ?
this.rules.map(function (r) {
return new(tree.Rule)(r.name, r.value, '!important', r.index);
}) : this.rules.slice(0);
return new(tree.Ruleset)(null, rules).eval({
frames: [this, frame].concat(this.frames, env.frames)
});
},
match: function (args, env) {
var argsLength = (args && args.length) || 0, len, frame;
if (! this.variadic) {
if (argsLength < this.required) { return false }
if (argsLength > this.params.length) { return false }
if ((this.required > 0) && (argsLength > this.params.length)) { return false }
}
if (this.condition && !this.condition.eval({
frames: [this.evalParams(env, args)].concat(env.frames)
})) { return false }
len = Math.min(argsLength, this.arity);
for (var i = 0; i < len; i++) {
if (!this.params[i].name) {
if (args[i].eval(env).toCSS() != this.params[i].value.eval(env).toCSS()) {
return false;
}
}
}
return true;
}
};
})(require('../tree'));

View File

@@ -0,0 +1,32 @@
(function (tree) {
tree.Operation = function (op, operands) {
this.op = op.trim();
this.operands = operands;
};
tree.Operation.prototype.eval = function (env) {
var a = this.operands[0].eval(env),
b = this.operands[1].eval(env),
temp;
if (a instanceof tree.Dimension && b instanceof tree.Color) {
if (this.op === '*' || this.op === '+') {
temp = b, b = a, a = temp;
} else {
throw { name: "OperationError",
message: "Can't substract or divide a color from a number" };
}
}
return a.operate(this.op, b);
};
tree.operate = function (op, a, b) {
switch (op) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
};
})(require('../tree'));

View File

@@ -0,0 +1,16 @@
(function (tree) {
tree.Paren = function (node) {
this.value = node;
};
tree.Paren.prototype = {
toCSS: function (env) {
return '(' + this.value.toCSS(env) + ')';
},
eval: function (env) {
return new(tree.Paren)(this.value.eval(env));
}
};
})(require('../tree'));

View File

@@ -0,0 +1,29 @@
(function (tree) {
tree.Quoted = function (str, content, escaped, i) {
this.escaped = escaped;
this.value = content || '';
this.quote = str.charAt(0);
this.index = i;
};
tree.Quoted.prototype = {
toCSS: function () {
if (this.escaped) {
return this.value;
} else {
return this.quote + this.value + this.quote;
}
},
eval: function (env) {
var that = this;
var value = this.value.replace(/`([^`]+)`/g, function (_, exp) {
return new(tree.JavaScript)(exp, that.index, true).eval(env).value;
}).replace(/@\{([\w-]+)\}/g, function (_, name) {
var v = new(tree.Variable)('@' + name, that.index).eval(env);
return ('value' in v) ? v.value : v.toCSS();
});
return new(tree.Quoted)(this.quote + value + this.quote, value, this.escaped, this.index);
}
};
})(require('../tree'));

View File

@@ -0,0 +1,42 @@
(function (tree) {
tree.Rule = function (name, value, important, index, inline) {
this.name = name;
this.value = (value instanceof tree.Value) ? value : new(tree.Value)([value]);
this.important = important ? ' ' + important.trim() : '';
this.index = index;
this.inline = inline || false;
if (name.charAt(0) === '@') {
this.variable = true;
} else { this.variable = false }
};
tree.Rule.prototype.toCSS = function (env) {
if (this.variable) { return "" }
else {
return this.name + (env.compress ? ':' : ': ') +
this.value.toCSS(env) +
this.important + (this.inline ? "" : ";");
}
};
tree.Rule.prototype.eval = function (context) {
return new(tree.Rule)(this.name,
this.value.eval(context),
this.important,
this.index, this.inline);
};
tree.Shorthand = function (a, b) {
this.a = a;
this.b = b;
};
tree.Shorthand.prototype = {
toCSS: function (env) {
return this.a.toCSS(env) + "/" + this.b.toCSS(env);
},
eval: function () { return this }
};
})(require('../tree'));

View File

@@ -0,0 +1,216 @@
(function (tree) {
tree.Ruleset = function (selectors, rules, strictImports) {
this.selectors = selectors;
this.rules = rules;
this._lookups = {};
this.strictImports = strictImports;
};
tree.Ruleset.prototype = {
eval: function (env) {
var selectors = this.selectors && this.selectors.map(function (s) { return s.eval(env) });
var ruleset = new(tree.Ruleset)(selectors, this.rules.slice(0), this.strictImports);
ruleset.root = this.root;
ruleset.allowImports = this.allowImports;
// push the current ruleset to the frames stack
env.frames.unshift(ruleset);
// Evaluate imports
if (ruleset.root || ruleset.allowImports || !ruleset.strictImports) {
for (var i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.Import) {
Array.prototype.splice
.apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
}
}
}
// Store the frames around mixin definitions,
// so they can be evaluated like closures when the time comes.
for (var i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.mixin.Definition) {
ruleset.rules[i].frames = env.frames.slice(0);
}
}
// Evaluate mixin calls.
for (var i = 0; i < ruleset.rules.length; i++) {
if (ruleset.rules[i] instanceof tree.mixin.Call) {
Array.prototype.splice
.apply(ruleset.rules, [i, 1].concat(ruleset.rules[i].eval(env)));
}
}
// Evaluate everything else
for (var i = 0, rule; i < ruleset.rules.length; i++) {
rule = ruleset.rules[i];
if (! (rule instanceof tree.mixin.Definition)) {
ruleset.rules[i] = rule.eval ? rule.eval(env) : rule;
}
}
// Pop the stack
env.frames.shift();
return ruleset;
},
match: function (args) {
return !args || args.length === 0;
},
variables: function () {
if (this._variables) { return this._variables }
else {
return this._variables = this.rules.reduce(function (hash, r) {
if (r instanceof tree.Rule && r.variable === true) {
hash[r.name] = r;
}
return hash;
}, {});
}
},
variable: function (name) {
return this.variables()[name];
},
rulesets: function () {
if (this._rulesets) { return this._rulesets }
else {
return this._rulesets = this.rules.filter(function (r) {
return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
});
}
},
find: function (selector, self) {
self = self || this;
var rules = [], rule, match,
key = selector.toCSS();
if (key in this._lookups) { return this._lookups[key] }
this.rulesets().forEach(function (rule) {
if (rule !== self) {
for (var j = 0; j < rule.selectors.length; j++) {
if (match = selector.match(rule.selectors[j])) {
if (selector.elements.length > rule.selectors[j].elements.length) {
Array.prototype.push.apply(rules, rule.find(
new(tree.Selector)(selector.elements.slice(1)), self));
} else {
rules.push(rule);
}
break;
}
}
}
});
return this._lookups[key] = rules;
},
//
// Entry point for code generation
//
// `context` holds an array of arrays.
//
toCSS: function (context, env) {
var css = [], // The CSS output
rules = [], // node.Rule instances
rulesets = [], // node.Ruleset instances
paths = [], // Current selectors
selector, // The fully rendered selector
rule;
if (! this.root) {
if (context.length === 0) {
paths = this.selectors.map(function (s) { return [s] });
} else {
this.joinSelectors(paths, context, this.selectors);
}
}
// Compile rules and rulesets
for (var i = 0; i < this.rules.length; i++) {
rule = this.rules[i];
if (rule.rules || (rule instanceof tree.Directive) || (rule instanceof tree.Media)) {
rulesets.push(rule.toCSS(paths, env));
} else if (rule instanceof tree.Comment) {
if (!rule.silent) {
if (this.root) {
rulesets.push(rule.toCSS(env));
} else {
rules.push(rule.toCSS(env));
}
}
} else {
if (rule.toCSS && !rule.variable) {
rules.push(rule.toCSS(env));
} else if (rule.value && !rule.variable) {
rules.push(rule.value.toString());
}
}
}
rulesets = rulesets.join('');
// If this is the root node, we don't render
// a selector, or {}.
// Otherwise, only output if this ruleset has rules.
if (this.root) {
css.push(rules.join(env.compress ? '' : '\n'));
} else {
if (rules.length > 0) {
selector = paths.map(function (p) {
return p.map(function (s) {
return s.toCSS(env);
}).join('').trim();
}).join( env.compress ? ',' : ',\n');
css.push(selector,
(env.compress ? '{' : ' {\n ') +
rules.join(env.compress ? '' : '\n ') +
(env.compress ? '}' : '\n}\n'));
}
}
css.push(rulesets);
return css.join('') + (env.compress ? '\n' : '');
},
joinSelectors: function (paths, context, selectors) {
for (var s = 0; s < selectors.length; s++) {
this.joinSelector(paths, context, selectors[s]);
}
},
joinSelector: function (paths, context, selector) {
var before = [], after = [], beforeElements = [],
afterElements = [], hasParentSelector = false, el;
for (var i = 0; i < selector.elements.length; i++) {
el = selector.elements[i];
if (el.combinator.value.charAt(0) === '&') {
hasParentSelector = true;
}
if (hasParentSelector) afterElements.push(el);
else beforeElements.push(el);
}
if (! hasParentSelector) {
afterElements = beforeElements;
beforeElements = [];
}
if (beforeElements.length > 0) {
before.push(new(tree.Selector)(beforeElements));
}
if (afterElements.length > 0) {
after.push(new(tree.Selector)(afterElements));
}
for (var c = 0; c < context.length; c++) {
paths.push(before.concat(context[c]).concat(after));
}
}
};
})(require('../tree'));

View File

@@ -0,0 +1,42 @@
(function (tree) {
tree.Selector = function (elements) {
this.elements = elements;
if (this.elements[0].combinator.value === "") {
this.elements[0].combinator.value = ' ';
}
};
tree.Selector.prototype.match = function (other) {
var len = this.elements.length,
olen = other.elements.length,
max = Math.min(len, olen);
if (len < olen) {
return false;
} else {
for (var i = 0; i < max; i++) {
if (this.elements[i].value !== other.elements[i].value) {
return false;
}
}
}
return true;
};
tree.Selector.prototype.eval = function (env) {
return new(tree.Selector)(this.elements.map(function (e) {
return e.eval(env);
}));
};
tree.Selector.prototype.toCSS = function (env) {
if (this._css) { return this._css }
return this._css = this.elements.map(function (e) {
if (typeof(e) === 'string') {
return ' ' + e.trim();
} else {
return e.toCSS(env);
}
}).join('');
};
})(require('../tree'));

View File

@@ -0,0 +1,25 @@
(function (tree) {
tree.URL = function (val, paths) {
if (val.data) {
this.attrs = val;
} else {
// Add the base path if the URL is relative and we are in the browser
if (typeof(window) !== 'undefined' && !/^(?:https?:\/\/|file:\/\/|data:|\/)/.test(val.value) && paths.length > 0) {
val.value = paths[0] + (val.value.charAt(0) === '/' ? val.value.slice(1) : val.value);
}
this.value = val;
this.paths = paths;
}
};
tree.URL.prototype = {
toCSS: function () {
return "url(" + (this.attrs ? 'data:' + this.attrs.mime + this.attrs.charset + this.attrs.base64 + this.attrs.data
: this.value.toCSS()) + ")";
},
eval: function (ctx) {
return this.attrs ? this : new(tree.URL)(this.value.eval(ctx), this.paths);
}
};
})(require('../tree'));

View File

@@ -0,0 +1,24 @@
(function (tree) {
tree.Value = function (value) {
this.value = value;
this.is = 'value';
};
tree.Value.prototype = {
eval: function (env) {
if (this.value.length === 1) {
return this.value[0].eval(env);
} else {
return new(tree.Value)(this.value.map(function (v) {
return v.eval(env);
}));
}
},
toCSS: function (env) {
return this.value.map(function (e) {
return e.toCSS(env);
}).join(env.compress ? ',' : ', ');
}
};
})(require('../tree'));

View File

@@ -0,0 +1,26 @@
(function (tree) {
tree.Variable = function (name, index, file) { this.name = name, this.index = index, this.file = file };
tree.Variable.prototype = {
eval: function (env) {
var variable, v, name = this.name;
if (name.indexOf('@@') == 0) {
name = '@' + new(tree.Variable)(name.slice(1)).eval(env).value;
}
if (variable = tree.find(env.frames, function (frame) {
if (v = frame.variable(name)) {
return v.value.eval(env);
}
})) { return variable }
else {
throw { type: 'Name',
message: "variable " + name + " is undefined",
filename: this.file,
index: this.index };
}
}
};
})(require('../tree'));

View File

@@ -0,0 +1,36 @@
{
"name": "less",
"description": "Leaner CSS",
"url": "http://lesscss.org",
"keywords": [
"css",
"parser",
"lesscss",
"browser"
],
"author": {
"name": "Alexis Sellier",
"email": "self@cloudhead.net"
},
"contributors": [],
"version": "1.3.0",
"bin": {
"lessc": "./bin/lessc"
},
"main": "./lib/less/index",
"directories": {
"test": "./test"
},
"engines": {
"node": ">=0.4.0"
},
"_id": "less@1.3.0",
"dependencies": {},
"devDependencies": {},
"optionalDependencies": {},
"_engineSupported": true,
"_npmVersion": "1.1.21",
"_nodeVersion": "v0.6.18",
"_defaultsLoaded": true,
"_from": "less@>=1.3.0"
}

View File

@@ -0,0 +1,58 @@
#yelow #short {
color: #fea;
}
#yelow #long {
color: #ffeeaa;
}
#yelow #rgba {
color: rgba(255, 238, 170, 0.1);
}
#yelow #argb {
color: #1affeeaa;
}
#blue #short {
color: #00f;
}
#blue #long {
color: #0000ff;
}
#blue #rgba {
color: rgba(0, 0, 255, 0.1);
}
#blue #argb {
color: #1a0000ff;
}
#alpha #hsla {
color: rgba(61, 45, 41, 0.6);
}
#overflow .a {
color: #000000;
}
#overflow .b {
color: #ffffff;
}
#overflow .c {
color: #ffffff;
}
#overflow .d {
color: #00ff00;
}
#grey {
color: #c8c8c8;
}
#808080 {
color: #808080;
}
#00ff00 {
color: #00ff00;
}
.lightenblue {
color: #3333ff;
}
.darkenblue {
color: #0000cc;
}
.unknowncolors {
color: blue2;
border: 2px solid superred;
}

View File

@@ -0,0 +1,56 @@
/******************\
* *
* Comment Header *
* *
\******************/
/*
Comment
*/
/*
* Comment Test
*
* - cloudhead (http://cloudhead.net)
*
*/
/* Colors
* ------
* #EDF8FC (background blue)
* #166C89 (darkest blue)
*
* Text:
* #333 (standard text) // A comment within a comment!
* #1F9EC9 (standard link)
*
*/
/* @group Variables
------------------- */
#comments {
/**/
color: red;
/* A C-style comment */
background-color: orange;
font-size: 12px;
/* lost comment */
content: "content";
border: 1px solid black;
padding: 0;
margin: 2em;
}
/* commented out
#more-comments {
color: grey;
}
*/
.selector,
.lots,
.comments {
color: #808080, /* blue */ #ffa500;
-webkit-border-radius: 2px /* webkit only */;
-moz-border-radius: 8px /* moz only with operation */;
}
#last {
color: #0000ff;
}

Some files were not shown because too many files have changed in this diff Show More