sproutcore 0.9.14 → 0.9.15

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 (61) hide show
  1. data/History.txt +43 -0
  2. data/Manifest.txt +12 -3
  3. data/bin/sc-build +19 -3
  4. data/bin/sc-install +5 -0
  5. data/bin/sc-remove +5 -0
  6. data/bin/sc-update +5 -0
  7. data/frameworks/prototype/prototype.js +267 -230
  8. data/frameworks/sproutcore/HISTORY +281 -135
  9. data/frameworks/sproutcore/controllers/array.js +133 -22
  10. data/frameworks/sproutcore/controllers/collection.js +4 -5
  11. data/frameworks/sproutcore/controllers/object.js +8 -2
  12. data/frameworks/sproutcore/core.js +361 -159
  13. data/frameworks/sproutcore/{foundation → debug}/unittest.js +3 -3
  14. data/frameworks/sproutcore/english.lproj/detect-browser +1 -1
  15. data/frameworks/sproutcore/english.lproj/theme.css +2 -2
  16. data/frameworks/sproutcore/foundation/application.js +6 -1
  17. data/frameworks/sproutcore/foundation/benchmark.js +37 -11
  18. data/frameworks/sproutcore/foundation/date.js +1 -1
  19. data/frameworks/sproutcore/foundation/enumerator.js +105 -0
  20. data/frameworks/sproutcore/foundation/object.js +19 -20
  21. data/frameworks/sproutcore/foundation/responder.js +1 -1
  22. data/frameworks/sproutcore/foundation/set.js +164 -57
  23. data/frameworks/sproutcore/foundation/string.js +151 -47
  24. data/frameworks/sproutcore/foundation/utils.js +84 -3
  25. data/frameworks/sproutcore/lib/collection_view.rb +1 -0
  26. data/frameworks/sproutcore/license.js +28 -0
  27. data/frameworks/sproutcore/mixins/array.js +73 -209
  28. data/frameworks/sproutcore/mixins/delegate_support.js +1 -1
  29. data/frameworks/sproutcore/mixins/enumerable.js +1006 -0
  30. data/frameworks/sproutcore/mixins/observable.js +153 -84
  31. data/frameworks/sproutcore/mixins/selection_support.js +13 -1
  32. data/frameworks/sproutcore/models/record.js +74 -27
  33. data/frameworks/sproutcore/models/store.js +7 -3
  34. data/frameworks/sproutcore/server/rails_server.js +82 -0
  35. data/frameworks/sproutcore/server/rest_server.js +178 -0
  36. data/frameworks/sproutcore/{foundation → server}/server.js +101 -48
  37. data/frameworks/sproutcore/tests/core/guidFor.rhtml +114 -0
  38. data/frameworks/sproutcore/tests/foundation/array.rhtml +6 -7
  39. data/frameworks/sproutcore/tests/foundation/set.rhtml +254 -0
  40. data/frameworks/sproutcore/tests/mixins/enumerable.rhtml +421 -0
  41. data/frameworks/sproutcore/tests/mixins/observable.rhtml +127 -0
  42. data/frameworks/sproutcore/tests/models/model.rhtml +23 -22
  43. data/frameworks/sproutcore/tests/views/collection/incremental_rendering.rhtml +2 -2
  44. data/frameworks/sproutcore/tests/views/view/clippingFrame.rhtml +112 -109
  45. data/frameworks/sproutcore/tests/views/view/frame.rhtml +91 -88
  46. data/frameworks/sproutcore/validators/date.js +1 -7
  47. data/frameworks/sproutcore/views/collection/collection.js +7 -2
  48. data/frameworks/sproutcore/views/list_item.js +141 -3
  49. data/frameworks/sproutcore/views/split.js +14 -11
  50. data/frameworks/sproutcore/views/view.js +9 -6
  51. data/lib/sproutcore/build_tools/html_builder.rb +19 -3
  52. data/lib/sproutcore/build_tools/resource_builder.rb +9 -3
  53. data/lib/sproutcore/bundle.rb +21 -0
  54. data/lib/sproutcore/bundle_manifest.rb +64 -20
  55. data/lib/sproutcore/helpers/capture_helper.rb +2 -2
  56. data/lib/sproutcore/library.rb +33 -9
  57. data/lib/sproutcore/merb/bundle_controller.rb +16 -5
  58. data/lib/sproutcore/version.rb +1 -1
  59. data/lib/sproutcore/view_helpers.rb +1 -1
  60. data/{sc-config.rb → sc-config} +5 -2
  61. metadata +24 -5
