uki 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/bin/uki +53 -2
- data/frameworks/uki/README.rdoc +49 -7
- data/frameworks/uki/spec/unit/data/model.spec.js +16 -5
- data/frameworks/uki/spec/unit/dom.spec.js +1 -1
- data/frameworks/uki/spec/unit/utils.spec.js +1 -1
- data/frameworks/uki/src/uki-core/background/sliced9.js +1 -1
- data/frameworks/uki/src/uki-core/collection.js +5 -5
- data/frameworks/uki/src/uki-core/dom/dnd.js +4 -0
- data/frameworks/uki/src/uki-core/dom/event.js +15 -8
- data/frameworks/uki/src/uki-core/dom/w3cdnd.js +18 -3
- data/frameworks/uki/src/uki-core/dom.js +1 -3
- data/frameworks/uki/src/uki-core/uki.js +2 -1
- data/frameworks/uki/src/uki-core/utils.js +2 -2
- data/frameworks/uki/src/uki-core/view/base.js +4 -3
- data/frameworks/uki/src/uki-core/view/focusable.js +61 -41
- data/frameworks/uki/src/uki-core/view/observable.js +3 -2
- data/frameworks/uki/src/uki-core/view/styleable.js +6 -6
- data/frameworks/uki/src/uki-data/model.js +83 -17
- data/frameworks/uki/src/uki-data/observable.js +8 -5
- data/frameworks/uki/src/uki-more/more/view/treeList/render.js +4 -3
- data/frameworks/uki/src/uki-more/more/view/treeList.js +18 -7
- data/frameworks/uki/src/uki-view/view/checkbox.js +2 -0
- data/frameworks/uki/src/uki-view/view/flow.js +28 -9
- data/frameworks/uki/src/uki-view/view/list.js +59 -16
- data/frameworks/uki/src/uki-view/view/radio.js +2 -1
- data/frameworks/uki/src/uki-view/view/scrollPane.js +5 -6
- data/frameworks/uki/src/uki-view/view/slider.js +4 -4
- data/frameworks/uki/src/uki-view/view/splitPane.js +26 -29
- data/frameworks/uki/src/uki-view/view/table/column.js +6 -5
- data/frameworks/uki/src/uki-view/view/table/header.js +28 -18
- data/frameworks/uki/src/uki-view/view/table.js +41 -2
- data/frameworks/uki/src/uki-view/view/textField.js +2 -3
- data/lib/uki/project.rb +55 -15
- data/templates/controller.js.erb +5 -0
- data/templates/layout.js.erb +5 -0
- data/templates/myapp.js.erb +1 -2
- data/uki.gemspec +4 -2
- metadata +5 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.2
|
data/bin/uki
CHANGED
@@ -7,7 +7,7 @@ require 'commander/import'
|
|
7
7
|
require File.join(UKI_ROOT, 'lib', 'uki')
|
8
8
|
|
9
9
|
program :name, 'uki tools'
|
10
|
-
program :version,
|
10
|
+
program :version, File.read(File.join(UKI_ROOT, 'VERSION'))
|
11
11
|
program :description, 'uki development tools'
|
12
12
|
|
13
13
|
|
@@ -63,6 +63,40 @@ command :'new model' do |c|
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
command :'new layout' do |c|
|
67
|
+
c.syntax = 'uki new layout <name>'
|
68
|
+
c.summary = 'Create uki layout'
|
69
|
+
c.description = "Create template for uki layout with given <name>
|
70
|
+
and add include to the project file"
|
71
|
+
c.example "Create myapp.layout.editor()", "uki new layout editor"
|
72
|
+
c.example "Create view in arbitary package", "uki new layout mypackage.editor"
|
73
|
+
|
74
|
+
c.when_called do |args, options|
|
75
|
+
path = args.shift or raise 'Layout name required'
|
76
|
+
project = Uki::Project.new('.')
|
77
|
+
path = "#{project.name}.layout.#{path}"
|
78
|
+
project.create_function 'layout.js', path
|
79
|
+
say "Layout #{path} created"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
command :'new controller' do |c|
|
84
|
+
c.syntax = 'uki new controller <name>'
|
85
|
+
c.summary = 'Create uki controller'
|
86
|
+
c.description = "Create template for uki controller with given <name>
|
87
|
+
and add include to the project file"
|
88
|
+
c.example "Create myapp.controller.editor()", "uki new controller editor"
|
89
|
+
c.example "Create view in arbitary package", "uki new controller mypackage.editor"
|
90
|
+
|
91
|
+
c.when_called do |args, options|
|
92
|
+
path = args.shift or raise 'Controller name required'
|
93
|
+
project = Uki::Project.new('.')
|
94
|
+
path = "#{project.name}.controller.#{path}"
|
95
|
+
project.create_function 'controller.js', path
|
96
|
+
say "Controller #{path} created"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
66
100
|
command :run do |c|
|
67
101
|
c.syntax = 'uki run [host[:port]]'
|
68
102
|
c.summary = 'Run development server'
|
@@ -96,7 +130,24 @@ command :build do |c|
|
|
96
130
|
target = args.shift || 'build'
|
97
131
|
project = Uki::Project.new('.')
|
98
132
|
project.build target, :compile => !option.nocompiler
|
99
|
-
say "Build complete at
|
133
|
+
say "Build complete at '#{target}'"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
command :ie_images do |c|
|
138
|
+
c.syntax = 'uki ie_images [file]'
|
139
|
+
c.summary = 'Creates image files for IE6,7'
|
140
|
+
c.description = 'Creates image files for IE6,7 from
|
141
|
+
data urls in the theme file.
|
142
|
+
|
143
|
+
[file] defaults to <project_name>/theme.js
|
144
|
+
'
|
145
|
+
c.when_called do |args, option|
|
146
|
+
project = Uki::Project.new('.')
|
147
|
+
target = args.shift || File.join(project.name, 'theme.js')
|
148
|
+
place = project.ie_images target
|
149
|
+
say "IE images are at #{place}"
|
100
150
|
end
|
151
|
+
|
101
152
|
end
|
102
153
|
|
data/frameworks/uki/README.rdoc
CHANGED
@@ -1,22 +1,64 @@
|
|
1
1
|
= UKI – simple UiKit for complex Web apps
|
2
|
-
Uki is a
|
3
|
-
|
4
|
-
user interface toolkit for desktop-like web applications.
|
5
|
-
It comes with
|
6
|
-
a rich view-component library
|
7
|
-
ranging from Sliders to Grids and SplitPanes.
|
2
|
+
Uki is a JavaScript user interface toolkit for desktop-like web applications.
|
3
|
+
It comes with a rich view-component library ranging from Sliders to Grids and SplitPanes.
|
8
4
|
|
9
5
|
uki({ view: 'Button', text: 'Click me', rect: '10 10 100 24' }).attachTo( window );
|
10
6
|
|
11
7
|
uki('Button[text^=Click]').click(function() { alert(this.text()); });
|
12
8
|
|
9
|
+
|
10
|
+
== All you have to know in 5 minutes
|
11
|
+
1. Uki interfaces are created from Views the same way web pages are created from DOM nodes.
|
12
|
+
Views even behave similar to DOM nodes. You can appendView, insertBefore, access parentView etc.
|
13
|
+
panel.appendView(button)
|
14
|
+
Examples of views: Slider, SplitPane or Table
|
15
|
+
2. View have attributes. You can read them by calling attrname() without params and write with
|
16
|
+
attrname(newValue).
|
17
|
+
label.text('Lorem') // set text to a label
|
18
|
+
label.text() == 'Lorem' // get text
|
19
|
+
splitPane.handlePosition(300) // move the split pane handle to 300px
|
20
|
+
3. You can create Views with uki() function.
|
21
|
+
Once created view can be attached to any block DOM container with attachTo()
|
22
|
+
uki({ view: 'Label', text: 'Lorem', ... more attributes ... }).attachTo( window )
|
23
|
+
4. You can find attached views using css-like selectors.
|
24
|
+
uki('Label') // find all labels on page
|
25
|
+
uki('Box[name=main] > Label') // find all immediate descendant Labels in a box with name = "main"
|
26
|
+
5. uki() calls return Collection of Views. This is similar to jQuery('expression') result. You can
|
27
|
+
access individual views with [index]. You can manipulate all views at the same
|
28
|
+
time with a number of collection methods (http://ukijs.org/docs/symbols/uki.Collection.html)
|
29
|
+
uki('Label')[3] // get 3-d found label
|
30
|
+
6. Events are bound to Views (not individual DOM nodes) with the bind() function
|
31
|
+
uki('Label')[0].bind('click', function() { handle the event here }) // bind click to the first label
|
32
|
+
uki('Label').bind('click', function() { handle the event here }) // bind click to all labels
|
33
|
+
uki('Label').unbind('click') // unbind all click handlers from all labels
|
34
|
+
7. Views are laid out with initial position and resize rules. Initial position is set with the rect property
|
35
|
+
button.rect('50 20 100 22') // set left = 50px, top = 20px, width = 100px, height = 22px
|
36
|
+
Resize rules are set with the anchors property:
|
37
|
+
button.anchors('left top') // stay at the left top when container resizes
|
38
|
+
button.anchors('right bottom') // move with the bottom right corner of the container
|
39
|
+
button.anchors('left top right') // stay at the top, resize width with the container
|
40
|
+
You can pass both rect and anchors to the uki() function:
|
41
|
+
uki({ view: 'Button', rect: '50 20 100 22', anchors: 'left top right' })
|
42
|
+
8. You can change visual appearance of the views with themes. Theme is basically a collection of
|
43
|
+
resources like images, styled dom nodes and backgrounds. You can find an example of one
|
44
|
+
at http://github.com/voloko/uki/blob/master/src/uki-theme/airport.js
|
45
|
+
9. If your adding uki to existing project then it is better to simply add
|
46
|
+
<script src='http://static.ukijs.org/pkg/0.1.3/uki.gz.js'></script>
|
47
|
+
to your pages and it will work. If you start a new one you might try
|
48
|
+
uki-tools (http://github.com/voloko/uki-tools)
|
49
|
+
10. See the available resources in Links section and have fun
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
13
54
|
== Links
|
14
55
|
* API docs at http://ukijs.org/docs/
|
15
56
|
* Google group http://groups.google.com/group/ukijs
|
16
|
-
* Code examples at http://
|
57
|
+
* Code examples at http://ukijs.org/examples/
|
17
58
|
* Development docs and tutorial at http://wiki.github.com/voloko/uki/
|
18
59
|
* Google wave in 100 lines of code example: http://ukijs.org/examples/core-examples/wave
|
19
60
|
|
61
|
+
|
20
62
|
== Contribute
|
21
63
|
To install development server
|
22
64
|
1. Install ruby http://ruby-lang.org
|
@@ -9,7 +9,7 @@ describe 'uki.data.Model'
|
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'should update model'
|
12
|
-
model.
|
12
|
+
model.update({ firstName: 'John', lastName: 'Smith' })
|
13
13
|
model.firstName.should.be 'John'
|
14
14
|
model.lastName.should.be 'Smith'
|
15
15
|
end
|
@@ -19,11 +19,22 @@ describe 'uki.data.Model'
|
|
19
19
|
e.fields.should.eql ['name']
|
20
20
|
e.changes.name.should.not.be_null
|
21
21
|
});
|
22
|
-
model.
|
22
|
+
model.update({ name: 'something' });
|
23
23
|
end
|
24
24
|
|
25
|
-
it 'should
|
26
|
-
model.
|
27
|
-
model.
|
25
|
+
it 'should allow accesor methods'
|
26
|
+
uki.data.model.addFields(model, ['firstName', 'lastName'])
|
27
|
+
model.update({ firstName: 'John', lastName: 'Smith' })
|
28
|
+
model.firstName().should.be 'John'
|
29
|
+
model.lastName().should.be 'Smith'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should trigger change with accessor methods'
|
33
|
+
uki.data.model.addFields(model, ['firstName', 'lastName'])
|
34
|
+
model.bind('change', function(e) {
|
35
|
+
e.fields.should.eql ['firstName']
|
36
|
+
e.changes.firstName.should.be_true
|
37
|
+
});
|
38
|
+
model.firstName('something')
|
28
39
|
end
|
29
40
|
end
|
@@ -9,7 +9,7 @@ describe 'uki.dom'
|
|
9
9
|
|
10
10
|
it 'should create stylesheets'
|
11
11
|
x = uki.createElement('div')
|
12
|
-
x.className = 'test' + uki.
|
12
|
+
x.className = 'test' + uki.guid++
|
13
13
|
uki.dom.createStylesheet('.' + x.className + ' { display: inline !important; }')
|
14
14
|
uki.dom.probe(x, function() {
|
15
15
|
uki.dom.computedStyle(x).display.should.be 'inline'
|
@@ -52,7 +52,7 @@ uki.background.Sliced9 = uki.newClass(new function() {
|
|
52
52
|
|
53
53
|
/** @ignore */
|
54
54
|
function img (setting, style) {
|
55
|
-
return uki.imageHTML(setting[0], setting[1], setting[2], ' ondragstart="return false;" galleryimg="no" style="-webkit-user-drag:none;position:absolute;' + style + '"');
|
55
|
+
return uki.imageHTML(setting[0], setting[1], setting[2], ' ondragstart="return false;" galleryimg="no" style="-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;position:absolute;' + style + '"');
|
56
56
|
}
|
57
57
|
|
58
58
|
/** @ignore */
|
@@ -62,9 +62,9 @@ uki.fn = uki.Collection.prototype = new function() {
|
|
62
62
|
*/
|
63
63
|
this.attr = function( name, value ) {
|
64
64
|
if (value !== undefined) {
|
65
|
-
this.
|
66
|
-
uki.attr( this, name, value );
|
67
|
-
}
|
65
|
+
for (var i=0; i < this.length; i++) {
|
66
|
+
uki.attr( this[i], name, value );
|
67
|
+
};
|
68
68
|
return this;
|
69
69
|
} else {
|
70
70
|
return this[0] ? uki.attr( this[0], name ) : '';
|
@@ -167,7 +167,7 @@ uki.fn = uki.Collection.prototype = new function() {
|
|
167
167
|
@name uki.Collection#focusable */
|
168
168
|
/** @function
|
169
169
|
@name uki.Collection#style */
|
170
|
-
uki.Collection.addAttrs('dom html text background value rect checked anchors childViews typeName id name visible disabled focusable style draggable textSelectable'.split(' '));
|
170
|
+
uki.Collection.addAttrs('dom html text background value rect checked anchors childViews typeName id name visible disabled focusable style draggable textSelectable width height minX maxX minY maxY left top x y'.split(' '));
|
171
171
|
|
172
172
|
/** @function
|
173
173
|
@name uki.Collection#parent */
|
@@ -267,7 +267,7 @@ uki.fn = uki.Collection.prototype = new function() {
|
|
267
267
|
this.bind(name, handler);
|
268
268
|
} else {
|
269
269
|
for (var i=0; i < this.length; i++) {
|
270
|
-
this[i].trigger(name);
|
270
|
+
this[i][name] ? this[i][name]() : this[i].trigger(name);
|
271
271
|
};
|
272
272
|
}
|
273
273
|
return this;
|
@@ -54,6 +54,7 @@ var dragEndEvents = 'mouseup ' + (dnd.nativeDnD ? ' dragend' : '');
|
|
54
54
|
// if (window.attachEvent && !window.opera) dragEndEvents += ' mouseleave';
|
55
55
|
|
56
56
|
function startGesture (el) {
|
57
|
+
if (dnd.draggable) return;
|
57
58
|
dnd.draggable = el;
|
58
59
|
uki.dom.bind(doc, 'mousemove scroll', draggesture);
|
59
60
|
uki.dom.bind(doc, dragEndEvents, draggestureend);
|
@@ -68,6 +69,7 @@ function stopGesture () {
|
|
68
69
|
}
|
69
70
|
|
70
71
|
function draggesturestart (e) {
|
72
|
+
e = new uki.dom.Event(e);
|
71
73
|
e.type = 'draggesturestart';
|
72
74
|
uki.dom.handler.apply(this, arguments);
|
73
75
|
if (!e.isDefaultPrevented()) {
|
@@ -77,6 +79,7 @@ function draggesturestart (e) {
|
|
77
79
|
}
|
78
80
|
|
79
81
|
function draggesture (e) {
|
82
|
+
e = new uki.dom.Event(e);
|
80
83
|
e.type = 'draggesture';
|
81
84
|
e.dragOffset = (new Point(e.pageX, e.pageY)).offset(dnd.position);
|
82
85
|
uki.dom.handler.apply(dnd.draggable, arguments);
|
@@ -84,6 +87,7 @@ function draggesture (e) {
|
|
84
87
|
}
|
85
88
|
|
86
89
|
function draggestureend (e) {
|
90
|
+
e = new uki.dom.Event(e);
|
87
91
|
e.type = 'draggestureend';
|
88
92
|
e.dragOffset = (new Point(e.pageX, e.pageY)).offset(dnd.position);
|
89
93
|
uki.dom.handler.apply(dnd.draggable, arguments);
|
@@ -48,9 +48,9 @@ uki.extend(uki.dom, /** @lends uki.dom */ {
|
|
48
48
|
if ( el.setInterval && el != window )
|
49
49
|
el = window;
|
50
50
|
|
51
|
-
listener.huid = listener.huid || uki.
|
51
|
+
listener.huid = listener.huid || uki.guid++;
|
52
52
|
|
53
|
-
var id = el[expando] = el[expando] || uki.
|
53
|
+
var id = el[expando] = el[expando] || uki.guid++,
|
54
54
|
handler = uki.dom.handlers[id] = uki.dom.handlers[id] || function() {
|
55
55
|
uki.dom.handler.apply(arguments.callee.elem, arguments);
|
56
56
|
},
|
@@ -76,13 +76,18 @@ uki.extend(uki.dom, /** @lends uki.dom */ {
|
|
76
76
|
|
77
77
|
unbind: function(el, types, listener) {
|
78
78
|
var id = el[expando],
|
79
|
-
huid = listener.huid,
|
79
|
+
huid = listener && listener.huid,
|
80
80
|
i, type;
|
81
|
-
|
81
|
+
if (types) {
|
82
|
+
types = types.split(' ');
|
83
|
+
} else {
|
84
|
+
types = [];
|
85
|
+
uki.each(uki.dom.bound[id] || [], function(k, v) { types.push(k); });
|
86
|
+
}
|
82
87
|
for (i=0; i < types.length; i++) {
|
83
88
|
type = types[i];
|
84
|
-
if (!
|
85
|
-
uki.dom.bound[id][type] = uki.grep(uki.dom.bound[id][type], function(h) { return h.huid !== huid; });
|
89
|
+
if (!id || !uki.dom.bound[id] || !uki.dom.bound[id][type]) continue;
|
90
|
+
uki.dom.bound[id][type] = listener ? uki.grep(uki.dom.bound[id][type], function(h) { return h.huid !== huid; }) : [];
|
86
91
|
|
87
92
|
if (uki.dom.bound[id][type].length == 0) {
|
88
93
|
var handler = uki.dom.handlers[id];
|
@@ -103,8 +108,10 @@ uki.extend(uki.dom, /** @lends uki.dom */ {
|
|
103
108
|
handlers = uki.dom.bound[id],
|
104
109
|
i;
|
105
110
|
|
106
|
-
|
107
|
-
|
111
|
+
if (!e.domEvent) {
|
112
|
+
e = new uki.dom.Event(e);
|
113
|
+
e = uki.dom.fix( e );
|
114
|
+
}
|
108
115
|
|
109
116
|
if (!id || !handlers || !handlers[type]) return;
|
110
117
|
|
@@ -178,9 +178,19 @@ include('event.js');
|
|
178
178
|
|
179
179
|
var handler = function(e) {
|
180
180
|
if (dnd.dataTransfer && retriggering) {
|
181
|
+
e = new uki.dom.Event(e);
|
181
182
|
e.type = source;
|
182
183
|
e.dataTransfer = dnd.dataTransfer;
|
184
|
+
if (source == 'dragover') {
|
185
|
+
dnd.__canDrop = false;
|
186
|
+
} else {
|
187
|
+
stopW3Cdrag(this);
|
188
|
+
if (!dnd.__canDrop) return;
|
189
|
+
}
|
183
190
|
uki.dom.handler.apply(this, arguments);
|
191
|
+
if (e.isDefaultPrevented()) {
|
192
|
+
dnd.__canDrop = true;
|
193
|
+
}
|
184
194
|
}
|
185
195
|
};
|
186
196
|
|
@@ -211,6 +221,7 @@ include('event.js');
|
|
211
221
|
e.dataTransfer = new uki.dom.DataTransferWrapper(dataTransfer);
|
212
222
|
uki.dom.handler.apply(this, arguments);
|
213
223
|
dataTransfer.effectAllowed = e.dataTransfer.effectAllowed;
|
224
|
+
dataTransfer.dropEffect = e.dataTransfer.dropEffect;
|
214
225
|
}
|
215
226
|
|
216
227
|
function startW3Cdrag (element) {
|
@@ -218,14 +229,16 @@ include('event.js');
|
|
218
229
|
}
|
219
230
|
|
220
231
|
function stopW3Cdrag (element) {
|
232
|
+
if (!dnd.dataTransfer) return;
|
221
233
|
dnd.dataTransfer.cleanup();
|
222
234
|
dnd.dragOver = dnd.dataTransfer = dnd.target = null;
|
223
235
|
uki.dom.unbind( element, 'draggestureend', dragend );
|
224
236
|
}
|
225
237
|
|
226
238
|
function dragenter (e) {
|
227
|
-
if (!dnd.dataTransfer || e.domEvent.
|
228
|
-
e
|
239
|
+
if (!dnd.dataTransfer || e.domEvent.__dragEntered || !retriggering) return;
|
240
|
+
e = new uki.dom.Event(e);
|
241
|
+
e.domEvent.__dragEntered = true;
|
229
242
|
if (dnd.dragOver == this) return;
|
230
243
|
dnd.dragOver = this;
|
231
244
|
e.type = 'dragenter';
|
@@ -234,7 +247,8 @@ include('event.js');
|
|
234
247
|
|
235
248
|
function drag (e) {
|
236
249
|
if (retriggering) {
|
237
|
-
if (!e.domEvent.
|
250
|
+
if (!e.domEvent.__dragEntered && dnd.dragOver) {
|
251
|
+
e = new uki.dom.Event(e);
|
238
252
|
e.type = 'dragleave';
|
239
253
|
uki.dom.handler.apply(dnd.dragOver, arguments);
|
240
254
|
dnd.dragOver = null;
|
@@ -262,6 +276,7 @@ include('event.js');
|
|
262
276
|
} else {
|
263
277
|
return;
|
264
278
|
}
|
279
|
+
e = new uki.dom.Event(e);
|
265
280
|
uki.dom.handler.apply(this, arguments);
|
266
281
|
if (e.isDefaultPrevented()) {
|
267
282
|
stopW3Cdrag(this);
|
@@ -8,8 +8,6 @@ include('utils.js');
|
|
8
8
|
* @author voloko
|
9
9
|
*/
|
10
10
|
uki.dom = {
|
11
|
-
guid: 1,
|
12
|
-
|
13
11
|
/**
|
14
12
|
* Convenience wrapper around document.createElement
|
15
13
|
* Creates dom element with given tagName, cssText and innerHTML
|
@@ -23,7 +21,7 @@ uki.dom = {
|
|
23
21
|
var e = doc.createElement(tagName);
|
24
22
|
if (cssText) e.style.cssText = cssText;
|
25
23
|
if (innerHTML) e.innerHTML = innerHTML;
|
26
|
-
e[expando] = uki.
|
24
|
+
e[expando] = uki.guid++;
|
27
25
|
return e;
|
28
26
|
},
|
29
27
|
|
@@ -58,7 +58,7 @@ var utils = {
|
|
58
58
|
result = function() {
|
59
59
|
return fn.apply(context, args.concat(slice.call(arguments, 0)));
|
60
60
|
};
|
61
|
-
result.huid = fn.huid = fn.huid || uki.
|
61
|
+
result.huid = fn.huid = fn.huid || uki.guid++;
|
62
62
|
return result;
|
63
63
|
},
|
64
64
|
|
@@ -107,7 +107,7 @@ var utils = {
|
|
107
107
|
'"': '"',
|
108
108
|
"'": '''
|
109
109
|
};
|
110
|
-
return html.replace(/[&<>\"\']/g, function(c) { return trans[c]; });
|
110
|
+
return (html + '').replace(/[&<>\"\']/g, function(c) { return trans[c]; });
|
111
111
|
},
|
112
112
|
|
113
113
|
/**
|
@@ -286,8 +286,9 @@ uki.view.declare('uki.view.Base', uki.view.Observable, uki.view.Styleable, funct
|
|
286
286
|
if (s === undefined) return this[prop] || new Size();
|
287
287
|
this[prop] = Size.create(s);
|
288
288
|
this.rect(this._parentRect);
|
289
|
-
|
290
|
-
|
289
|
+
this._dom.style[name + 'Width'] = this[prop].width ? this[prop].width + PX : '';
|
290
|
+
this._dom.style[name + 'Height'] = this[prop].height ? this[prop].height + PX : '';
|
291
|
+
return this;
|
291
292
|
};
|
292
293
|
}, this);
|
293
294
|
|
@@ -426,7 +427,7 @@ uki.view.declare('uki.view.Base', uki.view.Observable, uki.view.Styleable, funct
|
|
426
427
|
@name uki.view.Base#left */
|
427
428
|
/** @function
|
428
429
|
@name uki.view.Base#top */
|
429
|
-
uki.each(['width', 'height', 'minX', 'maxX', 'minY', 'maxY', 'left', 'top'], function(index, attr) {
|
430
|
+
uki.each(['width', 'height', 'minX', 'maxX', 'minY', 'maxY', 'x', 'y', 'left', 'top'], function(index, attr) {
|
430
431
|
this[attr] = function(value) {
|
431
432
|
if (value === undefined) return uki.attr(this.rect(), attr);
|
432
433
|
uki.attr(this.rect(), attr, value);
|
@@ -4,40 +4,48 @@ include('observable.js');
|
|
4
4
|
/**
|
5
5
|
* @class
|
6
6
|
*/
|
7
|
-
uki.view.Focusable = /** @lends uki.view.Focusable.prototype */
|
7
|
+
uki.view.Focusable = new function() {/** @lends uki.view.Focusable.prototype */
|
8
|
+
|
8
9
|
// dom: function() {
|
9
10
|
// return null; // should implement
|
10
11
|
// },
|
11
|
-
_focusable
|
12
|
+
this._focusable = true; // default value
|
13
|
+
this._focusOnClick = true;
|
14
|
+
|
15
|
+
this.focusOnClick = uki.newProp('_focusOnClick');
|
12
16
|
|
13
|
-
focusable
|
17
|
+
this.focusable = uki.newProp('_focusable', function(v) {
|
14
18
|
this._focusable = v;
|
15
|
-
this.
|
19
|
+
if (v) this._initFocusable();
|
20
|
+
this._updateFocusable();
|
16
21
|
}),
|
17
22
|
|
18
|
-
disabled
|
23
|
+
this.disabled = uki.newProp('_disabled', function(d) {
|
24
|
+
var changed = d !== !!this._disabled;
|
19
25
|
this._disabled = d;
|
20
26
|
if (d) this.blur();
|
21
|
-
this.
|
22
|
-
if (this._updateBg) this._updateBg();
|
27
|
+
this._updateFocusable();
|
28
|
+
if (changed && this._updateBg) this._updateBg();
|
23
29
|
}),
|
24
30
|
|
25
|
-
|
26
|
-
if (this._focusTarget)
|
27
|
-
|
28
|
-
|
31
|
+
this._updateFocusable = function() {
|
32
|
+
if (this._preCreatedFocusTarget || !this._focusTarget) return;
|
33
|
+
|
34
|
+
if (this._focusable && !this._disabled) {
|
35
|
+
this._focusTarget.style.display = 'block';
|
36
|
+
} else {
|
37
|
+
this._focusTarget.style.display = 'none';
|
29
38
|
}
|
30
39
|
},
|
31
40
|
|
32
|
-
_initFocusable
|
33
|
-
this._focusTarget
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
this.
|
39
|
-
this.
|
40
|
-
this._focusTarget.hideFocus = true;
|
41
|
+
this._initFocusable = function(preCreatedFocusTarget) {
|
42
|
+
if ((!preCreatedFocusTarget && !this._focusable) || this._focusTarget) return;
|
43
|
+
this._focusTarget = preCreatedFocusTarget;
|
44
|
+
this._preCreatedFocusTarget = preCreatedFocusTarget;
|
45
|
+
|
46
|
+
if (!preCreatedFocusTarget) {
|
47
|
+
this._focusTarget = uki.createElement('input', 'position:absolute;left:-9999px;top:0;width:1px;height:1px;');
|
48
|
+
this.dom().appendChild(this._focusTarget);
|
41
49
|
}
|
42
50
|
this._hasFocus = false;
|
43
51
|
this._firstFocus = true;
|
@@ -45,48 +53,60 @@ uki.view.Focusable = /** @lends uki.view.Focusable.prototype */ {
|
|
45
53
|
uki.dom.bind(this._focusTarget, 'focus', uki.proxy(function(e) {
|
46
54
|
if (!this._hasFocus) this._focus(e);
|
47
55
|
}, this));
|
56
|
+
|
48
57
|
uki.dom.bind(this._focusTarget, 'blur', uki.proxy(function(e) {
|
49
|
-
if (this._hasFocus)
|
58
|
+
if (this._hasFocus) {
|
59
|
+
this._hasFocus = false;
|
60
|
+
setTimeout(uki.proxy(function() { // wait for mousedown refocusing
|
61
|
+
if (!this._hasFocus) this._blur();
|
62
|
+
}, this), 1);
|
63
|
+
}
|
50
64
|
}, this));
|
51
65
|
|
52
|
-
if (!
|
53
|
-
|
54
|
-
try { this.focus(); } catch (e) {};
|
55
|
-
}, this), 1);
|
66
|
+
if (!preCreatedFocusTarget) this.bind('mousedown', function(e) {
|
67
|
+
if (this._focusOnClick) this.focus();
|
56
68
|
});
|
57
|
-
|
69
|
+
this._updateFocusable();
|
70
|
+
}
|
58
71
|
|
59
|
-
_focus
|
72
|
+
this._focus = function(e) {
|
60
73
|
this._hasFocus = true;
|
61
74
|
this._firstFocus = false;
|
62
|
-
}
|
75
|
+
}
|
63
76
|
|
64
|
-
_blur
|
77
|
+
this._blur = function(e) {
|
65
78
|
this._hasFocus = false;
|
66
|
-
}
|
79
|
+
}
|
67
80
|
|
68
|
-
focus
|
69
|
-
|
70
|
-
if (
|
71
|
-
|
81
|
+
this.focus = function() {
|
82
|
+
if (this._focusable && !this._disabled) {
|
83
|
+
if (!this._hasFocus) this._focus();
|
84
|
+
var target = this._focusTarget;
|
85
|
+
setTimeout(function() {
|
86
|
+
try {
|
87
|
+
target.focus();
|
88
|
+
} catch(e) { }
|
89
|
+
target = null;
|
90
|
+
}, 1);
|
91
|
+
}
|
72
92
|
return this;
|
73
93
|
},
|
74
94
|
|
75
|
-
blur
|
95
|
+
this.blur = function() {
|
76
96
|
try {
|
77
97
|
this._focusTarget.blur();
|
78
98
|
} catch(e) {}
|
79
99
|
return this;
|
80
|
-
}
|
100
|
+
}
|
81
101
|
|
82
|
-
hasFocus
|
102
|
+
this.hasFocus = function() {
|
83
103
|
return this._hasFocus;
|
84
|
-
}
|
104
|
+
}
|
85
105
|
|
86
|
-
_bindToDom
|
106
|
+
this._bindToDom = function(name) {
|
87
107
|
if (!this._focusTarget || 'keyup keydown keypress focus blur'.indexOf(name) == -1) return false;
|
88
|
-
|
89
|
-
return uki.view.Observable._bindToDom.call(this, name, this.
|
108
|
+
|
109
|
+
return uki.view.Observable._bindToDom.call(this, name, this._focusTarget);
|
90
110
|
}
|
91
111
|
|
92
112
|
|
@@ -9,6 +9,7 @@ uki.view.Observable = /** @lends uki.view.Observable.prototype */ {
|
|
9
9
|
// },
|
10
10
|
|
11
11
|
bind: function(name, callback) {
|
12
|
+
callback.huid = callback.huid || uki.guid++;
|
12
13
|
uki.each(name.split(' '), function(i, name) {
|
13
14
|
if (!this._bound(name)) this._bindToDom(name);
|
14
15
|
this._observersFor(name).push(callback);
|
@@ -18,8 +19,8 @@ uki.view.Observable = /** @lends uki.view.Observable.prototype */ {
|
|
18
19
|
|
19
20
|
unbind: function(name, callback) {
|
20
21
|
uki.each(name.split(' '), function(i, name) {
|
21
|
-
this._observers[name] = uki.grep(this.
|
22
|
-
return observer != callback;
|
22
|
+
this._observers[name] = !callback ? [] : uki.grep(this._observersFor(name, true), function(observer) {
|
23
|
+
return observer != callback && observer.huid != callback.huid;
|
23
24
|
});
|
24
25
|
if (this._observers[name].length == 0) {
|
25
26
|
this._unbindFromDom(name);
|