sproutcore 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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