mongo_browser 0.2.0.rc2 → 0.2.5

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 (141) hide show
  1. data/.gitignore +3 -1
  2. data/.rspec +1 -1
  3. data/.travis.yml +6 -1
  4. data/CHANGELOG.md +15 -0
  5. data/{grunt.js → Gruntfile.js} +10 -8
  6. data/Procfile +1 -0
  7. data/README.md +44 -2
  8. data/Rakefile +1 -12
  9. data/app/assets/images/ajax-loader.gif +0 -0
  10. data/app/assets/javascripts/app/controllers/{breadcrumbs.js.coffee → breadcrumbs_controller.js.coffee} +4 -7
  11. data/app/assets/javascripts/app/controllers/collections/index_controller.js.coffee +38 -0
  12. data/app/assets/javascripts/app/controllers/collections/stats_controller.js.coffee +17 -0
  13. data/app/assets/javascripts/app/controllers/{databases.js.coffee → databases/index_controller.js.coffee} +11 -15
  14. data/app/assets/javascripts/app/controllers/databases/stats_controller.js.coffee +15 -0
  15. data/app/assets/javascripts/app/controllers/documents/index_controller.js.coffee +54 -0
  16. data/app/assets/javascripts/app/controllers/documents/show_controller.js.coffee +38 -0
  17. data/app/assets/javascripts/app/controllers/main_controller.js.coffee +15 -0
  18. data/app/assets/javascripts/app/controllers/servers/show_controller.js.coffee +17 -0
  19. data/app/assets/javascripts/app/directives.js.coffee +23 -0
  20. data/app/assets/javascripts/app/filters.js.coffee +14 -1
  21. data/app/assets/javascripts/app/modules/alerts.js.coffee +58 -0
  22. data/app/assets/javascripts/app/modules/pager.js.coffee +2 -2
  23. data/app/assets/javascripts/app/modules/spinner.js.coffee +29 -0
  24. data/app/assets/javascripts/app/modules/table_filter.js.coffee +4 -4
  25. data/app/assets/javascripts/app/resources.js.coffee +14 -8
  26. data/app/assets/javascripts/app/services.js.coffee +11 -33
  27. data/app/assets/javascripts/application.js.coffee +62 -34
  28. data/app/assets/javascripts/application.test.js.coffee +5 -0
  29. data/app/assets/javascripts/compiled_templates.js.coffee +1 -0
  30. data/app/assets/javascripts/vendor.js.coffee +0 -1
  31. data/app/assets/stylesheets/application.css.scss +36 -18
  32. data/{public/index.html → app/views/index.erb} +8 -8
  33. data/bin/mongo_browser +2 -13
  34. data/config.ru +3 -1
  35. data/lib/mongo_browser.rb +1 -0
  36. data/lib/mongo_browser/api.rb +11 -0
  37. data/lib/mongo_browser/api/collections.rb +34 -0
  38. data/lib/mongo_browser/api/databases.rb +32 -0
  39. data/lib/mongo_browser/api/documents.rb +37 -0
  40. data/lib/mongo_browser/api/mongo.rb +41 -0
  41. data/lib/mongo_browser/application.rb +8 -174
  42. data/lib/mongo_browser/application/development.rb +32 -0
  43. data/lib/mongo_browser/cli.rb +48 -0
  44. data/lib/mongo_browser/entities.rb +43 -0
  45. data/lib/mongo_browser/models/collection.rb +7 -12
  46. data/lib/mongo_browser/models/document.rb +5 -1
  47. data/lib/mongo_browser/models/pager.rb +22 -9
  48. data/lib/mongo_browser/version.rb +1 -1
  49. data/mongo_browser.gemspec +22 -15
  50. data/package.json +30 -0
  51. data/public/ng/templates/alerts.html +6 -0
  52. data/public/ng/templates/collections/index.html +39 -0
  53. data/public/ng/templates/collections/stats.html +18 -0
  54. data/public/ng/templates/databases/index.html +35 -0
  55. data/public/ng/templates/databases/stats.html +18 -0
  56. data/public/ng/templates/documents/index.html +40 -0
  57. data/public/ng/templates/documents/show.html +17 -0
  58. data/{app/assets → public/ng}/templates/pager.html +0 -0
  59. data/{app/assets/templates/server_info.html → public/ng/templates/server/show.html} +1 -1
  60. data/{app/assets → public/ng}/templates/table_filter.html +0 -0
  61. data/script/ci_all +5 -1
  62. data/script/ci_e2e +5 -2
  63. data/script/ci_javascripts +1 -1
  64. data/script/ci_rspec +1 -1
  65. data/spec/javascripts/app/controllers/{breadcrumbs_spec.js.coffee → breadcrumbs_controller_spec.js.coffee} +1 -1
  66. data/spec/javascripts/app/controllers/collections/index_controller_spec.js.coffee +95 -0
  67. data/spec/javascripts/app/controllers/collections/stats_controller_spec.js.coffee +34 -0
  68. data/spec/javascripts/app/controllers/databases/index_controller_spec.js.coffee +93 -0
  69. data/spec/javascripts/app/controllers/databases/stats_controller_spec.js.coffee +30 -0
  70. data/spec/javascripts/app/controllers/documents/index_controller_spec.js.coffee +108 -0
  71. data/spec/javascripts/app/controllers/documents/show_controller_spec.js.coffee +94 -0
  72. data/spec/javascripts/app/controllers/{main_spec.js.coffee → main_controller_spec.js.coffee} +2 -2
  73. data/spec/javascripts/app/controllers/{server_info_spec.js.coffee → server/show_controller_spec.js.coffee} +5 -6
  74. data/spec/javascripts/app/directives_spec.js.coffee +108 -24
  75. data/spec/javascripts/app/filters_spec.js.coffee +31 -5
  76. data/spec/javascripts/app/modules/alerts_spec.js.coffee +138 -0
  77. data/spec/javascripts/app/modules/dialogs_spec.js.coffee +1 -2
  78. data/spec/javascripts/app/modules/pager_spec.js.coffee +0 -1
  79. data/spec/javascripts/app/modules/spinner_spec.js.coffee +65 -0
  80. data/spec/javascripts/app/modules/table_filter_spec.js.coffee +9 -9
  81. data/spec/javascripts/app/resources_spec.js.coffee +99 -0
  82. data/spec/javascripts/app/services_spec.js.coffee +31 -71
  83. data/spec/javascripts/config/{testacular-e2e.conf.js → karma-e2e.conf.js} +1 -1
  84. data/spec/javascripts/config/{testacular.conf.js → karma.conf.js} +2 -3
  85. data/spec/javascripts/e2e/collection_stats_scenario.js.coffee +12 -0
  86. data/spec/javascripts/e2e/collections_scenario.js.coffee +59 -20
  87. data/spec/javascripts/e2e/database_stats_scenario.js.coffee +11 -0
  88. data/spec/javascripts/e2e/databases_scenario.js.coffee +37 -36
  89. data/spec/javascripts/e2e/document_show_scenario.js.coffee +31 -0
  90. data/spec/javascripts/e2e/documents_pagination_scenario.js.coffee +33 -0
  91. data/spec/javascripts/e2e/documents_scenario.js.coffee +43 -4
  92. data/spec/javascripts/e2e/server_info_scenario.js.coffee +8 -2
  93. data/spec/javascripts/helpers/mocks.js.coffee +2 -0
  94. data/spec/javascripts/helpers_e2e/dsl.js.coffee +20 -0
  95. data/spec/javascripts/lib/angular-mocks.js +64 -16
  96. data/spec/javascripts/lib/angular-scenario.js +724 -561
  97. data/spec/javascripts/runner.html +5 -5
  98. data/spec/lib/api/collections_spec.rb +62 -0
  99. data/spec/lib/api/databases_spec.rb +58 -0
  100. data/spec/lib/api/documents_spec.rb +135 -0
  101. data/spec/lib/api/mongo_spec.rb +27 -0
  102. data/spec/lib/cli_spec.rb +19 -0
  103. data/spec/lib/entities_spec.rb +39 -0
  104. data/spec/lib/models/collection_spec.rb +16 -10
  105. data/spec/lib/models/database_spec.rb +4 -4
  106. data/spec/lib/models/document_spec.rb +5 -5
  107. data/spec/lib/models/pager_spec.rb +20 -11
  108. data/spec/spec_helper.rb +7 -15
  109. data/spec/support/api_example_group.rb +45 -0
  110. data/spec/support/fixtures.rb +10 -6
  111. data/spec/support/matchers/expose.rb +18 -0
  112. data/vendor/assets/javascripts/angular/angular-bootstrap.js +1 -1
  113. data/vendor/assets/javascripts/angular/angular-resource.js +78 -56
  114. data/vendor/assets/javascripts/angular/angular-sanitize.js +3 -1
  115. data/vendor/assets/javascripts/angular/angular.js +720 -404
  116. metadata +323 -183
  117. data/app/assets/javascripts/app.js.coffee +0 -8
  118. data/app/assets/javascripts/app/controllers.js.coffee +0 -2
  119. data/app/assets/javascripts/app/controllers/alerts.js.coffee +0 -12
  120. data/app/assets/javascripts/app/controllers/collections.js.coffee +0 -40
  121. data/app/assets/javascripts/app/controllers/documents.js.coffee +0 -49
  122. data/app/assets/javascripts/app/controllers/main.js.coffee +0 -10
  123. data/app/assets/javascripts/app/controllers/server_info.js.coffee +0 -14
  124. data/app/assets/javascripts/templates.js.coffee +0 -1
  125. data/app/assets/javascripts/templates/.gitkeep +0 -0
  126. data/app/assets/templates/collections.html +0 -53
  127. data/app/assets/templates/databases.html +0 -32
  128. data/app/assets/templates/documents.html +0 -45
  129. data/config-e2e.ru +0 -20
  130. data/spec/features/collections_list_spec.rb +0 -64
  131. data/spec/features/documents_list_spec.rb +0 -139
  132. data/spec/features/server_info_spec.rb +0 -23
  133. data/spec/javascripts/app/controllers/alerts_spec.js.coffee +0 -36
  134. data/spec/javascripts/app/controllers/collections_spec.js.coffee +0 -78
  135. data/spec/javascripts/app/controllers/databases_spec.js.coffee +0 -55
  136. data/spec/javascripts/app/controllers/documents_spec.js.coffee +0 -62
  137. data/spec/javascripts/helpers_e2e/app_element.js.coffee +0 -6
  138. data/spec/support/feature_example_group.rb +0 -53
  139. data/spec/support/matchers/have_flash_message.rb +0 -16
  140. data/spec/support/mongod.rb +0 -91
  141. data/spec/support/mongodb.conf +0 -47