@@ -5,30 +5,47 @@
5
5
 
6
6
  // These are basic enhancements to the string class used throughout
7
7
  // SproutCore.
8
- // capitalize a string.
9
- Object.extend(String.prototype,{
10
-
11
- // Capitalize a string.
12
- //
13
- // mode: optional. 'each' - capitalize each word. the default.
14
- // 'first' - capitalize the first word only.
15
-
16
- capitalize: function(mode) {
17
- var words = (mode == 'first') ? this : this.split(' ') ;
18
- words = words.map(function(word) {
19
- if (word.length == 0) return word ;
20
- return word.charAt(0).toUpperCase() + word.substring(1) ;
21
- }) ;
22
- return words.join(' ') ;
23
- },
24
8
 
9
+ SC.STRING_TITLEIZE_REGEXP = (/([\s|\-|\_|\n])([^\s|\-|\_|\n]?)/g);
10
+
11
+ /**
12
+ @namespace
13
+
14
+ SproutCore implements a variety of enhancements to the built-in String
15
+ object that make it easy to perform common substitutions and conversions.
16
+
17
+ Most of the utility methods defined here mirror those found in Prototype
18
+ 1.6.
19
+
20
+ @since SproutCore 1.0
21
+ */
22
+ SC.String = {
23
+
25
24
  // Interpolate string. looks for %@ or %@1; to control the order of params.
26
- format: function() {
27
- var args = $A(arguments) ;
25
+ /**
26
+ Apply formatting options to the string. This will look for occurrences
27
+ of %@ in your string and substitute them with the arguments you pass into
28
+ this method. If you want to control the specific order of replacement,
29
+ you can add a number after the key as well to indicate which argument
30
+ you want to insert.
31
+
32
+ Ordered insertions are most useful when building loc strings where values
33
+ you need to insert may appear in different orders.
34
+
35
+ h3. Examples
28
36
 
37
+ {{{
38
+ "Hello %@ %@".fmt('John', 'Doe') => "Hello John Doe"
39
+ "Hello %@2, %@1".fmt('John', 'Doe') => "Hello Doe, John"
40
+ }}}
41
+
42
+ @param args {Object...} optional arguments
43
+ @returns {String} formatted string
44
+ */
45
+ fmt: function() {
29
46
  // first, replace any ORDERED replacements.
30
47
  var str = this.gsub(/%@([0-9]+)/, function(m) {
31
- return (args[parseInt(m[1],0)-1] || '').toString();
48
+ return (arguments[parseInt(m[1],0)-1] || '').toString();
32
49
  }) ;
33
50
 
34
51
  // now, replace any remaining %@ items. Use this indexOf() method b/c
@@ -36,13 +53,14 @@ Object.extend(String.prototype,{
36
53
  var ret = [] ;
37
54
  var idx = -1 ;
38
55
  var loc = 0 ;
56
+ var argIdx = 0;
39
57
  while((idx = str.indexOf("%@",loc)) >= 0) {
40
58
  // slice off initial part of string and push into ret. update loc.
41
59
  ret.push(str.slice(loc,idx)) ;
42
60
  loc = idx + 2 ; // 2 to skip '%@'.
43
61
 
44
62
  // add in replacement.
45
- var value = args.shift() ;
63
+ var value = arguments[argIdx++] ;
46
64
  if (value && value.toString) value = value.toString() ;
47
65
  ret.push(value) ;
48
66
  }
@@ -56,8 +74,15 @@ Object.extend(String.prototype,{
56
74
  return (ret.length > 1) ? ret.join('') : ret[0] ;
57
75
  },
58
76
 
59
- // localize a string. Also interpolates any items you pass just like
60
- // format().
77
+ /**
78
+ Localizes the string. This will look up the reciever string as a key
79
+ in the current Strings hash. If the key matches, the loc'd value will be
80
+ used. The resulting string will also be passed through fmt() to insert
81
+ any variables.
82
+
83
+ @param args {Object...} optional arguments to interpolate also
84
+ @returns {String} the localized and formatted string.
85
+ */
61
86
  loc: function() {
62
87
  // NB: This could be implemented as a wrapper to locWithDefault() but
63
88
  // it would add some overhead to deal with the arguments and adds stack
@@ -66,60 +91,139 @@ Object.extend(String.prototype,{
66
91
  var kit = String[String.currentLanguage()];
67
92
  var str = kit[this] ;
68
93
  if (!str) str = String.English[this] || this ;
69
- return str.format.apply(str,arguments) ;
94
+ return str.fmt.apply(str,arguments) ;
70
95
  },
71
-
72
- // this works just like loc except it will return the first argument
73
- // as a default if the matching value is not found.
96
+
97
+ /**
98
+ Works just like loc() except that it will return the passed default
99
+ string if a matching key is not found.
100
+
101
+ @param def {String} the default to return
102
+ @param args {Object...} optional formatting arguments
103
+ @returns {String} localized and formatted string
104
+ */
74
105
  locWithDefault: function(def) {
75
106
  var kit = String[String.currentLanguage()];
76
107
  var str = kit[this] ;
77
108
  if (!str) str = String.English[this] || def ;
78
- var args = $A(arguments) ;
109
+ var args = SC.$A(arguments) ;
79
110
  args.shift() ; // escape def.
80
- return str.format.apply(str, args) ;
111
+ return str.fmt.apply(str, args) ;
112
+ },
113
+
114
+ /**
115
+ Capitalizes a string.
116
+ @return {String} capitalized string
117
+ */
118
+ capitalize: function() {
119
+ return this.charAt(0).toUpperCase() + this.substring(1) ;
120
+ },
121
+
122
+ /**
123
+ Capitalized every word in the string, separated by spaces or dashes.
124
+ @return {String} titleized string.
125
+ */
126
+ titleize: function() {
127
+ return this.replace(SC.STRING_TITLEIZE_REGEXP,
128
+ function(str,separater,character) {
129
+ return (character) ? (' ' + character.toUpperCase()) : ' ';
130
+ }).capitalize() ;
131
+ },
132
+
133
+ /**
134
+ Camelizes a string. This will take any words separated by spaces, dashes
135
+ or underscores and convert them into camelCase.
136
+
137
+ h3. Examples
138
+
139
+ {{{
140
+ "my favorite items".camelize() => "myFavoriteItems"
141
+ "css-class-name".camelize() => "cssClassName"
142
+ "action_name".camelize() => "actionName"
143
+ }}}
144
+
145
+ @returns {String} camelized string
146
+ */
147
+ camelize: function() {
148
+ var parts = this.split('-'), len = parts.length;
149
+ if (len == 1) return parts[0];
150
+
151
+ var camelized = this.charAt(0) == '-'
152
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
153
+ : parts[0];
154
+
155
+ for (var i = 1; i < len; i++)
156
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
157
+
158
+ return camelized;
81
159
  },
160
+
82
161
 
162
+ /**
163
+ Converts the string into a class name. This method will camelize your
164
+ string and then capitalize the first letter.
165
+ */
83
166
  classify: function() {
84
167
  return this.camelize().capitalize() ;
85
168
  },
86
169
 
170
+ /**
171
+ Converts a camelized string into all lower case separated by underscores.
172
+
173
+ @returns {String} the decamelized string.
174
+ */
87
175
  decamelize: function() {
88
176
  return this.replace(/([a-z])([A-Z])/g,'$1_$2').toLowerCase();
89
177
  },
90
178
 
179
+ /**
180
+ Converts a camelized string or a string with spaces or underscores into
181
+ a string with components separated by dashes.
182
+
183
+ @returns {String} the dasherized string.
184
+ */
91
185
  dasherize: function() {
92
186
  return this.decamelize().replace(/[ _]/g,'-') ;
93
187
  },
94
188
 
189
+ /**
190
+ Converts a camelized string or a string with dashes or underscores into
191
+ a string with components separated by spaces.
192
+
193
+ @returns {String} the humanized string.
194
+ */
95
195
  humanize: function() {
96
196
  return this.decamelize().replace(/[-_]/g,' ') ;
97
197
  },
98
198
 
99
- toHref: function() {
100
- if (this.match(/.+@.+\...+/)) {
101
- return 'mailto:' + this;
102
- } else if (this.indexOf('http://') != 0 && this.indexOf('https://') !=0 && this.match(/[^.]+\.[^.]+/)) {
103
- return 'http://' + this;
104
- } else {
105
- return this;
106
- }
107
- },
108
-
109
- trim: function ()
110
- {
199
+ /**
200
+ Removes any extra whitespace from the edges of the strings.
201
+
202
+ This method is also aliased as strip().
203
+
204
+ @returns {String} the trimmed string
205
+ */
206
+ trim: function () {
111
207
  return this.replace(/^\s+|\s+$/g,"");
112
208
  },
113
-
114
- strip: function()
115
- {
116
- return this.trim();
209
+
210
+ /**
211
+ Explodes a string into an array of characters.
212
+
213
+ @returns {Array}
214
+ */
215
+ toArray: function() {
216
+ return this.split('');
117
217
  }
118
218
 
119
- }) ;
219
+ } ;
220
+
221
+ // Deprecated, longer version of this method.
222
+ SC.String.format = SC.String.fmt;
223
+ SC.String.strip = SC.String.trim; // convenience alias.
120
224
 
121
- // Shorter alias of the format function.
122
- String.prototype.fmt = String.prototype.format ;
225
+ // Apply SC.String mixin to built-in String object
226
+ SC.mixin(String.prototype, SC.String) ;
123
227
 
124
228
  // Add strings for various languages to this collection. String.loc()
125
229
  // method will try to localize the string passed using the current language.
@@ -6,10 +6,75 @@
6
6
  // These are helpful utility functions for calculating range and rect values
7
7
 
8
8
 
9
- Object.extend(SC,
9
+ SC.mixin(
10
10
  /** @scope SC */
11
11
  {
12
12
 
13
+ _downloadFrames: 0, // count of download frames inserted into document
14
+
15
+ /**
16
+ Starts a download of the file at the named path.
17
+
18
+ Use this method when you want to cause a file to be downloaded to a users
19
+ desktop instead of having it display in the web browser. Note that your
20
+ server must return a header indicating that the file is intended for
21
+ download also.
22
+ */
23
+ download: function(path) {
24
+ var tempDLIFrame=document.createElement('iframe');
25
+ var frameId = 'DownloadFrame_' + this._downloadFrames;
26
+ tempDLIFrame.setAttribute('id',frameId);
27
+ tempDLIFrame.style.border='10px';
28
+ tempDLIFrame.style.width='0px';
29
+ tempDLIFrame.style.height='0px';
30
+ tempDLIFrame.style.position='absolute';
31
+ tempDLIFrame.style.top='-10000px';
32
+ tempDLIFrame.style.left='-10000px';
33
+ // Don't set the iFrame content yet if this is Safari
34
+ if (!(SC.isSafari())) {
35
+ tempDLIFrame.setAttribute('src',path);
36
+ }
37
+ document.getElementsByTagName('body')[0].appendChild(tempDLIFrame);
38
+ if (SC.isSafari()) {
39
+ tempDLIFrame.setAttribute('src',path);
40
+ }
41
+ this._downloadFrames = this._downloadFrames + 1;
42
+ if (!(SC.isSafari())) {
43
+ var r = function() {
44
+ document.body.removeChild(document.getElementById(frameId));
45
+ frameId = null;
46
+ } ;
47
+ var t = r.invokeLater(null, 2000);
48
+ }
49
+ //remove possible IE7 leak
50
+ tempDLIFrame = null;
51
+ },
52
+
53
+ /**
54
+ Takes a URL of any type and normalizes it into a fully qualified URL with
55
+ hostname. For example:
56
+
57
+ {{{
58
+ "some/path" => "http://localhost:4020/some/path"
59
+ "/some/path" => "http://localhost:4020/some/path"
60
+ "http://localhost:4020/some/path" => "http://localhost:4020/some/path"
61
+ }}}
62
+
63
+ @param url {String} the URL
64
+ @returns {String} the normalized URL
65
+ */
66
+ normalizeURL: function(url) {
67
+ if (url.slice(0,1) == '/') {
68
+ url = window.location.protocol + '//' + window.location.host + url ;
69
+ } else if ((url.slice(0,5) == 'http:') || (url.slice(0,6) == 'https:')) {
70
+ // no change
71
+ } else {
72
+ url = window.location.href + '/' + url ;
73
+ }
74
+ return url ;
75
+ },
76
+
77
+
13
78
  /** Return the left edge of the frame */
14
79
  minX: function(frame) {
15
80
  return frame.x;
@@ -142,9 +207,17 @@ Object.extend(SC,
142
207
 
143
208
  // add up all the offsets for the element.
144
209
  var element = el ;
210
+ var isFirefox3 = SC.Platform.Firefox >= 3 ;
145
211
  while (element) {
146
- valueT += (element.offsetTop || 0) + (element.clientTop || 0);
147
- valueL += (element.offsetLeft || 0) + (element.clientLeft || 0);
212
+ valueT += (element.offsetTop || 0);
213
+ if (!isFirefox3 || (element !== el)) {
214
+ valueT += (element.clientTop || 0);
215
+ }
216
+
217
+ valueL += (element.offsetLeft || 0);
218
+ if (!isFirefox3 || (element !== el)) {
219
+ valueL += (element.clientLeft || 0);
220
+ }
148
221
 
149
222
  // bizarely for FireFox if your offsetParent has a border, then it can
150
223
  // impact the offset.
@@ -158,6 +231,14 @@ Object.extend(SC,
158
231
  }
159
232
  valueL += left; valueT += top ;
160
233
  }
234
+
235
+ // In FireFox 3 -- the offsetTop/offsetLeft subtracts the clientTop/
236
+ // clientLeft of the offset parent.
237
+ var offsetParent = element.offsetParent ;
238
+ if ((SC.Platform.Firefox >= 3) && offsetParent) {
239
+ valueT -= offsetParent.clientTop ;
240
+ valueL -= offsetParent.clientLeft;
241
+ }
161
242
  }
162
243
 
163
244
  // Safari fix
@@ -32,6 +32,7 @@ view_helper :collection_view do
32
32
  property :can_delete_content
33
33
 
34
34
  property :content_icon_key
35
+ property :content_checkbox_key
35
36
 
36
37
  # Unless the developer passes something specific, automatically enable
37
38
  # has_content_icon if either icon property is specified.
@@ -0,0 +1,28 @@
1
+ //@license
2
+ // ==========================================================================
3
+ // SproutCore -- JavaScript Application Framework
4
+ // copyright 2006-2008, Sprout Systems, Inc. and contributors.
5
+ //
6
+ // Permission is hereby granted, free of charge, to any person obtaining a
7
+ // copy of this software and associated documentation files (the "Software"),
8
+ // to deal in the Software without restriction, including without limitation
9
+ // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ // and/or sell copies of the Software, and to permit persons to whom the
11
+ // Software is furnished to do so, subject to the following conditions:
12
+ //
13
+ // The above copyright notice and this permission notice shall be included in
14
+ // all copies or substantial portions of the Software.
15
+ //
16
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ // DEALINGS IN THE SOFTWARE.
23
+ //
24
+ // For more information about SproutCore, visit http://www.sproutcore.com
25
+ //
26
+ //
27
+ // ==========================================================================
28
+ //@license