middleman 2.0.9.pre.2 → 2.0.9.pre.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/CHANGELOG +9 -0
  2. data/features/builder.feature +6 -0
  3. data/features/data.feature +16 -1
  4. data/features/fonts.feature +11 -0
  5. data/features/relative_assets.feature +8 -2
  6. data/features/step_definitions/middleman_steps.rb +9 -2
  7. data/fixtures/data-app/config.rb +3 -0
  8. data/fixtures/data-app/data/pages.yml +6 -0
  9. data/fixtures/data-app/source/index.html.haml +1 -0
  10. data/fixtures/data-app/source/layout.haml +3 -0
  11. data/fixtures/fonts-app/config.rb +0 -0
  12. data/fixtures/fonts-app/source/fonts/StMarie-Thin.otf +0 -0
  13. data/fixtures/fonts-app/source/stylesheets/fonts.css.sass +3 -0
  14. data/fixtures/glob-app/config.rb +1 -0
  15. data/fixtures/glob-app/source/index.html.haml +6 -0
  16. data/fixtures/glob-app/source/stylesheets/site.css.sass +1 -0
  17. data/fixtures/test-app/config.rb +1 -0
  18. data/fixtures/test-app/data/test2.json +4 -0
  19. data/fixtures/test-app/source/data3.html.erb +1 -0
  20. data/lib/middleman/base.rb +8 -3
  21. data/lib/middleman/builder.rb +61 -22
  22. data/lib/middleman/cli.rb +2 -1
  23. data/lib/middleman/core_extensions/assets.rb +1 -1
  24. data/lib/middleman/core_extensions/compass.rb +6 -2
  25. data/lib/middleman/core_extensions/data.rb +20 -3
  26. data/lib/middleman/templates/html5.rb +1 -0
  27. data/lib/middleman/templates/mobile.rb +17 -0
  28. data/lib/middleman/templates/mobile/source/404.html +38 -0
  29. data/lib/middleman/templates/mobile/source/README.markdown +64 -0
  30. data/lib/middleman/templates/mobile/source/crossdomain.xml +25 -0
  31. data/lib/middleman/templates/mobile/source/css/style.css +236 -0
  32. data/lib/middleman/templates/mobile/source/default.appcache +17 -0
  33. data/lib/middleman/templates/mobile/source/humans.txt +43 -0
  34. data/lib/middleman/templates/mobile/source/img/h/apple-touch-icon.png +0 -0
  35. data/lib/middleman/templates/mobile/source/img/h/splash.png +0 -0
  36. data/lib/middleman/templates/mobile/source/img/l/apple-touch-icon-precomposed.png +0 -0
  37. data/lib/middleman/templates/mobile/source/img/l/apple-touch-icon.png +0 -0
  38. data/lib/middleman/templates/mobile/source/img/l/splash.png +0 -0
  39. data/lib/middleman/templates/mobile/source/img/m/apple-touch-icon.png +0 -0
  40. data/lib/middleman/templates/mobile/source/index.html +95 -0
  41. data/lib/middleman/templates/mobile/source/js/libs/jquery-1.5.1.js +8316 -0
  42. data/lib/middleman/templates/mobile/source/js/libs/jquery-1.5.1.min.js +16 -0
  43. data/lib/middleman/templates/mobile/source/js/libs/modernizr-custom.js +14 -0
  44. data/lib/middleman/templates/mobile/source/js/libs/respond.min.js +7 -0
  45. data/lib/middleman/templates/mobile/source/js/mylibs/helper.js +147 -0
  46. data/lib/middleman/templates/mobile/source/js/script.js +0 -0
  47. data/lib/middleman/templates/mobile/source/robots.txt +5 -0
  48. data/lib/middleman/templates/mobile/source/sitemap.xml +10 -0
  49. data/lib/middleman/templates/mobile/source/test/index.html +31 -0
  50. data/lib/middleman/templates/mobile/source/test/qunit/qunit.css +148 -0
  51. data/lib/middleman/templates/mobile/source/test/qunit/qunit.js +1265 -0
  52. data/lib/middleman/templates/mobile/source/test/tests.js +26 -0
  53. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/Readme.PDF +0 -0
  54. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/aspx1.snippet +31 -0
  55. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/aspx2.snippet +2 -0
  56. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/ga.aspx +195 -0
  57. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/sample.aspx +44 -0
  58. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/ga.jsp +225 -0
  59. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/jsp1.snippet +35 -0
  60. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/jsp2.snippet +2 -0
  61. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/sample.jsp +51 -0
  62. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/ga.php +176 -0
  63. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/php1.snippet +30 -0
  64. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/php2.snippet +4 -0
  65. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/sample.php +44 -0
  66. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/ga.pl +195 -0
  67. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/perl1.snippet +27 -0
  68. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/perl2.snippet +1 -0
  69. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/sample.pl +38 -0
  70. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/COPYING +202 -0
  71. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/bookmark_bubble.js +559 -0
  72. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/example/example.html +43 -0
  73. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/example/example.js +57 -0
  74. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/arrow.png +0 -0
  75. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/close.png +0 -0
  76. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/generate_base64_images +33 -0
  77. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/icon_calendar.png +0 -0
  78. data/lib/middleman/templates/mobile/source/tools/wspl/README +27 -0
  79. data/lib/middleman/templates/mobile/source/tools/wspl/databasefactory.js +45 -0
  80. data/lib/middleman/templates/mobile/source/tools/wspl/dbworker.js +324 -0
  81. data/lib/middleman/templates/mobile/source/tools/wspl/dbworker_test.html +393 -0
  82. data/lib/middleman/templates/mobile/source/tools/wspl/dbworkerstarter.js +32 -0
  83. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_gears.js +595 -0
  84. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_gears_test.html +404 -0
  85. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_html5.js +203 -0
  86. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_html5_test.html +468 -0
  87. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapperapi.js +202 -0
  88. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapperapi_test.html +51 -0
  89. data/lib/middleman/templates/mobile/source/tools/wspl/gears_resultset.js +71 -0
  90. data/lib/middleman/templates/mobile/source/tools/wspl/gears_resultset_test.html +86 -0
  91. data/lib/middleman/templates/mobile/source/tools/wspl/gears_transaction.js +196 -0
  92. data/lib/middleman/templates/mobile/source/tools/wspl/gears_transaction_test.html +221 -0
  93. data/lib/middleman/templates/mobile/source/tools/wspl/gearsutils.js +94 -0
  94. data/lib/middleman/templates/mobile/source/tools/wspl/gearsutils_test.html +84 -0
  95. data/lib/middleman/templates/mobile/source/tools/wspl/global_functions.js +72 -0
  96. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/index.html +347 -0
  97. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/simplenotes.js +503 -0
  98. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/styles.css +66 -0
  99. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/template.js +75 -0
  100. data/lib/middleman/version.rb +1 -1
  101. data/middleman-x86-mingw32.gemspec +0 -1
  102. data/middleman.gemspec +3 -2
  103. metadata +116 -51
  104. data/lib/middleman/config.ru +0 -2
  105. data/lib/middleman/features/tiny_src.rb +0 -11