@@ -1,14 +1,14 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe MongoBrowser::Models::Document do
4
- let(:mongo_db_name) { "first_database" }
5
- let(:mongo_collection_name) { "first_collection" }
4
+ let(:db_name) { "first_database" }
5
+ let(:collection_name) { "first_collection" }
6
6
 
7
7
  let(:server) { MongoBrowser::Models::Server.current }
8
- let(:mongo_collection) { server.connection[mongo_db_name].collection(mongo_collection_name) }
9
- let(:mongo_document) { mongo_collection.find.first }
8
+ let(:colleciton) { server.connection[db_name].collection(collection_name) }
9
+ let(:mongo_document) { colleciton.find.first }
10
10
 
11
- let(:document) { described_class.new(mongo_document) }
11
+ let(:document) { described_class.new(db_name, collection_name, mongo_document) }
12
12
  subject { document }
13
13
 
14
14
  its(:id) { should_not be_nil }
@@ -1,49 +1,49 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe MongoBrowser::Models::Pager do
4
- let(:current_page) { 1 }
4
+ let(:page) { 1 }
5
5
  let(:size) { 25 }
6
6
 
7
- let(:pager) { described_class.new(current_page, size) }
7
+ let(:pager) { described_class.new(page, size) }
8
8
  subject { pager }
