Skip to content

Commit

Permalink
bugfixes, remove obsolete readme
Browse files Browse the repository at this point in the history
  • Loading branch information
voloko committed Feb 26, 2011
1 parent 64be832 commit f8078cb
Show file tree
Hide file tree
Showing 8 changed files with 31 additions and 224 deletions.
201 changes: 4 additions & 197 deletions README.rdoc
@@ -1,199 +1,6 @@
= UKI – simple UiKit for complex Web apps
Uki is a JavaScript user interface toolkit for desktop-like web applications.
It comes with a rich view-component library ranging from Sliders to Grids and SplitPanes.
Uki is a small js library that helps build complex desktop-class in
a simple and conscious way. Now with nodejs support

uki({ view: 'Button', text: 'Click me', pos: 'l:10px t:10px w:100px' }).attach( window );

uki('Button[text^=Click]').addListener('click', function() { alert(this.text()); });


== All you have to know in 5 minutes
1. Uki interfaces are created from Views the same way web pages are created from DOM nodes.
Views even behave similar to DOM nodes. You can appendChild, insertBefore, access parent etc.
panel.appendChild(button)
Examples of views: Slider, SplitPane or Table (http://ukijs.org/examples/)
2. View have attributes. You can read them by calling attrname() without params and write with
attrname(newValue).
label.text('Lorem') // set text to a label
label.text() == 'Lorem' // get text
splitPane.handlePosition(300) // move the split pane handle to 300px
3. You can create Views with uki() function.
Once created view can be attached to any block DOM container with attachTo()
uki({ view: 'Label', text: 'Lorem', ... more attributes ... }).attachTo( window )
4. You can find attached views using css-like selectors.
uki('Label') // find all labels on page
uki('Box[name=main] > Label') // find all immediate descendant Labels in a box with name = "main"
5. uki() calls return Collection of Views. This is similar to jQuery('expression') result. You can
access individual views with [index]. You can manipulate all views at the same
time with a number of collection methods (http://ukijs.org/docs/symbols/uki.Collection.html)
uki('Label')[2] // get 3-d found label
6. Events are bound to Views (not individual DOM nodes) with the bind() function
uki('Label')[0].bind('click', function() { handle the event here }) // bind click to the first label
uki('Label').bind('click', function() { handle the event here }) // bind click to all labels
uki('Label').unbind('click') // unbind all click handlers from all labels
7. Views are laid out with initial position and resize rules. Initial position is set with the rect property
button.rect('50 20 100 22') // set left = 50px, top = 20px, width = 100px, height = 22px
Resize rules are set with the anchors property:
button.anchors('left top') // stay at the left top when container resizes
button.anchors('right bottom') // move with the bottom right corner of the container
button.anchors('left top right') // stay at the top, resize width with the container
You can pass both rect and anchors to the uki() function:
uki({ view: 'Button', rect: '50 20 100 22', anchors: 'left top right' })
8. You can change visual appearance of the views with themes. Theme is basically a collection of
resources like images, styled dom nodes and backgrounds. You can find an example of one
at http://github.com/voloko/uki/blob/master/src/uki-theme/airport.js
9. If your adding uki to existing project then it is better to simply add
<script src='http://static.ukijs.org/pkg/0.2.0/uki.js'></script>
to your pages and it will work. If you start a new one you might try
uki-tools (http://github.com/voloko/uki-tools)
10. See the available resources in Links section and have fun




== Links
* API docs at http://ukijs.org/docs/
* Google group http://groups.google.com/group/ukijs
* Code examples at http://ukijs.org/examples/
* Development docs and tutorial at http://wiki.github.com/voloko/uki/
* Google wave in 100 lines of code example: http://ukijs.org/examples/core-examples/wave


== Contribute
To install development server
1. Install ruby http://ruby-lang.org
2. Open terminal and run
gem install uki
cd PATH_TO_UKI
uki run

== Simple
The Web should be simple.
Adding a new library to your app should not require
using a specific build process or learning a new language.
It should be as simple as adding a <script> tag to your HTML.
That's exactly the way uki works. No frameworks to install,
no dependencies to manage,
no CSS to include.
Simple.

== Cross-Browser
Uki works with IE7+, Opera 9+, FF 2+, Safari 3+, and Chrome.
And it looks exactly the same on any of them.

== Fast
One of the reasons uki appeared
is that I had to create a 4000-row complex
client-side-searchable table.
Just rendering the table made any version of IE unresponsive for half a minute.
Uki uses progressive rendering and can render 30k+-row lists and tables mostly instantly.

== Small
With all the images packed into it
(not supported in IE7),
a gzipped uki build is under 30kb,
and it's a single HTTP request.

== Extensible
Creating a new component requires only one function to redeclare.

== Embeddable
It's great when you start building your whole app with uki.
But sometimes
you have to add a desktop-like experience to a working site.
Say, adding a widget or a table
to an existing design.
While uki can occupy the whole browser window,
it works perfectly well in a small <div> in
your sidebar.
Just use attachTo( myDiv ) for any widget you want to add.

== You already know it
Uki is written in plain JavaScript.
It leverages well-known DOM and JS idioms
such as CSS selectors, events and attributes.
If you've ever used
jQuery, learning uki won't take long.

== Programmable Layout
HTML and CSS are great technologies,
though you can't lay everything out with them.
There are things that require programmable layout calculations.
Think of a toolbar,
which should show a popup
when some of the buttons don't fit.
Or a split pane.
Or moving a slider bar on window resize.
That's the reason
uki calculates view positions and sizes
with JavaScript.
Unfortunately,
resizing everything with pure JS will make your layout slow as a turtle.
So uki uses as much native browser layout as possible.

== Longer example
uki(
{ // create a split pane...
view: 'SplitPane', rect: '1000 600', anchors: 'left top right bottom',
handlePosition: 300, leftMin: 200, rightMin: 300,
// ...with button on the left
leftChildViews: { view: 'Button', rect: '10 10 280 24', anchors: 'top left right', text: 'Clear text field' },
// ...and a vertical split pane on the right...
rightChildViews: [
{ view: 'VSplitPane', rect: '693 600', anchors: 'left top right bottom', vertical: true,
// ...with text field in the top part
topChildViews: { view: 'TextField', rect: '10 10 280 24', anchors: 'top left', value: '0', id: 'field' },
// ...and a slider in the bottom
bottomChildViews: { view: 'Slider', rect: '10 10 673 24', anchors: 'top right left' }
}
]
}).attachTo( window, '1000 600' );

// on slider change update text field
uki('SplitPane Slider').bind('change', function() {
uki('TextField').value(this.value())
});

// on button click clear the text field
uki('Button[text~="Clear"]').bind('click', function() {
uki('#field').value('') // find by id
});

results in http://ukijs.org/functional/splitPaneEx.html

== Builder
uki({
view: 'Button',
rect: '400 40 200 24',
text: 'uki is awesome!'
}).attachTo( document.getElementById('test'), '1000 100' );

uki('Button[text^=uki]').click(function() {
alert('Hello world!');
});

uki(
{ view: "Button", text: "Click me", rect: "10 10 100 24" }
).attachTo( document.getElementById("test") );

uki("Button[text^=Click]").click(
function() { alert(this.text()); }
);

uki({ view: 'SplitPane', rect: '1000 600', anchors: 'left top right bottom',
handlePosition: 300, autogrowLeft: false, leftMin: 300, rightMin: 300,
leftChildViews: { view: 'Button', rect: '10 10 280 24', anchors: 'top left right', text: 'left pane' },
rightChildViews: [
{ view: 'SplitPane', rect: '693 600', anchors: 'left top right bottom', vertical: true,
topChildViews: { view: 'Button', rect: '10 10 280 24', anchors: 'top left', text: 'top pane' },
bottomChildViews: { view: 'Slider', rect: '10 10 673 24', anchors: 'top right left' }
}
]
}).attachTo( window, '1000 600' );

== Tests
cd tests
narwhal runner.js

== P.S.
And one more thing. Unobtrusive JavaScript is evil.
uki({ view: 'Button', text: 'Click me', pos: 'l:10px t:10px w:100px' }).attach();
uki('Button[text^=Click]').on('click', function() { alert(this.text()); });
31 changes: 14 additions & 17 deletions express.js
@@ -1,22 +1,19 @@
var path = require('path'),
sr = require('static_require'),
fs = require('fs');

var examplesPath = path.join(__dirname, 'examples');

exports.init = function(app) {
app.get('/perf', sr.getAppHandler('Benchmark runner', '/perf/runner.js'));

app.get('/client', sr.getAppHandler('Client', '/client/app.js'));



app.set('views', path.join(examplesPath, 'views'));



app.get('/perf', sr.getAppHandler('Benchmark runner', '/perf/runner.js'));

app.get('/', function(req, res) {
res.redirect('/examples/');
});

app.get('/examples/', function(req, res) {
var exampleList = listExamples(examplesPath).map(function(name) {
var filePath = path.join(examplesPath, name),
Expand All @@ -32,21 +29,21 @@ exports.init = function(app) {
}).sort(function(a, b) {
return a.order*1 - b.order*1;
});
res.render('exampleList.jade', {
res.render('exampleList.jade', {
layout: false,
locals: { exampleList: exampleList }
locals: { exampleList: exampleList }
});
});

app.get('/examples/:type/:example/', function(req, res) {
var filePath = path.join(examplesPath, req.param('type'), req.param('example')),
page = getExamplePage(filePath);

if (page) {
res.send(page);
} else {
var code = getExampleCode(filePath);
res.render('example.jade', {
res.render('example.jade', {
layout: false,
locals: {
html: extractExampleHtml(code),
Expand All @@ -55,11 +52,11 @@ exports.init = function(app) {
});
}
});

app.get('/*.js', sr.getHandler({
searchPaths: [fs.realpathSync(path.join(__dirname, 'src'))]
}));

};

function getExamplePage (filePath) {
Expand Down Expand Up @@ -89,7 +86,7 @@ function listExamples (filePath) {
function getExampleCode (filePath) {
var name = path.basename(filePath),
jsPath = path.join(filePath, name + '.js');

return fs.readFileSync(jsPath, 'utf8');
}

Expand Down
3 changes: 2 additions & 1 deletion src/uki-core/attachment.js
Expand Up @@ -2,6 +2,7 @@ var Container = require('./view/container.js').Container,
after = require('./after').after,
utils = require('./utils'),
env = require('./env'),
evt = require('./event'),
dom = require('./dom'),
fun = require('./function');

Expand Down Expand Up @@ -45,7 +46,7 @@ function register(a) {
instances = {};
var timeout = false;

require('./event').addListener(window, 'resize', function() {
evt.on(env.root, 'resize', function() {
if (!timeout) {
timeout = true;
setTimeout(function(i, len) {
Expand Down
4 changes: 2 additions & 2 deletions src/uki-core/binding.js
Expand Up @@ -20,9 +20,9 @@ exports.Binding = fun.newClass({
}

if (this.model && this.view) {
this.view.addListener(this.viewEvent,
this.view.on(this.viewEvent,
fun.bindOnce(this.updateModel, this));
this.model.addListener(this.modelEvent,
this.model.on(this.modelEvent,
fun.bindOnce(this.updateView, this));
if (this.sync !== false) {
this.updateView();
Expand Down
6 changes: 4 additions & 2 deletions src/uki-core/gesture.js
Expand Up @@ -18,12 +18,14 @@ var addDraggestures = {
el.__draggesturebound++;
} else {
el.__draggesturebound = 1;
evt.addListener(el, 'mousedown', dragGestureStart);
evt.on(el, 'mousedown', dragGestureStart);
}
},
teardown: function(el) {
el.__draggesturebound--;
if (!el.__draggesturebound) evt.removeListener(el, 'mousedown', dragGestureStart);
if (!el.__draggesturebound) {
evt.removeListener(el, 'mousedown', dragGestureStart);
}
}
};

Expand Down
6 changes: 3 additions & 3 deletions src/uki-view/view/dataList.js
Expand Up @@ -274,8 +274,8 @@ proto.editSelected = function() {
this.dom().appendChild(this.editor().dom());

this.editor()
.addListener('finishEdit', fun.bindOnce(this._editorBlur, this))
.addListener('move', fun.bindOnce(this._editorMove, this))
.on('finishEdit', fun.bindOnce(this._editorBlur, this))
.on('move', fun.bindOnce(this._editorMove, this))
.pos({ top: t+'px', left: 0+'px', right: 0+'px', height: this.rowHeight() + 'px' })
.visible(true)
.parent(this)
Expand Down Expand Up @@ -324,7 +324,7 @@ proto._createDom = function(initArgs) {
this._initSelectable();

// prevent dragging of selection
this.addListener('selectstart dragstart', evt.preventDefaultHandler);
this.on('selectstart dragstart', evt.preventDefaultHandler);
};

proto.triggerSelection = function() {
Expand Down
2 changes: 1 addition & 1 deletion src/uki-view/view/nativeControl.js
Expand Up @@ -130,7 +130,7 @@ textProto._initPlaceholder = function() {
this.addClass('uki-nc-text_with-placeholder');
this._placeholderDom = dom.createElement('span', { className: 'uki-nc-text__placholder' });
this._dom.insertBefore(this._placeholderDom, this._dom.firstChild);
evt.addListener(this._placeholderDom, 'click', fun.bindOnce(function() {
evt.on(this._placeholderDom, 'click', fun.bindOnce(function() {
this.focus();
}, this));
this.on('focus blur change keyup', this._updatePlaceholderVis);
Expand Down
2 changes: 1 addition & 1 deletion src/uki-view/view/splitPane.js
Expand Up @@ -161,7 +161,7 @@ proto._createHandle = function() {
}

utils.forEach(['draggesturestart', 'draggesture', 'draggestureend'], function(name) {
evt.addListener(handle, name, fun.bind(this['_' + name], this));
evt.on(handle, name, fun.bind(this['_' + name], this));
}, this);

return handle;
Expand Down

0 comments on commit f8078cb

Please sign in to comment.