sproutcore 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. data/Manifest.txt +42 -29
  2. data/README.txt +1 -1
  3. data/Rakefile +5 -0
  4. data/app_generators/sproutcore/sproutcore_generator.rb +4 -4
  5. data/app_generators/sproutcore/templates/sc-config.rb +72 -0
  6. data/bin/sc-build +2 -0
  7. data/clients/sc_docs/controllers/docs.js +1 -0
  8. data/clients/sc_docs/english.lproj/body.rhtml +5 -0
  9. data/clients/sc_docs/views/doc_frame.js +1 -1
  10. data/clients/sc_test_runner/controllers/runner.js +2 -2
  11. data/clients/sc_test_runner/english.lproj/body.rhtml +5 -0
  12. data/clients/sc_test_runner/main.js +12 -12
  13. data/clients/sc_test_runner/models/test.js +3 -0
  14. data/clients/sc_test_runner/views/test_label.js +1 -1
  15. data/config/hoe.rb +2 -0
  16. data/frameworks/sproutcore/controllers/array.js +132 -125
  17. data/frameworks/sproutcore/drag/drag.js +5 -2
  18. data/frameworks/sproutcore/english.lproj/buttons.css +64 -64
  19. data/frameworks/sproutcore/english.lproj/collections.css +82 -0
  20. data/frameworks/sproutcore/english.lproj/images/buttons-sprite.png +0 -0
  21. data/frameworks/sproutcore/english.lproj/images/sproutcore-logo.png +0 -0
  22. data/frameworks/sproutcore/english.lproj/images/sticky-note.png +0 -0
  23. data/frameworks/sproutcore/english.lproj/menu.css +1 -1
  24. data/frameworks/sproutcore/english.lproj/theme.css +13 -4
  25. data/frameworks/sproutcore/foundation/array.js +24 -2
  26. data/frameworks/sproutcore/foundation/benchmark.js +12 -5
  27. data/frameworks/sproutcore/foundation/observable.js +62 -1
  28. data/frameworks/sproutcore/foundation/utils.js +16 -0
  29. data/frameworks/sproutcore/tests/views/label_item.rhtml +21 -0
  30. data/frameworks/sproutcore/tests/views/list.rhtml +21 -0
  31. data/frameworks/sproutcore/tests/views/scroll.rhtml +21 -0
  32. data/frameworks/sproutcore/views/collection.js +401 -73
  33. data/frameworks/sproutcore/views/collection/collection_item.js +36 -0
  34. data/frameworks/sproutcore/views/collection/grid.js +149 -0
  35. data/frameworks/sproutcore/views/collection/image_cell.js +154 -0
  36. data/frameworks/sproutcore/views/collection/list.js +115 -0
  37. data/frameworks/sproutcore/views/collection/text_cell.js +128 -0
  38. data/frameworks/sproutcore/views/image.js +1 -1
  39. data/frameworks/sproutcore/views/label.js +6 -2
  40. data/frameworks/sproutcore/views/scroll.js +34 -0
  41. data/frameworks/sproutcore/views/view.js +12 -4
  42. data/generators/client/client_generator.rb +3 -11
  43. data/generators/client/templates/english.lproj/body.css +75 -0
  44. data/generators/client/templates/english.lproj/body.rhtml +17 -2
  45. data/generators/model/templates/fixture.js +32 -0
  46. data/lib/sproutcore/build_tools/html_builder.rb +29 -11
  47. data/lib/sproutcore/build_tools/resource_builder.rb +1 -1
  48. data/lib/sproutcore/bundle.rb +19 -7
  49. data/lib/sproutcore/library.rb +39 -21
  50. data/lib/sproutcore/merb/bundle_controller.rb +3 -8
  51. data/lib/sproutcore/version.rb +1 -1
  52. data/lib/sproutcore/view_helpers.rb +7 -5
  53. data/lib/sproutcore/view_helpers/core_views.rb +11 -3
  54. data/sc-config.rb +7 -0
  55. data/tasks/deployment.rake +15 -2
  56. metadata +44 -31
  57. data/app_generators/sproutcore/templates/environment.yml +0 -4
  58. 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
+ }) ;
@@ -8,7 +8,7 @@ require('views/view') ;
8
8
  lc_cnt = 0 ;
9
9
 
10
10
  SC.ImageView = SC.View.extend({
11
- emptyElement: '<img />',
11
+ emptyElement: '<img src="%@" />'.fmt(static_url('blank')),
12
12
 
13
13
  status: 'unknown',
14
14
 
@@ -19,10 +19,14 @@ SC.LabelView = SC.View.extend({
19
19
  isEditing: false,
20
20
 
21
21
 
22
- // set to true to have any markup in the content escaped.
22
+ /**
23
+ set to true to have any markup in the content escaped.
24
+ */
23
25
  escapeHTML: true,
24
26
 
25
- // set to true to have the value you set automatically localized.
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
- if (this._frameCached) {
470
- this._frame = null ;
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
- # opts.separator ''
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
- # Templates can access these value via the attr_reader-generated methods, but not the
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
- <h1>Welcome to SproutCore</h1>
3
- <% end %>
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, :filenames, :filename, :language, :library
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
- filenames.each { |fn| _render_one(fn) }
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(filename)
47
- @filename = filename
48
- @entry = bundle.entry_for(filename, :hidden => :include, :language => language)
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
- def self.build_html(entry, bundle)
72
- context = HtmlContext.new(entry,bundle)
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