9
9
 
10
10
  before { pager.stub(:per_page).and_return(25) }
11
11
 
12
- describe "#current_page" do
13
- subject { pager.current_page }
12
+ describe "#page" do
13
+ subject { pager.page }
14
14
 
15
15
  [-2, -1, 0, 1].each do |number|
16
16
  context "when the given page number is #{number}" do
17
- let(:current_page) { number }
17
+ let(:page) { number }
18
18
 
19
19
  it("return the first page") { should == 1 }
20
20
  end
21
21
  end
22
22
 
23
23
  context "when the given page number exceed the total pages number" do
24
- let(:current_page) { 3 }
24
+ let(:page) { 3 }
25
25
  let(:size) { 30 }
26
26
 
27
27
  it("returns the last page number") { should == 2 }
28
28
  end
29
29
 
30
30
  context "otherwise" do
31
- let(:current_page) { 2 }
31
+ let(:page) { 2 }
32
32
  let(:size) { 26 }
33
33
 
34
- it("returns the current page") { should == current_page }
34
+ it("returns the current page") { should == page }
35
35
  end
36
36
  end
37
37
 
38
38
  describe "#offset" do
39
39
  subject { pager.offset }
40
40
 
41
- context "when current_page eq 1" do
41
+ context "when page eq 1" do
42
42
  it { should == 0 }