@@ -0,0 +1,404 @@
1
+ <!DOCTYPE html>
2
+ <!--
3
+ Copyright 2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ -->
17
+
18
+ <html>
19
+ <head>
20
+ <title>Gears database wrapper tests</title>
21
+ <script type="text/javascript" src="../jsunit/app/jsUnitCore.js"></script>
22
+ <script type="text/javascript" src="jsmock.js"></script>
23
+ <script type="text/javascript" src="global_functions.js"></script>
24
+ <script type="text/javascript" src="gearsutils.js"></script>
25
+ <script type="text/javascript" src="dbwrapperapi.js"></script>
26
+ <script type="text/javascript" src="gears_resultset.js"></script>
27
+ <script type="text/javascript" src="gears_transaction.js"></script>
28
+ <script type="text/javascript" src="dbworker.js"></script>
29
+ <script type="text/javascript" src="dbwrapper_gears.js"></script>
30
+ </head>
31
+ <body>
32
+ <script type='text/javascript'>
33
+
34
+ var mockControl;
35
+ var callbackMock;
36
+ var dbMock;
37
+ var wp;
38
+ var workerId = 123;
39
+ var transMock;
40
+
41
+ function setUp() {
42
+ mockControl = new MockControl();
43
+
44
+ callbackMock = mockControl.createMock({
45
+ onSuccess: function(){},
46
+ onFailure: function(){}
47
+ });
48
+
49
+ transMock = mockControl.createMock({
50
+ success: function(){},
51
+ failure: function(){}
52
+ });
53
+
54
+ wp = mockControl.createMock({
55
+ allowCrossOrigin: function(){},
56
+ createWorkerFromUrl: function(){},
57
+ sendMessage: function(){}
58
+ });
59
+
60
+ dbMock = mockControl.createMock({
61
+ execute: function(){},
62
+ open: function(){},
63
+ close: function(){},
64
+ remove: function(){}
65
+ });
66
+
67
+ google.wspl.GearsUtils.resultSetToObjectArray = function(rs) {
68
+ return rs;
69
+ };
70
+ }
71
+
72
+ function buildSyncDatabase() {
73
+ var database = new google.wspl.gears.Database(true);
74
+ database.userId_ = 'userId';
75
+ database.name_ = 'name';
76
+ database.db_ = dbMock;
77
+ return database;
78
+ }
79
+
80
+ function buildDatabase() {
81
+ var database = buildSyncDatabase();
82
+
83
+ var type = google.wspl.gears.DbWorker.CommandTypes.OPEN;
84
+ wp.expects().createWorkerFromUrl('workerUrl').andReturn(workerId);
85
+ wp.expects().sendMessage(TypeOf.isA(Object), workerId).andStub(function() {
86
+ assertEquals('Wrong message type.', type, arguments[0].type);
87
+ assertEquals('Incorrect name.', 'name', arguments[0].name);
88
+ assertEquals('Incorrect user id.', 'userId', arguments[0].userId);
89
+ });
90
+
91
+ database.startWorker(wp, 'workerUrl', 0);
92
+ database.handleStarted_();
93
+ database.handleOpenSuccessful_();
94
+ database.useWorker_ = true;
95
+ return database;
96
+ }
97
+
98
+ function testConstructor() {
99
+ var db = buildSyncDatabase();
100
+ mockControl.verify();
101
+ }
102
+
103
+ function testStartWorker() {
104
+ var db = buildDatabase();
105
+ assertTrue('Expected worker to be ready.', db.workerReady_);
106
+ mockControl.verify();
107
+ }
108
+
109
+ function testCreateTransaction() {
110
+ var db = buildDatabase();
111
+ var tx;
112
+ var populateMock = function(txa) {
113
+ tx = txa;
114
+ var transactions = db.transactions_;
115
+ assertEquals('missing transaction', tx, transactions[tx.id_].transaction);
116
+ assertEquals('missing callback', callbackMock,
117
+ transactions[tx.id_].callback);
118
+ assertEquals('database not saved', db, tx.db_);
119
+ assertTrue('database should be locked', db.locked_);
120
+ };
121
+
122
+ callbackMock.expects().onSuccess();
123
+
124
+ var transactions = db.transactions_;
125
+ db.createTransaction(populateMock, callbackMock);
126
+ assertEquals('failed to clean up transaction', undefined,
127
+ transactions[tx.id_]);
128
+ assertFalse('database should not be locked', db.locked_);
129
+
130
+ mockControl.verify();
131
+ }
132
+
133
+ function testMultipleTransactions() {
134
+ var db = buildDatabase();
135
+ var handler = mockControl.createMock();
136
+ handler.addMockMethod('populate');
137
+ handler.addMockMethod('onSuccess');
138
+ handler.addMockMethod('onFailure');
139
+
140
+ var trans;
141
+ handler.expects().populate(TypeOf.isA(google.wspl.gears.Transaction)).andStub(
142
+ function(tx) {
143
+ trans = tx;
144
+ tx.numActiveExecutes_ = 1;
145
+ });
146
+
147
+ db.createTransaction(handler.populate, handler);
148
+ db.createTransaction(handler.populate, handler);
149
+ mockControl.verify();
150
+
151
+ handler.expects().onSuccess();
152
+ handler.expects().populate(TypeOf.isA(google.wspl.gears.Transaction)).andStub(
153
+ function(tx) {
154
+ trans = tx;
155
+ tx.numActiveExecutes_ = 1;
156
+ });
157
+
158
+ db.handleCommit_(trans.id_);
159
+ mockControl.verify();
160
+
161
+ handler.expects().onFailure(undefined).andStub(function() {
162
+ db.createTransaction(handler.populate, handler);
163
+ });
164
+ handler.expects().populate(TypeOf.isA(google.wspl.gears.Transaction)).andStub(
165
+ function(tx) {
166
+ trans = tx;
167
+ tx.numActiveExecutes_ = 1;
168
+ });
169
+
170
+ db.handleRollback_(trans.id_);
171
+ mockControl.verify();
172
+
173
+ handler.expects().onSuccess();
174
+
175
+ db.handleCommit_(trans.id_);
176
+ mockControl.verify();
177
+ }
178
+
179
+ function testDoBegin() {
180
+ var db = buildDatabase();
181
+ var transactionId = 10;
182
+ var type = google.wspl.gears.DbWorker.CommandTypes.BEGIN;
183
+ wp.expects().sendMessage(TypeOf.isA(Object), workerId).andStub(function() {
184
+ assertEquals('wrong message type', type, arguments[0].type);
185
+ assertNotUndefined('Missing transaction id.', arguments[0].transactionId);
186
+ });
187
+ db.doBegin(transactionId);
188
+ mockControl.verify();
189
+ }
190
+
191
+ function testSynchronousBegin() {
192
+ var db = buildSyncDatabase();
193
+ dbMock.expects().execute('BEGIN IMMEDIATE');
194
+ db.doBegin(1);
195
+ mockControl.verify();
196
+ }
197
+
198
+ function testDoExecute() {
199
+ var statements = [{sql: 's1', params: 'p1'},
200
+ {sql: 's2', params: 'p2'},
201
+ {sql: 's3', params: 'p3'}];
202
+ var callbackId = 5;
203
+ var transactionId = 10;
204
+ var db = buildDatabase();
205
+ var type = google.wspl.gears.DbWorker.CommandTypes.EXECUTE;
206
+ wp.expects().sendMessage(TypeOf.isA(Object), workerId).andStub(function() {
207
+ assertEquals('wrong message type', type, arguments[0].type);
208
+ assertEquals('statements do not match', statements.length,
209
+ arguments[0].statements.length);
210
+ for (var i = 0; i < statements.length; i++) {
211
+ assertEquals('a statement sql does not match', statements[i].sql,
212
+ arguments[0].statements[i].sql);
213
+ assertEquals('a statement params does not match', statements[i].params,
214
+ arguments[0].statements[i].params);
215
+ }
216
+ assertEquals('missing callback id', callbackId, arguments[0].callbackId);
217
+ assertEquals('missing trans id', transactionId, arguments[0].transactionId);
218
+ });
219
+ db.doExecute(statements, callbackId, transactionId);
220
+ mockControl.verify();
221
+ }
222
+
223
+ function testSynchronousExecute() {
224
+ var statements = [{sql: 's1', params: 'p1'},
225
+ {sql: 's2', params: 'p2'},
226
+ {sql: 's3', params: 'p3'}];
227
+ var callbackId = 5;
228
+ var transactionId = 10;
229
+ var db = buildSyncDatabase();
230
+
231
+ for (var i = 0; i < 3; i++) {
232
+ var stat = statements[i];
233
+ dbMock.expects().execute(stat.sql, stat.params).andReturn('result' + i);
234
+ }
235
+
236
+ var handler = mockControl.createMock();
237
+ handler.addMockMethod('handleResult_');
238
+ db.handleResult_ = handler.handleResult_;
239
+ handler.expects().handleResult_(
240
+ TypeOf.isA(Array), callbackId, transactionId).andStub(function(results) {
241
+ var expected = ['result0', 'result1', 'result2'];
242
+ assertArrayEquals('Wrong results.', expected, results);
243
+ });
244
+
245
+ db.doExecute(statements, callbackId, transactionId);
246
+ mockControl.verify();
247
+ }
248
+
249
+ function testSynchronousExecute_failure() {
250
+ var statements = [{sql: 's1', params: 'p1'},
251
+ {sql: 's2', params: 'p2'},
252
+ {sql: 's3', params: 'p3'}];
253
+ var callbackId = 5;
254
+ var transactionId = 10;
255
+ var db = buildSyncDatabase();
256
+
257
+ dbMock.expects().execute('s1', 'p1').andReturn('result0');
258
+ dbMock.expects().execute('s2', 'p2').andThrow(Error('db error'));
259
+
260
+ var handler = mockControl.createMock();
261
+ handler.addMockMethod('handleFailure_');
262
+ db.handleFailure_ = handler.handleFailure_;
263
+ handler.expects().handleFailure_(
264
+ TypeOf.isA(Error), callbackId, transactionId);
265
+
266
+ db.doExecute(statements, callbackId, transactionId);
267
+ mockControl.verify();
268
+ }
269
+
270
+ function testDoCommit() {
271
+ var transactionId = 10;
272
+ var db = buildDatabase();
273
+ var type = google.wspl.gears.DbWorker.CommandTypes.COMMIT;
274
+ wp.expects().sendMessage(TypeOf.isA(Object), workerId).andStub(function() {
275
+ assertEquals('wrong message type', type, arguments[0].type);
276
+ assertEquals('missing trans id', transactionId, arguments[0].transactionId);
277
+ });
278
+ db.doCommit(transactionId);
279
+ mockControl.verify();
280
+ }
281
+
282
+ function testSynchronousCommit() {
283
+ var db = buildSyncDatabase();
284
+ dbMock.expects().execute('COMMIT');
285
+ db.doCommit(1);
286
+ mockControl.verify();
287
+ }
288
+
289
+ function testDoRollback() {
290
+ var transactionId = 10;
291
+ var db = buildDatabase();
292
+ var type = google.wspl.gears.DbWorker.CommandTypes.ROLLBACK;
293
+ wp.expects().sendMessage(TypeOf.isA(Object), workerId).andStub(function() {
294
+ assertEquals('wrong message type', type, arguments[0].type);
295
+ assertEquals('missing trans id', transactionId, arguments[0].transactionId);
296
+ });
297
+ db.doRollback(transactionId);
298
+ mockControl.verify();
299
+ }
300
+
301
+ function testSynchronousRollback() {
302
+ var db = buildSyncDatabase();
303
+ dbMock.expects().execute('ROLLBACK');
304
+ db.doRollback(1);
305
+ mockControl.verify();
306
+ }
307
+
308
+ function testHandleCommit() {
309
+ var db = buildDatabase();
310
+ db.transactions_[5] = {transaction: 'tx', callback: callbackMock};
311
+ callbackMock.expects().onSuccess();
312
+ db.handleCommit_(5);
313
+ assertUndefined('failed to remove transaction', db.transactions_[5]);
314
+ mockControl.verify();
315
+ }
316
+
317
+ function testHandleRollback() {
318
+ var db = buildDatabase();
319
+ db.transactions_[5] = {
320
+ transaction: 'tx',
321
+ callback: callbackMock,
322
+ error: Error('error')
323
+ };
324
+ callbackMock.expects().onFailure(TypeOf.isA(Error)).andStub(function() {
325
+ assertEquals('did not pass error', 'error', arguments[0].message);
326
+ });
327
+ db.handleRollback_(5);
328
+ assertUndefined('failed to remove transaction', db.transactions_[5]);
329
+ mockControl.verify();
330
+ }
331
+
332
+ function testHandleResult() {
333
+ var db = buildDatabase();
334
+ transMock.expects().success(TypeOf.isA(google.wspl.gears.ResultSet),
335
+ 22).andStub(function() {
336
+ assertEquals('result not set', 'result1', arguments[0].resultArray_);
337
+ });
338
+ transMock.expects().success(TypeOf.isA(google.wspl.gears.ResultSet),
339
+ 22).andStub(function() {
340
+ assertEquals('result not set', 'result2', arguments[0].resultArray_);
341
+ });
342
+ db.transactions_[5] = {transaction: transMock, callback: 'cb'};
343
+
344
+ db.handleResult_(['result1', 'result2'], 22, 5);
345
+ mockControl.verify();
346
+ }
347
+
348
+ function testHandleFailure() {
349
+ var db = buildDatabase();
350
+ transMock.expects().failure(TypeOf.isA(Error), 22).andStub(function() {
351
+ assertEquals('error not set', 'error', arguments[0].message);
352
+ });
353
+ db.transactions_[5] = {transaction: transMock, callback: 'cb'};
354
+
355
+ db.handleFailure_(Error('error'), 22, 5);
356
+ assertEquals('failed to save error', 'error',
357
+ db.transactions_[5].error.message);
358
+ mockControl.verify();
359
+ }
360
+
361
+ function testHandleStarted() {
362
+ var db = buildDatabase();
363
+ var type = google.wspl.gears.DbWorker.CommandTypes.OPEN;
364
+ wp.expects().sendMessage(TypeOf.isA(Object), workerId).andStub(function() {
365
+ assertEquals('wrong message type', type, arguments[0].type);
366
+ assertEquals('wrong db userId', 'userId', arguments[0].userId);
367
+ assertEquals('wrong db name', 'name', arguments[0].name);
368
+ });
369
+ db.handleStarted_();
370
+ mockControl.verify();
371
+ }
372
+
373
+ function testHandleStarted_afterTimeout() {
374
+ var db = buildDatabase();
375
+ db.handleTimeout_();
376
+
377
+ // This should do nothing.
378
+ db.handleStarted_();
379
+
380
+ mockControl.verify();
381
+ }
382
+
383
+ function testHandleTimeout() {
384
+ var db = buildDatabase();
385
+ db.handleTimeout_();
386
+ mockControl.verify();
387
+ }
388
+
389
+ function testHandleOpenSuccessful() {
390
+ var db = buildDatabase();
391
+ db.handleOpenSuccessful_();
392
+ assertTrue('Worker should be ready.', db.workerReady_);
393
+ mockControl.verify();
394
+ }
395
+
396
+ function testHandleOpenFailed() {
397
+ var db = buildDatabase();
398
+ db.handleOpenFailed_('error');
399
+ mockControl.verify();
400
+ }
401
+
402
+ </script>
403
+ </body>
404
+ </html>
@@ -0,0 +1,203 @@
1
+ /*
2
+ Copyright 2009 Google Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * @fileoverview Generic Database API.
19
+ *
20
+ * A small set of classes to define how we interact with databases that
21
+ * can easily be implemented on top of HTML5.
22
+ */
23
+
24
+ google.wspl.html5 = google.wspl.html5 || {};
25
+
26
+ /**
27
+ * Specification's default largest database size in HTML5 databases.
28
+ * @type{number}
29
+ */
30
+ google.wspl.LARGEST_SUPPORTED_DATABASE = 1024 * 1024 * 4;
31
+
32
+ /**
33
+ * Creates an HTML5 Transaction object.
34
+ * @see google.wspl.Transaction#Transaction
35
+ *
36
+ * @constructor
37
+ * @extends google.wspl.Transaction
38
+ *
39
+ * @param {SQLTransaction} html5tx The HTML5 implementation of transactions.
40
+ */
41
+ google.wspl.html5.Transaction = function(html5tx) {
42
+ this.tx_ = html5tx;
43
+ };
44
+ google.inherits(google.wspl.html5.Transaction, google.wspl.Transaction);
45
+
46
+ /**
47
+ * Runs an array of statements in a single database transaction.
48
+ * Invokes the onSuccess callback once for each succeesfully executed
49
+ * statement and
50
+ * once for the first failed statement.
51
+ *
52
+ * @param {Array.<google.wspl.Statement>} statements The statements to
53
+ * execute.
54
+ * @param {Object?} opt_callback An object containing onSuccess and onFailure
55
+ * handlers.
56
+ */
57
+ google.wspl.html5.Transaction.prototype.executeAll = function(statements,
58
+ opt_callback) {
59
+ if (statements.length == 0) {
60
+ throw Error('Possibly silly attempt to execute empty statement list.');
61
+ }
62
+
63
+ var self = this;
64
+ for (var i = 0; i < statements.length; ++i) {
65
+ var statement = statements[i];
66
+ google.logger('SQL: ' + statement.sql + ' PARAMS: ' + statement.params);
67
+ this.tx_.executeSql(statement.sql, statement.params,
68
+ function(tx, result) {
69
+ if (opt_callback && opt_callback.onSuccess) {
70
+ var resultSet = new google.wspl.html5.ResultSet(result);
71
+ opt_callback.onSuccess(self, resultSet);
72
+ }
73
+ },
74
+ function(tx, error) {
75
+ if (opt_callback && opt_callback.onFailure) {
76
+ opt_callback.onFailure(error);
77
+ }
78
+ // fail the whole transaction if any step fails
79
+ return true;
80
+ });
81
+ }
82
+ };
83
+
84
+ /**
85
+ * @see google.wspl.Database#Database
86
+ * @param {string} name The name for this database.
87
+ * @param {window} opt_window A window object for dependency injection.
88
+ * @constructor
89
+ * @extends google.wspl.Database
90
+ */
91
+ google.wspl.html5.Database = function(name, opt_window) {
92
+ /**
93
+ * Sequence number for transactions.
94
+ * @type {number}
95
+ * @private
96
+ */
97
+ this.sequenceNum_ = 1;
98
+
99
+ /**
100
+ * Map of transactionIds -> transaction start time in millis.
101
+ * @type {Object}
102
+ * @private
103
+ */
104
+ this.inflightTransactions_ = {};
105
+
106
+ var win = opt_window || window;
107
+ this.db_ = win.openDatabase(name, '',
108
+ name, google.wspl.LARGEST_SUPPORTED_DATABASE);
109
+ if (this.db_ == null) {
110
+ throw Error('The returned database was null.');
111
+ }
112
+ };
113
+ google.inherits(google.wspl.html5.Database, google.wspl.Database);
114
+
115
+ /**
116
+ * @see google.wspl.Database#createTransaction
117
+ */
118
+ google.wspl.html5.Database.prototype.createTransaction = function(populate,
119
+ opt_callback) {
120
+ var transactionCallback = opt_callback || {
121
+ onSuccess: function() {},
122
+ onFailure: function() {}
123
+ };
124
+
125
+ var transactionId = this.sequenceNum_++;
126
+ var inflightTransactions = this.inflightTransactions_;
127
+ inflightTransactions[transactionId] = this.getCurrentTime();
128
+ this.db_.transaction(
129
+ function(tx) {
130
+ // Delete the transaction before the executing it because our
131
+ // definition of an 'in-flight' transaction is the time between
132
+ // when the request was made and when the database starts to
133
+ // execute the transaction.
134
+ delete inflightTransactions[transactionId];
135
+ populate(new google.wspl.html5.Transaction(tx));
136
+ },
137
+ function(error) {transactionCallback.onFailure(error);},
138
+ function() {transactionCallback.onSuccess();});
139
+ };
140
+
141
+ /**
142
+ * Determine if there is an in-flight database transaction that's older than
143
+ * the given time period.
144
+ * @param {number} olderThanMillis The time period.
145
+ * @return {boolean} True if the database has an in-flight transaction older
146
+ * than the given time period, false otherwise.
147
+ */
148
+ google.wspl.html5.Database.prototype.hasInflightTransactions =
149
+ function(olderThanMillis) {
150
+ for (var transactionId in this.inflightTransactions_) {
151
+ var startTime = this.inflightTransactions_[transactionId];
152
+ if (this.getCurrentTime() - startTime > olderThanMillis) {
153
+ return true;
154
+ }
155
+ }
156
+ return false;
157
+ };
158
+
159
+ /**
160
+ * Returns the current time.
161
+ * @return {number} The current time in millis.
162
+ */
163
+ google.wspl.html5.Database.prototype.getCurrentTime = function() {
164
+ // The iPhone does not support Date.now()
165
+ var d = new Date();
166
+ return d.getTime();
167
+ };
168
+
169
+ /**
170
+ * Creates an HTML5 ResultSet object.
171
+ * @see google.wspl.ResultSet#ResultSet
172
+ *
173
+ * @constructor
174
+ * @extends google.wspl.ResultSet
175
+ *
176
+ * @param {Object} html5_result The HTML5 implementation of result set.
177
+ */
178
+ google.wspl.html5.ResultSet = function(html5_result) {
179
+ this.result_ = html5_result;
180
+ this.index_ = 0;
181
+ };
182
+ google.inherits(google.wspl.html5.ResultSet, google.wspl.ResultSet);
183
+
184
+ /**
185
+ * @see google.wspl.ResultSet#isValidRow
186
+ */
187
+ google.wspl.html5.ResultSet.prototype.isValidRow = function() {
188
+ return this.index_ >= 0 && this.index_ < this.result_.rows.length;
189
+ };
190
+
191
+ /**
192
+ * @see google.wspl.ResultSet#next
193
+ */
194
+ google.wspl.html5.ResultSet.prototype.next = function() {
195
+ this.index_ ++;
196
+ };
197
+
198
+ /**
199
+ * @see google.wspl.ResultSet#getRow
200
+ */
201
+ google.wspl.html5.ResultSet.prototype.getRow = function() {
202
+ return this.result_.rows.item(this.index_);
203
+ };