sproutcore 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +42 -29
- data/README.txt +1 -1
- data/Rakefile +5 -0
- data/app_generators/sproutcore/sproutcore_generator.rb +4 -4
- data/app_generators/sproutcore/templates/sc-config.rb +72 -0
- data/bin/sc-build +2 -0
- data/clients/sc_docs/controllers/docs.js +1 -0
- data/clients/sc_docs/english.lproj/body.rhtml +5 -0
- data/clients/sc_docs/views/doc_frame.js +1 -1
- data/clients/sc_test_runner/controllers/runner.js +2 -2
- data/clients/sc_test_runner/english.lproj/body.rhtml +5 -0
- data/clients/sc_test_runner/main.js +12 -12
- data/clients/sc_test_runner/models/test.js +3 -0
- data/clients/sc_test_runner/views/test_label.js +1 -1
- data/config/hoe.rb +2 -0
- data/frameworks/sproutcore/controllers/array.js +132 -125
- data/frameworks/sproutcore/drag/drag.js +5 -2
- data/frameworks/sproutcore/english.lproj/buttons.css +64 -64
- data/frameworks/sproutcore/english.lproj/collections.css +82 -0
- data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
- data/frameworks/sproutcore/english.lproj/images/sproutcore-logo.png +0 -0
- data/frameworks/sproutcore/english.lproj/images/sticky-note.png +0 -0
- data/frameworks/sproutcore/english.lproj/menu.css +1 -1
- data/frameworks/sproutcore/english.lproj/theme.css +13 -4
- data/frameworks/sproutcore/foundation/array.js +24 -2
- data/frameworks/sproutcore/foundation/benchmark.js +12 -5
- data/frameworks/sproutcore/foundation/observable.js +62 -1
- data/frameworks/sproutcore/foundation/utils.js +16 -0
- data/frameworks/sproutcore/tests/views/label_item.rhtml +21 -0
- data/frameworks/sproutcore/tests/views/list.rhtml +21 -0
- data/frameworks/sproutcore/tests/views/scroll.rhtml +21 -0
- data/frameworks/sproutcore/views/collection.js +401 -73
- data/frameworks/sproutcore/views/collection/collection_item.js +36 -0
- data/frameworks/sproutcore/views/collection/grid.js +149 -0
- data/frameworks/sproutcore/views/collection/image_cell.js +154 -0
- data/frameworks/sproutcore/views/collection/list.js +115 -0
- data/frameworks/sproutcore/views/collection/text_cell.js +128 -0
- data/frameworks/sproutcore/views/image.js +1 -1
- data/frameworks/sproutcore/views/label.js +6 -2
- data/frameworks/sproutcore/views/scroll.js +34 -0
- data/frameworks/sproutcore/views/view.js +12 -4
- data/generators/client/client_generator.rb +3 -11
- data/generators/client/templates/english.lproj/body.css +75 -0
- data/generators/client/templates/english.lproj/body.rhtml +17 -2
- data/generators/model/templates/fixture.js +32 -0
- data/lib/sproutcore/build_tools/html_builder.rb +29 -11
- data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
- data/lib/sproutcore/bundle.rb +19 -7
- data/lib/sproutcore/library.rb +39 -21
- data/lib/sproutcore/merb/bundle_controller.rb +3 -8
- data/lib/sproutcore/version.rb +1 -1
- data/lib/sproutcore/view_helpers.rb +7 -5
- data/lib/sproutcore/view_helpers/core_views.rb +11 -3
- data/sc-config.rb +7 -0
- data/tasks/deployment.rake +15 -2
- metadata +44 -31
- data/app_generators/sproutcore/templates/environment.yml +0 -4
- data/environment.yml +0 -9
@@ -0,0 +1,128 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// SC.TextCellView
|
3
|
+
// ==========================================================================
|
4
|
+
|
5
|
+
require('views/collection/collection_item') ;
|
6
|
+
|
7
|
+
/** @class
|
8
|
+
|
9
|
+
A Text Cell can display some textual or HTML content based on a content
|
10
|
+
object. Unlike a label view, a text cell relies on an owner view (usually
|
11
|
+
a collection view) to handle all of its event management and many of its
|
12
|
+
drawing properties and functions.
|
13
|
+
|
14
|
+
@extends SC.View
|
15
|
+
@author AuthorName
|
16
|
+
@version 0.1
|
17
|
+
*/
|
18
|
+
SC.TextCellView = SC.View.extend(SC.CollectionItem,
|
19
|
+
/** @scope SC.TextCellView.prototype */ {
|
20
|
+
|
21
|
+
emptyElement: '<div class="text-cell collection-item"></div>',
|
22
|
+
|
23
|
+
/**
|
24
|
+
The content object this text item view will display.
|
25
|
+
*/
|
26
|
+
content: null,
|
27
|
+
|
28
|
+
/**
|
29
|
+
The owner view of this cell. The TextCell relies on this
|
30
|
+
view to provide many of its behavioral defaults and for
|
31
|
+
event handling.
|
32
|
+
*/
|
33
|
+
owner: null,
|
34
|
+
|
35
|
+
/**
|
36
|
+
If true, value will be escaped to avoid scripting attacks.
|
37
|
+
|
38
|
+
This is a default value that can be overridden by the
|
39
|
+
settings on the owner view.
|
40
|
+
*/
|
41
|
+
escapeHtml: true,
|
42
|
+
|
43
|
+
/**
|
44
|
+
If true, then the value will be localized.
|
45
|
+
|
46
|
+
This is a default default that can be overidden by the
|
47
|
+
settings in the owner view.
|
48
|
+
*/
|
49
|
+
localize: false,
|
50
|
+
|
51
|
+
/**
|
52
|
+
Set this to a validator or to a function and the value
|
53
|
+
will be passed through it before being set.
|
54
|
+
|
55
|
+
This is a default default that can be overidden by the
|
56
|
+
settings in the owner view.
|
57
|
+
*/
|
58
|
+
formatter: null,
|
59
|
+
|
60
|
+
displayProperty: null,
|
61
|
+
|
62
|
+
// invoked whenever the content object changes.
|
63
|
+
_contentObserver: function() {
|
64
|
+
var content = this.get('content') ;
|
65
|
+
if (this._content == content) return ;
|
66
|
+
var f = this._boundValueDidChange() ;
|
67
|
+
|
68
|
+
// stop observing the old display property, if there is one.
|
69
|
+
if (this._content && this._displayProperty) {
|
70
|
+
this._content.removeObserver(this._displayProperty, f) ;
|
71
|
+
}
|
72
|
+
|
73
|
+
// start observing the new display property, if there is one
|
74
|
+
this._displayProperty = this._getDefault('displayProperty') ;
|
75
|
+
this._content = content ;
|
76
|
+
if (this._content && this._displayProperty) {
|
77
|
+
this._content.addObserver(this._displayProperty, f) ;
|
78
|
+
}
|
79
|
+
|
80
|
+
// notify value did change
|
81
|
+
this._valueDidChange() ;
|
82
|
+
}.observes('content'),
|
83
|
+
|
84
|
+
/**
|
85
|
+
@private
|
86
|
+
|
87
|
+
Invoked whenever the monitored value on the content object
|
88
|
+
changes.
|
89
|
+
|
90
|
+
The value processed is either the displayProperty, if set, or
|
91
|
+
it is the content object itself.
|
92
|
+
*/
|
93
|
+
_valueDidChange: function() {
|
94
|
+
var content = this.get('content') ;
|
95
|
+
var value = (content && this._displayProperty) ? content.get(this._displayProperty) : content;
|
96
|
+
var owner = this.get('owner') ;
|
97
|
+
|
98
|
+
// prepare the value...
|
99
|
+
|
100
|
+
// 1. apply the formatter
|
101
|
+
var formatter = this._getDefault('formatter') ;
|
102
|
+
if (formatter) {
|
103
|
+
var formattedValue = ($type(formatter) == T_FUNCTION) ? formatter(value, this) : formatter.fieldValueForObject(value, this) ;
|
104
|
+
if (formattedValue != null) value = formattedValue ;
|
105
|
+
}
|
106
|
+
|
107
|
+
// 2. If the returned value is not a string, convert it.
|
108
|
+
if (($type(value) != T_NULL) && value.toString) value = value.toString() ;
|
109
|
+
|
110
|
+
// 3. Localize
|
111
|
+
if (value && this._getDefault('localize')) value = value.loc() ;
|
112
|
+
|
113
|
+
// 4. Escape HTML
|
114
|
+
if (value && this._getDefault('escapeHtml')) value = value.escapeHTML() ;
|
115
|
+
|
116
|
+
this.set('asHTML', value || '') ;
|
117
|
+
},
|
118
|
+
|
119
|
+
_boundValueDidChange: function() {
|
120
|
+
return this._boundValueDidChange = this._boundValueDidChange || this._valueDidChange.bind(this);
|
121
|
+
},
|
122
|
+
|
123
|
+
// Retrieves the default value from the owner or locally.
|
124
|
+
_getDefault: function(keyName) {
|
125
|
+
var ret = (this.owner) ? this.owner.get(keyName) : null ;
|
126
|
+
return (ret != null) ? ret : this.get(keyName) ;
|
127
|
+
}
|
128
|
+
}) ;
|
@@ -19,10 +19,14 @@ SC.LabelView = SC.View.extend({
|
|
19
19
|
isEditing: false,
|
20
20
|
|
21
21
|
|
22
|
-
|
22
|
+
/**
|
23
|
+
set to true to have any markup in the content escaped.
|
24
|
+
*/
|
23
25
|
escapeHTML: true,
|
24
26
|
|
25
|
-
|
27
|
+
/**
|
28
|
+
set to true to have the value you set automatically localized.
|
29
|
+
*/
|
26
30
|
localize: false,
|
27
31
|
|
28
32
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Sproutcore.ScrollView
|
3
|
+
// ==========================================================================
|
4
|
+
|
5
|
+
require('views/container') ;
|
6
|
+
|
7
|
+
/** @class
|
8
|
+
|
9
|
+
The scroll view is used throughout SproutCore anytime you need to display
|
10
|
+
content that can be scrolled. Although you can make any div scrollable in
|
11
|
+
HTML using CSS, SC.ScrollView provides a number of additional advantages
|
12
|
+
including support for incremental rendering, auto-scrolling during a
|
13
|
+
drag operations and support for custom scroll bars.
|
14
|
+
|
15
|
+
Scroll views are generally included automatically if you use the built-in
|
16
|
+
view helpers in SproutCore. Depending on the views you are writing, you may
|
17
|
+
want to use scroll views yourself as well. The following sections describe
|
18
|
+
how you can use the scroll view to support incremental rendering and auto-
|
19
|
+
scrolling dragging.
|
20
|
+
|
21
|
+
h3. Using Scroll Views for Incremental Rendering
|
22
|
+
|
23
|
+
Coming Soon...
|
24
|
+
|
25
|
+
@extends SC.View
|
26
|
+
@author Charles Jolley
|
27
|
+
@version 1.0
|
28
|
+
*/
|
29
|
+
SC.ScrollView = SC.View.extend(
|
30
|
+
/** @scope SC.ScrollView.prototype */ {
|
31
|
+
|
32
|
+
emptyElement: '<div class="sc-scroll-view"></div>'
|
33
|
+
|
34
|
+
}) ;
|
@@ -466,10 +466,8 @@ SC.View = SC.Responder.extend(SC.PathModule,
|
|
466
466
|
// if you cached the frame, you can use this to clear that cache so that it
|
467
467
|
// will now track with the frame in the document.
|
468
468
|
flushFrameCache: function() {
|
469
|
-
|
470
|
-
|
471
|
-
this._frameCached = false;
|
472
|
-
}
|
469
|
+
this._frame = null ;
|
470
|
+
this._frameCached = false;
|
473
471
|
},
|
474
472
|
|
475
473
|
// This property returns a DOM ELEMENT that is the offset parent for
|
@@ -1344,6 +1342,14 @@ SC.View.mixin({
|
|
1344
1342
|
return this.viewFor.apply(this,args) ;
|
1345
1343
|
},
|
1346
1344
|
|
1345
|
+
// extend works just like a normal extend except that we need to delete the cached empty
|
1346
|
+
// element.
|
1347
|
+
extend: function(configs) {
|
1348
|
+
var ret = SC.Object.extend.apply(this, arguments) ;
|
1349
|
+
ret.prototype._cachedEmptyElement = null ;
|
1350
|
+
return ret ;
|
1351
|
+
},
|
1352
|
+
|
1347
1353
|
// define your view as an outlet.
|
1348
1354
|
outletFor: function(path) {
|
1349
1355
|
var view = this ;
|
@@ -1387,3 +1393,5 @@ SC._ViewCreator = document.createElement('div') ;
|
|
1387
1393
|
|
1388
1394
|
// This div can be used to hold elements you don't want on the page right now.
|
1389
1395
|
SC.NodeCache = document.createElement('div') ;
|
1396
|
+
|
1397
|
+
console.log('SC.View = %@'.fmt(SC.View)) ;
|
@@ -34,20 +34,12 @@ EOS
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def add_options!(opts)
|
37
|
-
|
38
|
-
# opts.separator 'Options:'
|
39
|
-
# For each option below, place the default
|
40
|
-
# at the top of the file next to "default_options"
|
41
|
-
# opts.on("-a", "--author=\"Your Name\"", String,
|
42
|
-
# "Some comment about this option",
|
43
|
-
# "Default: none") { |options[:author]| }
|
44
|
-
# opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
37
|
+
opts.on('-l', "--library=LIBRARY_ROOT", String, "Specify an alternate library root other than current working directory", "Default: working directory") { |options[:library_root] | }
|
45
38
|
end
|
46
39
|
|
47
40
|
def extract_options
|
48
41
|
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
49
|
-
|
50
|
-
# raw instance variable value.
|
51
|
-
# @author = options[:author]
|
42
|
+
@destination_root = File.expand_path(options[:library_root]) unless options[:library_root].nil?
|
52
43
|
end
|
44
|
+
|
53
45
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
/* Default CSS for welcome page. Delete this styling and replace it with your own. */
|
2
|
+
|
3
|
+
.sc-welcome {
|
4
|
+
position: absolute ;
|
5
|
+
top: 0px;
|
6
|
+
left: 0px;
|
7
|
+
right: 0px;
|
8
|
+
bottom: 0px;
|
9
|
+
background-color: white ;
|
10
|
+
}
|
11
|
+
|
12
|
+
.sc-welcome img.logo {
|
13
|
+
position: absolute ;
|
14
|
+
bottom: 80px;
|
15
|
+
left: 50%;
|
16
|
+
margin-left: -20px;
|
17
|
+
}
|
18
|
+
|
19
|
+
/* @group Message */
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
.sc-welcome .message {
|
24
|
+
max-width: 800px;
|
25
|
+
margin-left: auto ;
|
26
|
+
margin-right: auto;
|
27
|
+
margin-top: 100px;
|
28
|
+
position: relative;
|
29
|
+
}
|
30
|
+
|
31
|
+
.sc-welcome h1 {
|
32
|
+
border: none ;
|
33
|
+
padding: 0;
|
34
|
+
margin: 0;
|
35
|
+
letter-spacing: -3px;
|
36
|
+
font: normal 6.4em "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
|
37
|
+
}
|
38
|
+
|
39
|
+
.sc-welcome h3 {
|
40
|
+
margin: 8px 12px;
|
41
|
+
padding: 0;
|
42
|
+
font: 1.5em "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
|
43
|
+
color: #808080;
|
44
|
+
}
|
45
|
+
|
46
|
+
/* @end */
|
47
|
+
|
48
|
+
/* @group Sticky Note */
|
49
|
+
|
50
|
+
.sc-welcome .sticky-note {
|
51
|
+
position: absolute ;
|
52
|
+
right: 0;
|
53
|
+
top: -70px;
|
54
|
+
width: 320px;
|
55
|
+
height: 300px;
|
56
|
+
padding: 60px;
|
57
|
+
padding-right: 20px;
|
58
|
+
background: url(/static/sproutcore/_src/english.lproj/images/sticky-note.png) no-repeat center center;
|
59
|
+
font: 1.3em "Comic Sans MS", "Comic Sans", Arial, Helvetica, Geneva, sans-serif;
|
60
|
+
color: #5f4700;
|
61
|
+
}
|
62
|
+
|
63
|
+
.sc-welcome .sticky-note p {
|
64
|
+
font-weight: bold ;
|
65
|
+
}
|
66
|
+
|
67
|
+
.sc-welcome .sticky-note ul {
|
68
|
+
padding: 0 10px ;
|
69
|
+
}
|
70
|
+
|
71
|
+
.sc-welcome .sticky-note li {
|
72
|
+
margin: 8px 0 ;
|
73
|
+
}
|
74
|
+
|
75
|
+
/* @end */
|
@@ -1,3 +1,18 @@
|
|
1
1
|
<% content_for('body') do %>
|
2
|
-
<
|
3
|
-
|
2
|
+
<div class="sc-welcome">
|
3
|
+
<img class="logo" src="<%= static_url('images/sproutcore-logo') %>" />
|
4
|
+
<div class="message">
|
5
|
+
<h1>Welcome!</h1>
|
6
|
+
<h3>You are now running SproutCore.</h3>
|
7
|
+
<div class="sticky-note">
|
8
|
+
<p>Things to do:</p>
|
9
|
+
<ul>
|
10
|
+
<li>Add a model:<br/>sc-gen model contacts/my_model</li>
|
11
|
+
<li>Add a controller:<br/>sc-gen controller contacts/my_controller</li>
|
12
|
+
<li>Edit english.lproj/body.rhtml</li>
|
13
|
+
<li>Build for deployment:<br />sc-build</li>
|
14
|
+
</ul>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<% end %>
|
@@ -7,5 +7,37 @@ require('core') ;
|
|
7
7
|
<%= client_namespace %>.FIXTURES = <%= client_namespace %>.FIXTURES.concat([
|
8
8
|
|
9
9
|
// TODO: Add your data fixtures here.
|
10
|
+
// All fixture records must have a unique guid and a type matching the
|
11
|
+
// name of your contact. See the example below.
|
12
|
+
|
13
|
+
// { guid: 1,
|
14
|
+
// type: 'Contact',
|
15
|
+
// firstName: "Michael",
|
16
|
+
// lastName: "Scott"
|
17
|
+
// },
|
18
|
+
//
|
19
|
+
// { guid: 2,
|
20
|
+
// type: 'Contact',
|
21
|
+
// firstName: "Dwight",
|
22
|
+
// lastName: "Schrute"
|
23
|
+
// },
|
24
|
+
//
|
25
|
+
// { guid: 3,
|
26
|
+
// type: 'Contact',
|
27
|
+
// firstName: "Jim",
|
28
|
+
// lastName: "Halpert"
|
29
|
+
// },
|
30
|
+
//
|
31
|
+
// { guid: 4,
|
32
|
+
// type: 'Contact',
|
33
|
+
// firstName: "Pam",
|
34
|
+
// lastName: "Beesly"
|
35
|
+
// },
|
36
|
+
//
|
37
|
+
// { guid: 5,
|
38
|
+
// type: 'Contact',
|
39
|
+
// firstName: "Ryan",
|
40
|
+
// lastName: "Howard"
|
41
|
+
// }
|
10
42
|
|
11
43
|
]);
|
@@ -18,14 +18,30 @@ module SproutCore
|
|
18
18
|
include SproutCore::Helpers::StaticHelper
|
19
19
|
include SproutCore::ViewHelpers
|
20
20
|
|
21
|
-
attr_reader :entry, :bundle, :
|
21
|
+
attr_reader :entry, :bundle, :entries, :filename, :language, :library
|
22
22
|
|
23
|
-
def initialize(entry, bundle)
|
23
|
+
def initialize(entry, bundle, deep=true)
|
24
24
|
@entry = nil
|
25
25
|
@language = entry.language
|
26
|
-
@filenames = entry.composite.nil? ? [entry.filename] : entry.composite
|
27
26
|
@bundle = bundle
|
28
27
|
@library = bundle.library
|
28
|
+
|
29
|
+
# Find all of the entries that need to be included. If deep is true, the include
|
30
|
+
# required bundles. Example composite entries to include their members.
|
31
|
+
if deep
|
32
|
+
@entries = bundle.all_required_bundles.map do |cur_bundle|
|
33
|
+
ret = (cur_bundle == bundle) ? [entry] : cur_bundle.entries_for(:html, :language => language, :hidden => :include)
|
34
|
+
ret.map do |e|
|
35
|
+
e.composite? ? e.composite.map { |c| cur_bundle.entry_for(c, :hidden => :include) } : [e]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@entries = @entries.flatten.compact.uniq
|
39
|
+
else
|
40
|
+
@entries = entry.composite? ? entry.composite.map { |c| x.entry_for(c) } : [entry]
|
41
|
+
end
|
42
|
+
|
43
|
+
# Clean out any composites we might have collected. They have already been expanded.
|
44
|
+
@entries.reject! { |entry| entry.composite? }
|
29
45
|
end
|
30
46
|
|
31
47
|
# Actually builds the HTML file from the entry (actually from any composite entries)
|
@@ -35,7 +51,7 @@ module SproutCore
|
|
35
51
|
|
36
52
|
# Render each filename. By default, the output goes to the resources string
|
37
53
|
@content_for_resources = ''
|
38
|
-
|
54
|
+
entries.each { |fn| _render_one(fn) }
|
39
55
|
|
40
56
|
# Finally, render the layout. This should produce the final output to return
|
41
57
|
input = File.read(@layout_path)
|
@@ -43,9 +59,9 @@ module SproutCore
|
|
43
59
|
end
|
44
60
|
|
45
61
|
# render a single entry
|
46
|
-
def _render_one(
|
47
|
-
@
|
48
|
-
@
|
62
|
+
def _render_one(entry)
|
63
|
+
@entry = entry
|
64
|
+
@filename = @entry.filename
|
49
65
|
|
50
66
|
# avoid double render of layout path
|
51
67
|
return if @entry.source_path == @layout_path
|
@@ -68,11 +84,13 @@ module SproutCore
|
|
68
84
|
|
69
85
|
end
|
70
86
|
|
71
|
-
|
72
|
-
|
87
|
+
# Builds an html file for the specified entry. If deep is true, then this will also
|
88
|
+
# find all of the html entries for any required bundles and include them in the built
|
89
|
+
# html file.
|
90
|
+
def self.build_html(entry, bundle, deep=true)
|
91
|
+
context = HtmlContext.new(entry, bundle, deep)
|
73
92
|
output = context.build
|
74
93
|
|
75
|
-
puts "saving: #{entry.filename} to #{entry.build_path}: size: #{output.size}"
|
76
94
|
FileUtils.mkdir_p(File.dirname(entry.build_path))
|
77
95
|
f = File.open(entry.build_path, 'w')
|
78
96
|
f.write(output)
|
@@ -82,7 +100,7 @@ module SproutCore
|
|
82
100
|
|
83
101
|
# Building a test is just like building a single page except that we do not include
|
84
102
|
# all the other html templates in the project
|
85
|
-
def self.build_test(entry, bundle); build_html(entry, bundle); end
|
103
|
+
def self.build_test(entry, bundle); build_html(entry, bundle, false); end
|
86
104
|
|
87
105
|
end
|
88
106
|
end
|