43
43
  end
44
44
 
45
45
  context "otherwise" do
46
- let(:current_page) { 2 }
46
+ let(:page) { 2 }
47
47
  let(:size) { 26 }
48
48
 
49
49
  it("return a valid offset") { should == 25 }
@@ -53,7 +53,7 @@ describe MongoBrowser::Models::Pager do
53
53
  describe "#total_pages" do
54
54
  subject { pager.total_pages }
55
55
 
56
- { 1 => 1, 25 => 1, 26 => 2, 50 => 2, 51 => 3, 101 => 5 }.each do |size, expected|
56
+ { 0 => 1, 1 => 1, 25 => 1, 26 => 2, 50 => 2, 51 => 3, 101 => 5 }.each do |size, expected|
57
57
  context "when the size is #{size}" do
58
58
  let(:size) { size }
59
59
 
@@ -61,4 +61,13 @@ describe MongoBrowser::Models::Pager do
61
61
  end
62
62
  end
63
63
  end
64
+
65
+ describe "#to_hash" do
66
+ subject { pager.to_hash }
67
+
68
+ it { should be_an_instance_of(Hash) }
69
+ its([:size]) { should == 25 }
70
+ its([:page]) { should == 1 }
71
+ its([:total_pages]) { should == 1 }
72
+ end
64
73
  end
@@ -4,28 +4,20 @@ require "mongo_browser"
4
4
 
5
5
  require "debugger"
6
6
  require "rspec"
7
+ require "rack/test"
8
+
9
+ if ENV["TRAVIS"]
10
+ require "coveralls"
11
+ Coveralls.wear!
12
+ end
7
13
 
8
14
  # Requires supporting ruby files with custom matchers and macros, etc,
9
15
  # from spec/support/ and its subdirectories.
10
16
  Dir[File.expand_path("spec/support/**/*.rb")].each { |f| require f }
11
17
 
12
- test_server = Mongod.instance
13
- fixtures = Fixtures.instance
14
-
15
18
  RSpec.configure do |config|
16
- config.include FeatureExampleGroup, type: :request
17
-
18
- # Run test mongod instance and load database fixtures
19
19
  config.before do
20
- test_server.start! do |port|
21
- MongoBrowser.mongodb_host = "127.0.0.1"
22
- MongoBrowser.mongodb_port = port
23
- end
24
-
20
+ fixtures = Fixtures.instance
25
21
  fixtures.load!
26
22
  end
27
23
  end
28
-
29
- at_exit do
30
- test_server.shutdown!
31
- end
@@ -0,0 +1,45 @@
1
+ module ApiExampleGroup
2
+ include Rack::Test::Methods
3
+
4
+ def self.included(base)
5
+ base.let(:server) { MongoBrowser::Models::Server.current }
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ # Helper for describing API endpoints
11
+ #
12
+ # Usage:
13
+ # describe_endpoint :delete, "/databases/:db_name" do
14
+ # let(:db_name) { "first_database" }
15
+ # # some assertions here
16
+ # end
17
+ def describe_endpoint(method, route_path, &block)
18
+ describe "#{method.upcase} #{route_path}" do
19
+ let(:path) do
20
+ path = route_path.clone
21
+ route_path.scan(/(:(\w+))/).each do |place_holder, name|
22
+ path.sub!(place_holder, instance_eval(name).to_s)
23
+ end
24
+
25
+ path
26
+ end
27
+
28
+ let(:do_request) { send(method.downcase.to_sym, path) }
29
+ subject(:response) { do_request }
30
+
31
+ # Create a new context with route description
32
+ by_path = -> route { route.route_path.match(/^#{route_path.split("?").first}/) }
33
+ route = described_class.routes.find(&by_path)
34
+
35
+ if route and route.route_description
36
+ describe route.route_description do
37
+ instance_eval(&block)
38
+ end
39
+ else
40
+ instance_eval(&block)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -20,16 +20,20 @@ class Fixtures
20
20
  end
21
21
  end
22
22
 
23
+ def load_documents!
24
+ database = connection.db("first_database")
25
+ collection = database.collection("second_collection")
26
+ collection.remove()
27
+
28
+ 70.times do |n|
29
+ collection.insert(name: "Document #{n}", position: n)
30
+ end
31
+ end
32
+
23
33
  # Delete all databases
24
34
  def cleanup!
25
35
  fixture_databases = data.map { |db| db["name"] }
26
36
 
27
- # Drop all databases outside fixtures
28
- other_databases = connection.database_names - fixture_databases
29
- other_databases.each do |db_name|
30
- connection.drop_database(db_name)
31
- end
32
-
33
37
  # Drop collections inside databases
34
38
  fixture_databases.each do |db_name|
35
39
  collection_names = connection[db_name].collection_names - ["system.indexes"]
@@ -0,0 +1,18 @@
1
+ RSpec::Matchers.define :expose do |expected|
2
+ match do |entity|
3
+ entity.exposures.keys.include?(expected)
4
+ end
5
+
6
+ failure_message_for_should do |entity|
7
+ "expected that #{entity} would exposure :#{expected}"
8
+ end
9
+
10
+ description do |entity|
11
+ str = "expose :#{expected}"
12
+
13
+ doc = entity.documentation[expected]
14
+ str << " [#{doc[:type]}] #{doc[:desc]}" if doc
15
+
16
+ str
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.0.3
2
+ * @license AngularJS v1.1.1
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.0.3
2
+ * @license AngularJS v1.0.7
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -12,7 +12,7 @@
12
12
  * @description
13
13
  */
14
14
 
15
- /**
15
+ /**
16
16
  * @ngdoc object
17
17
  * @name ngResource.$resource
18
18
  * @requires $http
@@ -24,8 +24,21 @@
24
24
  * The returned resource object has action methods which provide high-level behaviors without
25
25
  * the need to interact with the low level {@link ng.$http $http} service.
26
26
  *
27
+ * # Installation
28
+ * To use $resource make sure you have included the `angular-resource.js` that comes in Angular
29
+ * package. You can also find this file on Google CDN, bower as well as at
30
+ * {@link http://code.angularjs.org/ code.angularjs.org}.
31
+ *
32
+ * Finally load the module in your application:
33
+ *
34
+ * angular.module('app', ['ngResource']);
35
+ *
36
+ * and you are ready to get started!
37
+ *
27
38
  * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
28
- * `/user/:username`.
39
+ * `/user/:username`. If you are using a URL with a port number (e.g.
40
+ * `http://example.com:8080/api`), you'll need to escape the colon character before the port
41
+ * number, like this: `$resource('http://example.com\\:8080/api')`.
29
42
  *
30
43
  * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
31
44
  * `actions` methods.
@@ -67,9 +80,9 @@
67
80
  *
68
81
  * Calling these methods invoke an {@link ng.$http} with the specified http method,
69
82
  * destination and parameters. When the data is returned from the server then the object is an
70
- * instance of the resource class `save`, `remove` and `delete` actions are available on it as
71
- * methods with the `$` prefix. This allows you to easily perform CRUD operations (create, read,
72
- * update, delete) on server-side data like this:
83
+ * instance of the resource class. The actions `save`, `remove` and `delete` are available on it
84
+ * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
85
+ * read, update, delete) on server-side data like this:
73
86
  * <pre>
74
87
  var User = $resource('/user/:userId', {userId:'@id'});
75
88
  var user = User.get({userId:123}, function() {
@@ -149,9 +162,9 @@
149
162
  });
150
163
  </pre>
151
164
  *
152
- * It's worth noting that the success callback for `get`, `query` and other method gets passed
153
- * in the response that came from the server as well as $http header getter function, so one
154
- * could rewrite the above example and get access to http headers as:
165
+ * It's worth noting that the success callback for `get`, `query` and other method gets passed
166
+ * in the response that came from the server as well as $http header getter function, so one
167
+ * could rewrite the above example and get access to http headers as:
155
168
  *
156
169
  <pre>
157
170
  var User = $resource('/user/:userId', {userId:'@id'});
@@ -230,51 +243,51 @@ angular.module('ngResource', ['ng']).
230
243
  return $parse(path)(obj);
231
244
  };
232
245
 
233
- /**
234
- * We need our custom mehtod because encodeURIComponent is too aggressive and doesn't follow
235
- * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
236
- * segments:
237
- * segment = *pchar
238
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
239
- * pct-encoded = "%" HEXDIG HEXDIG
240
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
241
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
242
- * / "*" / "+" / "," / ";" / "="
243
- */
244
- function encodeUriSegment(val) {
245
- return encodeUriQuery(val, true).
246
- replace(/%26/gi, '&').
247
- replace(/%3D/gi, '=').
248
- replace(/%2B/gi, '+');
249
- }
250
-
251
-
252
- /**
253
- * This method is intended for encoding *key* or *value* parts of query component. We need a custom
254
- * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
255
- * encoded per http://tools.ietf.org/html/rfc3986:
256
- * query = *( pchar / "/" / "?" )
257
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
258
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
259
- * pct-encoded = "%" HEXDIG HEXDIG
260
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
261
- * / "*" / "+" / "," / ";" / "="
262
- */
263
- function encodeUriQuery(val, pctEncodeSpaces) {
264
- return encodeURIComponent(val).
265
- replace(/%40/gi, '@').
266
- replace(/%3A/gi, ':').
267
- replace(/%24/g, '$').
268
- replace(/%2C/gi, ',').
269
- replace((pctEncodeSpaces ? null : /%20/g), '+');
270
- }
271
-
272
- function Route(template, defaults) {
246
+ /**
247
+ * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
248
+ * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
249
+ * segments:
250
+ * segment = *pchar
251
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
252
+ * pct-encoded = "%" HEXDIG HEXDIG
253
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
254
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
255
+ * / "*" / "+" / "," / ";" / "="
256
+ */
257
+ function encodeUriSegment(val) {
258
+ return encodeUriQuery(val, true).
259
+ replace(/%26/gi, '&').
260
+ replace(/%3D/gi, '=').
261
+ replace(/%2B/gi, '+');
262
+ }
263
+
264
+
265
+ /**
266
+ * This method is intended for encoding *key* or *value* parts of query component. We need a custom
267
+ * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
268
+ * encoded per http://tools.ietf.org/html/rfc3986:
269
+ * query = *( pchar / "/" / "?" )
270
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
271
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
272
+ * pct-encoded = "%" HEXDIG HEXDIG
273
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
274
+ * / "*" / "+" / "," / ";" / "="
275
+ */
276
+ function encodeUriQuery(val, pctEncodeSpaces) {
277
+ return encodeURIComponent(val).
278
+ replace(/%40/gi, '@').
279
+ replace(/%3A/gi, ':').
280
+ replace(/%24/g, '$').
281
+ replace(/%2C/gi, ',').
282
+ replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
283
+ }
284
+
285
+ function Route(template, defaults) {
273
286
  this.template = template = template + '#';
274
287
  this.defaults = defaults || {};
275
288
  var urlParams = this.urlParams = {};
276
289
  forEach(template.split(/\W/), function(param){
277
- if (param && template.match(new RegExp("[^\\\\]:" + param + "\\W"))) {
290
+ if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) {
278
291
  urlParams[param] = true;
279
292
  }
280
293
  });
@@ -295,7 +308,14 @@ angular.module('ngResource', ['ng']).
295
308
  encodedVal = encodeUriSegment(val);
296
309
  url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
297
310
  } else {
298
- url = url.replace(new RegExp("/?:" + urlParam + "(\\W)", "g"), '$1');
311
+ url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match,
312
+ leadingSlashes, tail) {
313
+ if (tail.charAt(0) == '/') {
314
+ return tail;
315
+ } else {
316
+ return leadingSlashes + tail;
317
+ }
318
+ });
299
319
  }
300
320
  });
301
321
  url = url.replace(/\/?#$/, '');
@@ -331,6 +351,7 @@ angular.module('ngResource', ['ng']).
331
351
  }
332
352
 
333
353
  forEach(actions, function(action, name) {
354
+ action.method = angular.uppercase(action.method);
334
355
  var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH';
335
356
  Resource[name] = function(a1, a2, a3, a4) {
336
357
  var params = {};
@@ -396,11 +417,6 @@ angular.module('ngResource', ['ng']).
396
417
  };
397
418
 
398
419
 
399
- Resource.bind = function(additionalParamDefaults){
400
- return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
401
- };
402
-
403
-
404
420
  Resource.prototype['$' + name] = function(a1, a2, a3) {
405
421
  var params = extractParams(this),
406
422
  success = noop,
@@ -426,10 +442,16 @@ angular.module('ngResource', ['ng']).
426
442
  Resource[name].call(this, params, data, success, error);
427
443
  };
428
444
  });
445
+
446
+ Resource.bind = function(additionalParamDefaults){
447
+ return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
448
+ };
449
+
429
450
  return Resource;
430
451
  }
431
452
 
432
453
  return ResourceFactory;
433
454
  }]);
434
455
 
456
+
435
457
  })(window, window.angular);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.0.3
2
+ * @license AngularJS v1.0.7
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -422,6 +422,7 @@ angular.module('ngSanitize').directive('ngBindHtml', ['$sanitize', function($san
422
422
  });
423
423
  };
424
424
  }]);
425
+
425
426
  /**
426
427
  * @ngdoc filter
427
428
  * @name ngSanitize.filter:linky
@@ -532,4 +533,5 @@ angular.module('ngSanitize').filter('linky', function() {
532
533
  };
533
534
  });
534
535
 
536
+
535
537
  })(window, window.angular);