spree_core 3.4.6 → 3.5.0.rc1
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.
- checksums.yaml +5 -5
- data/app/assets/javascripts/spree.js.coffee +1 -1
- data/app/helpers/spree/base_helper.rb +4 -0
- data/app/models/concerns/spree/named_type.rb +1 -1
- data/app/models/concerns/spree/user_methods.rb +21 -4
- data/app/models/concerns/spree/user_reporting.rb +2 -2
- data/app/models/spree/address.rb +6 -12
- data/app/models/spree/adjustable/adjustments_updater.rb +2 -1
- data/app/models/spree/country.rb +2 -1
- data/app/models/spree/line_item.rb +8 -2
- data/app/models/spree/log_entry.rb +1 -1
- data/app/models/spree/order.rb +8 -6
- data/app/models/spree/order/checkout.rb +1 -0
- data/app/models/spree/order_contents.rb +20 -12
- data/app/models/spree/order_inventory.rb +24 -12
- data/app/models/spree/payment/processing.rb +2 -2
- data/app/models/spree/preferences/preferable.rb +1 -1
- data/app/models/spree/product/scopes.rb +1 -1
- data/app/models/spree/promotion.rb +15 -1
- data/app/models/spree/promotion/rules/option_value.rb +13 -5
- data/app/models/spree/promotion/rules/product.rb +2 -1
- data/app/models/spree/promotion/rules/taxon.rb +3 -1
- data/app/models/spree/promotion_action_line_item.rb +3 -0
- data/app/models/spree/promotion_handler/promotion_duplicator.rb +52 -0
- data/app/models/spree/refund.rb +1 -1
- data/app/models/spree/reimbursement.rb +1 -1
- data/app/models/spree/reimbursement/reimbursement_type_engine.rb +7 -18
- data/app/models/spree/reimbursement_performer.rb +3 -7
- data/app/models/spree/reimbursement_type/original_payment.rb +2 -2
- data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +3 -7
- data/app/models/spree/reimbursement_type/store_credit.rb +2 -10
- data/app/models/spree/shipment.rb +10 -4
- data/app/models/spree/stock/availability_validator.rb +1 -1
- data/app/models/spree/stock/packer.rb +1 -1
- data/app/models/spree/stock/splitter/backordered.rb +5 -7
- data/app/models/spree/stock/splitter/base.rb +1 -0
- data/app/models/spree/stock/splitter/shipping_category.rb +9 -16
- data/app/models/spree/stock/splitter/weight.rb +18 -20
- data/app/models/spree/stock_transfer.rb +2 -1
- data/app/models/spree/store_credit_category.rb +13 -0
- data/app/models/spree/taxon.rb +7 -0
- data/app/models/spree/variant.rb +1 -1
- data/app/validators/email_validator.rb +7 -0
- data/config/locales/en.yml +18 -27
- data/db/default/spree/states.rb +9 -27
- data/db/migrate/20150128032538_remove_environment_from_tracker.rb +2 -0
- data/db/migrate/20171004223836_remove_icon_from_taxons.rb +8 -0
- data/db/migrate/20180222133746_add_unique_index_on_spree_promotions_code.rb +6 -0
- data/lib/generators/spree/dummy_model/dummy_model_generator.rb +23 -0
- data/lib/generators/spree/dummy_model/templates/migration.rb.tt +10 -0
- data/lib/generators/spree/dummy_model/templates/model.rb.tt +6 -0
- data/lib/spree/core/controller_helpers/auth.rb +1 -1
- data/lib/spree/core/controller_helpers/common.rb +4 -0
- data/lib/spree/core/controller_helpers/order.rb +6 -5
- data/lib/spree/core/engine.rb +10 -10
- data/lib/spree/core/environment_extension.rb +3 -0
- data/lib/spree/core/importer/order.rb +1 -1
- data/lib/spree/core/validators/email.rb +1 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/money.rb +1 -5
- data/lib/spree/permitted_attributes.rb +1 -1
- data/lib/spree/testing_support/capybara_ext.rb +16 -13
- data/lib/spree/testing_support/common_rake.rb +4 -1
- data/lib/spree/testing_support/factories/inventory_unit_factory.rb +7 -0
- data/lib/spree/testing_support/factories/taxon_factory.rb +1 -1
- data/spree_core.gemspec +1 -1
- data/vendor/assets/javascripts/jsuri.js +458 -2
- metadata +13 -7
- data/app/models/spree/tracker.rb +0 -25
- data/lib/spree/testing_support/factories/tracker_factory.rb +0 -7
@@ -4,6 +4,9 @@ module Spree
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
def add_class(name)
|
7
|
+
ActiveSupport::Deprecation.warn(<<-EOS, caller)
|
8
|
+
EnvironmentExtension module is deprecated and will be removed in Spree 3.6
|
9
|
+
EOS
|
7
10
|
instance_variable_set "@#{name}", Set.new
|
8
11
|
|
9
12
|
create_method("#{name}=".to_sym) do |val|
|
@@ -94,7 +94,7 @@ module Spree
|
|
94
94
|
if existing
|
95
95
|
existing.quantity += 1
|
96
96
|
else
|
97
|
-
line_item = order.line_items.detect { |ln| ln.variant_id
|
97
|
+
line_item = order.line_items.detect { |ln| ln.variant_id == inventory_unit_param[:variant_id] }
|
98
98
|
inventory_units << InventoryUnit.new(line_item: line_item, order_id: order.id, variant: line_item.variant, quantity: 1)
|
99
99
|
end
|
100
100
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
class EmailValidator < ActiveModel::EachValidator
|
2
2
|
def validate_each(record, attribute, value)
|
3
|
+
warn "`EmailValidator` in 'lib/spree/core' is deprecated. Use `EmailValidator` in 'app/validators' instead."
|
3
4
|
unless value =~ /\A[^@\s]+@[^@\s]+\z/
|
4
5
|
record.errors.add(attribute, :invalid, { value: value }.merge!(options))
|
5
6
|
end
|
data/lib/spree/core/version.rb
CHANGED
data/lib/spree/money.rb
CHANGED
@@ -15,17 +15,13 @@ module Spree
|
|
15
15
|
|
16
16
|
attr_reader :money
|
17
17
|
|
18
|
-
delegate :cents,
|
18
|
+
delegate :cents, to: :money
|
19
19
|
|
20
20
|
def initialize(amount, options = {})
|
21
21
|
@money = Monetize.parse([amount, (options[:currency] || Spree::Config[:currency])].join)
|
22
22
|
@options = Spree::Money.default_formatting_rules.merge(options)
|
23
23
|
end
|
24
24
|
|
25
|
-
def amount_in_cents
|
26
|
-
(cents / currency.subunit_to_unit.to_f * 100).round
|
27
|
-
end
|
28
|
-
|
29
25
|
def to_s
|
30
26
|
@money.format(@options)
|
31
27
|
end
|
@@ -90,7 +90,7 @@ module Spree
|
|
90
90
|
@@stock_movement_attributes = [
|
91
91
|
:quantity, :stock_item, :stock_item_id, :originator, :action]
|
92
92
|
|
93
|
-
@@store_attributes = [:name, :url, :seo_title, :meta_keywords,
|
93
|
+
@@store_attributes = [:name, :url, :seo_title, :code, :meta_keywords,
|
94
94
|
:meta_description, :default_currency, :mail_from_address]
|
95
95
|
|
96
96
|
@@store_credit_attributes = [:amount, :category_id, :memo]
|
@@ -59,8 +59,6 @@ module CapybaraExt
|
|
59
59
|
raise "Must pass a hash containing 'from'" if !options.is_a?(Hash) || !options.key?(:from)
|
60
60
|
|
61
61
|
placeholder = options[:from]
|
62
|
-
minlength = options[:minlength] || 4
|
63
|
-
|
64
62
|
click_link placeholder
|
65
63
|
|
66
64
|
select_select2_result(value)
|
@@ -101,12 +99,11 @@ module CapybaraExt
|
|
101
99
|
|
102
100
|
# arg delay in seconds
|
103
101
|
def wait_for_ajax(delay = Capybara.default_max_wait_time)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
raise "AJAX request took longer than #{delay} seconds." if counter >= delay_threshold
|
102
|
+
Timeout.timeout(delay) do
|
103
|
+
active = page.evaluate_script('typeof jQuery !== "undefined" && jQuery.active')
|
104
|
+
until active.zero?
|
105
|
+
active = page.evaluate_script('typeof jQuery !== "undefined" && jQuery.active')
|
106
|
+
end
|
110
107
|
end
|
111
108
|
end
|
112
109
|
|
@@ -114,6 +111,7 @@ module CapybaraExt
|
|
114
111
|
#
|
115
112
|
# Much better than a random sleep "here and there"
|
116
113
|
# it will not cause any delay in case the condition is fullfilled on first cycle.
|
114
|
+
|
117
115
|
def wait_for_condition(delay = Capybara.default_max_wait_time)
|
118
116
|
counter = 0
|
119
117
|
delay_threshold = delay * 10
|
@@ -124,17 +122,22 @@ module CapybaraExt
|
|
124
122
|
end
|
125
123
|
end
|
126
124
|
|
127
|
-
def accept_alert
|
128
|
-
page.evaluate_script('window.confirm = function() { return true; }')
|
129
|
-
yield
|
130
|
-
end
|
131
|
-
|
132
125
|
def dismiss_alert
|
133
126
|
page.evaluate_script('window.confirm = function() { return false; }')
|
134
127
|
yield
|
135
128
|
# Restore existing default
|
136
129
|
page.evaluate_script('window.confirm = function() { return true; }')
|
137
130
|
end
|
131
|
+
|
132
|
+
def spree_accept_alert
|
133
|
+
yield
|
134
|
+
rescue Selenium::WebDriver::Error::UnhandledAlertError
|
135
|
+
page.driver.browser.switch_to.alert.accept
|
136
|
+
end
|
137
|
+
|
138
|
+
def disable_html5_validation
|
139
|
+
page.execute_script('for(var f=document.forms,i=f.length;i--;)f[i].setAttribute("novalidate",i)')
|
140
|
+
end
|
138
141
|
end
|
139
142
|
|
140
143
|
Capybara.configure do |config|
|
@@ -3,6 +3,7 @@ unless defined?(Spree::InstallGenerator)
|
|
3
3
|
end
|
4
4
|
|
5
5
|
require 'generators/spree/dummy/dummy_generator'
|
6
|
+
require 'generators/spree/dummy_model/dummy_model_generator'
|
6
7
|
|
7
8
|
desc 'Generates a dummy app for testing'
|
8
9
|
namespace :common do
|
@@ -17,7 +18,9 @@ namespace :common do
|
|
17
18
|
Spree::InstallGenerator.start ["--lib_name=#{ENV['LIB_NAME']}", '--auto-accept', '--migrate=false', '--seed=false', '--sample=false', '--quiet', '--copy_views=false', "--user_class=#{args[:user_class]}"]
|
18
19
|
|
19
20
|
puts 'Setting up dummy database...'
|
20
|
-
system("bundle exec rake db:drop db:create
|
21
|
+
system("bundle exec rake db:drop db:create > #{File::NULL}")
|
22
|
+
Spree::DummyModelGenerator.start
|
23
|
+
system("bundle exec rake db:migrate > #{File::NULL}")
|
21
24
|
|
22
25
|
begin
|
23
26
|
require "generators/#{ENV['LIB_NAME']}/install/install_generator"
|
@@ -6,5 +6,12 @@ FactoryBot.define do
|
|
6
6
|
state 'on_hand'
|
7
7
|
association(:shipment, factory: :shipment, state: 'pending')
|
8
8
|
# return_authorization
|
9
|
+
|
10
|
+
# this trait usage increases build speed ~ 2x
|
11
|
+
trait :without_assoc do
|
12
|
+
shipment nil
|
13
|
+
order nil
|
14
|
+
line_item nil
|
15
|
+
end
|
9
16
|
end
|
10
17
|
end
|
data/spree_core.gemspec
CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
|
|
35
35
|
s.add_dependency 'paranoia', '~> 2.3.0'
|
36
36
|
s.add_dependency 'premailer-rails'
|
37
37
|
s.add_dependency 'acts-as-taggable-on', '~> 5.0'
|
38
|
-
s.add_dependency 'rails', '~> 5.1.
|
38
|
+
s.add_dependency 'rails', '~> 5.1.5'
|
39
39
|
s.add_dependency 'ransack', '~> 1.8.0'
|
40
40
|
s.add_dependency 'responders'
|
41
41
|
s.add_dependency 'state_machines-activerecord', '~> 0.5'
|
@@ -1,2 +1,458 @@
|
|
1
|
-
/*!
|
2
|
-
|
1
|
+
/*!
|
2
|
+
* jsUri
|
3
|
+
* https://github.com/derek-watson/jsUri
|
4
|
+
*
|
5
|
+
* Copyright 2013, Derek Watson
|
6
|
+
* Released under the MIT license.
|
7
|
+
*
|
8
|
+
* Includes parseUri regular expressions
|
9
|
+
* http://blog.stevenlevithan.com/archives/parseuri
|
10
|
+
* Copyright 2007, Steven Levithan
|
11
|
+
* Released under the MIT license.
|
12
|
+
*/
|
13
|
+
|
14
|
+
/*globals define, module */
|
15
|
+
|
16
|
+
(function(global) {
|
17
|
+
|
18
|
+
var re = {
|
19
|
+
starts_with_slashes: /^\/+/,
|
20
|
+
ends_with_slashes: /\/+$/,
|
21
|
+
pluses: /\+/g,
|
22
|
+
query_separator: /[&;]/,
|
23
|
+
uri_parser: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*)(?::([^:@]*))?)?@)?(\[[0-9a-fA-F:.]+\]|[^:\/?#]*)(?::(\d+|(?=:)))?(:)?)((((?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
|
24
|
+
};
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Define forEach for older js environments
|
28
|
+
* @see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach#Compatibility
|
29
|
+
*/
|
30
|
+
if (!Array.prototype.forEach) {
|
31
|
+
Array.prototype.forEach = function(callback, thisArg) {
|
32
|
+
var T, k;
|
33
|
+
|
34
|
+
if (this == null) {
|
35
|
+
throw new TypeError(' this is null or not defined');
|
36
|
+
}
|
37
|
+
|
38
|
+
var O = Object(this);
|
39
|
+
var len = O.length >>> 0;
|
40
|
+
|
41
|
+
if (typeof callback !== "function") {
|
42
|
+
throw new TypeError(callback + ' is not a function');
|
43
|
+
}
|
44
|
+
|
45
|
+
if (arguments.length > 1) {
|
46
|
+
T = thisArg;
|
47
|
+
}
|
48
|
+
|
49
|
+
k = 0;
|
50
|
+
|
51
|
+
while (k < len) {
|
52
|
+
var kValue;
|
53
|
+
if (k in O) {
|
54
|
+
kValue = O[k];
|
55
|
+
callback.call(T, kValue, k, O);
|
56
|
+
}
|
57
|
+
k++;
|
58
|
+
}
|
59
|
+
};
|
60
|
+
}
|
61
|
+
|
62
|
+
/**
|
63
|
+
* unescape a query param value
|
64
|
+
* @param {string} s encoded value
|
65
|
+
* @return {string} decoded value
|
66
|
+
*/
|
67
|
+
function decode(s) {
|
68
|
+
if (s) {
|
69
|
+
s = s.toString().replace(re.pluses, '%20');
|
70
|
+
s = decodeURIComponent(s);
|
71
|
+
}
|
72
|
+
return s;
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* Breaks a uri string down into its individual parts
|
77
|
+
* @param {string} str uri
|
78
|
+
* @return {object} parts
|
79
|
+
*/
|
80
|
+
function parseUri(str) {
|
81
|
+
var parser = re.uri_parser;
|
82
|
+
var parserKeys = ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "isColonUri", "relative", "path", "directory", "file", "query", "anchor"];
|
83
|
+
var m = parser.exec(str || '');
|
84
|
+
var parts = {};
|
85
|
+
|
86
|
+
parserKeys.forEach(function(key, i) {
|
87
|
+
parts[key] = m[i] || '';
|
88
|
+
});
|
89
|
+
|
90
|
+
return parts;
|
91
|
+
}
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Breaks a query string down into an array of key/value pairs
|
95
|
+
* @param {string} str query
|
96
|
+
* @return {array} array of arrays (key/value pairs)
|
97
|
+
*/
|
98
|
+
function parseQuery(str) {
|
99
|
+
var i, ps, p, n, k, v, l;
|
100
|
+
var pairs = [];
|
101
|
+
|
102
|
+
if (typeof(str) === 'undefined' || str === null || str === '') {
|
103
|
+
return pairs;
|
104
|
+
}
|
105
|
+
|
106
|
+
if (str.indexOf('?') === 0) {
|
107
|
+
str = str.substring(1);
|
108
|
+
}
|
109
|
+
|
110
|
+
ps = str.toString().split(re.query_separator);
|
111
|
+
|
112
|
+
for (i = 0, l = ps.length; i < l; i++) {
|
113
|
+
p = ps[i];
|
114
|
+
n = p.indexOf('=');
|
115
|
+
|
116
|
+
if (n !== 0) {
|
117
|
+
k = decode(p.substring(0, n));
|
118
|
+
v = decode(p.substring(n + 1));
|
119
|
+
pairs.push(n === -1 ? [p, null] : [k, v]);
|
120
|
+
}
|
121
|
+
|
122
|
+
}
|
123
|
+
return pairs;
|
124
|
+
}
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Creates a new Uri object
|
128
|
+
* @constructor
|
129
|
+
* @param {string} str
|
130
|
+
*/
|
131
|
+
function Uri(str) {
|
132
|
+
this.uriParts = parseUri(str);
|
133
|
+
this.queryPairs = parseQuery(this.uriParts.query);
|
134
|
+
this.hasAuthorityPrefixUserPref = null;
|
135
|
+
}
|
136
|
+
|
137
|
+
/**
|
138
|
+
* Define getter/setter methods
|
139
|
+
*/
|
140
|
+
['protocol', 'userInfo', 'host', 'port', 'path', 'anchor'].forEach(function(key) {
|
141
|
+
Uri.prototype[key] = function(val) {
|
142
|
+
if (typeof val !== 'undefined') {
|
143
|
+
this.uriParts[key] = val;
|
144
|
+
}
|
145
|
+
return this.uriParts[key];
|
146
|
+
};
|
147
|
+
});
|
148
|
+
|
149
|
+
/**
|
150
|
+
* if there is no protocol, the leading // can be enabled or disabled
|
151
|
+
* @param {Boolean} val
|
152
|
+
* @return {Boolean}
|
153
|
+
*/
|
154
|
+
Uri.prototype.hasAuthorityPrefix = function(val) {
|
155
|
+
if (typeof val !== 'undefined') {
|
156
|
+
this.hasAuthorityPrefixUserPref = val;
|
157
|
+
}
|
158
|
+
|
159
|
+
if (this.hasAuthorityPrefixUserPref === null) {
|
160
|
+
return (this.uriParts.source.indexOf('//') !== -1);
|
161
|
+
} else {
|
162
|
+
return this.hasAuthorityPrefixUserPref;
|
163
|
+
}
|
164
|
+
};
|
165
|
+
|
166
|
+
Uri.prototype.isColonUri = function (val) {
|
167
|
+
if (typeof val !== 'undefined') {
|
168
|
+
this.uriParts.isColonUri = !!val;
|
169
|
+
} else {
|
170
|
+
return !!this.uriParts.isColonUri;
|
171
|
+
}
|
172
|
+
};
|
173
|
+
|
174
|
+
/**
|
175
|
+
* Serializes the internal state of the query pairs
|
176
|
+
* @param {string} [val] set a new query string
|
177
|
+
* @return {string} query string
|
178
|
+
*/
|
179
|
+
Uri.prototype.query = function(val) {
|
180
|
+
var s = '', i, param, l;
|
181
|
+
|
182
|
+
if (typeof val !== 'undefined') {
|
183
|
+
this.queryPairs = parseQuery(val);
|
184
|
+
}
|
185
|
+
|
186
|
+
for (i = 0, l = this.queryPairs.length; i < l; i++) {
|
187
|
+
param = this.queryPairs[i];
|
188
|
+
if (s.length > 0) {
|
189
|
+
s += '&';
|
190
|
+
}
|
191
|
+
if (param[1] === null) {
|
192
|
+
s += param[0];
|
193
|
+
} else {
|
194
|
+
s += param[0];
|
195
|
+
s += '=';
|
196
|
+
if (typeof param[1] !== 'undefined') {
|
197
|
+
s += encodeURIComponent(param[1]);
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
return s.length > 0 ? '?' + s : s;
|
202
|
+
};
|
203
|
+
|
204
|
+
/**
|
205
|
+
* returns the first query param value found for the key
|
206
|
+
* @param {string} key query key
|
207
|
+
* @return {string} first value found for key
|
208
|
+
*/
|
209
|
+
Uri.prototype.getQueryParamValue = function (key) {
|
210
|
+
var param, i, l;
|
211
|
+
for (i = 0, l = this.queryPairs.length; i < l; i++) {
|
212
|
+
param = this.queryPairs[i];
|
213
|
+
if (key === param[0]) {
|
214
|
+
return param[1];
|
215
|
+
}
|
216
|
+
}
|
217
|
+
};
|
218
|
+
|
219
|
+
/**
|
220
|
+
* returns an array of query param values for the key
|
221
|
+
* @param {string} key query key
|
222
|
+
* @return {array} array of values
|
223
|
+
*/
|
224
|
+
Uri.prototype.getQueryParamValues = function (key) {
|
225
|
+
var arr = [], i, param, l;
|
226
|
+
for (i = 0, l = this.queryPairs.length; i < l; i++) {
|
227
|
+
param = this.queryPairs[i];
|
228
|
+
if (key === param[0]) {
|
229
|
+
arr.push(param[1]);
|
230
|
+
}
|
231
|
+
}
|
232
|
+
return arr;
|
233
|
+
};
|
234
|
+
|
235
|
+
/**
|
236
|
+
* removes query parameters
|
237
|
+
* @param {string} key remove values for key
|
238
|
+
* @param {val} [val] remove a specific value, otherwise removes all
|
239
|
+
* @return {Uri} returns self for fluent chaining
|
240
|
+
*/
|
241
|
+
Uri.prototype.deleteQueryParam = function (key, val) {
|
242
|
+
var arr = [], i, param, keyMatchesFilter, valMatchesFilter, l;
|
243
|
+
|
244
|
+
for (i = 0, l = this.queryPairs.length; i < l; i++) {
|
245
|
+
|
246
|
+
param = this.queryPairs[i];
|
247
|
+
keyMatchesFilter = decode(param[0]) === decode(key);
|
248
|
+
valMatchesFilter = param[1] === val;
|
249
|
+
|
250
|
+
if ((arguments.length === 1 && !keyMatchesFilter) || (arguments.length === 2 && (!keyMatchesFilter || !valMatchesFilter))) {
|
251
|
+
arr.push(param);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
|
255
|
+
this.queryPairs = arr;
|
256
|
+
|
257
|
+
return this;
|
258
|
+
};
|
259
|
+
|
260
|
+
/**
|
261
|
+
* adds a query parameter
|
262
|
+
* @param {string} key add values for key
|
263
|
+
* @param {string} val value to add
|
264
|
+
* @param {integer} [index] specific index to add the value at
|
265
|
+
* @return {Uri} returns self for fluent chaining
|
266
|
+
*/
|
267
|
+
Uri.prototype.addQueryParam = function (key, val, index) {
|
268
|
+
if (arguments.length === 3 && index !== -1) {
|
269
|
+
index = Math.min(index, this.queryPairs.length);
|
270
|
+
this.queryPairs.splice(index, 0, [key, val]);
|
271
|
+
} else if (arguments.length > 0) {
|
272
|
+
this.queryPairs.push([key, val]);
|
273
|
+
}
|
274
|
+
return this;
|
275
|
+
};
|
276
|
+
|
277
|
+
/**
|
278
|
+
* test for the existence of a query parameter
|
279
|
+
* @param {string} key check values for key
|
280
|
+
* @return {Boolean} true if key exists, otherwise false
|
281
|
+
*/
|
282
|
+
Uri.prototype.hasQueryParam = function (key) {
|
283
|
+
var i, len = this.queryPairs.length;
|
284
|
+
for (i = 0; i < len; i++) {
|
285
|
+
if (this.queryPairs[i][0] == key)
|
286
|
+
return true;
|
287
|
+
}
|
288
|
+
return false;
|
289
|
+
};
|
290
|
+
|
291
|
+
/**
|
292
|
+
* replaces query param values
|
293
|
+
* @param {string} key key to replace value for
|
294
|
+
* @param {string} newVal new value
|
295
|
+
* @param {string} [oldVal] replace only one specific value (otherwise replaces all)
|
296
|
+
* @return {Uri} returns self for fluent chaining
|
297
|
+
*/
|
298
|
+
Uri.prototype.replaceQueryParam = function (key, newVal, oldVal) {
|
299
|
+
var index = -1, len = this.queryPairs.length, i, param;
|
300
|
+
|
301
|
+
if (arguments.length === 3) {
|
302
|
+
for (i = 0; i < len; i++) {
|
303
|
+
param = this.queryPairs[i];
|
304
|
+
if (decode(param[0]) === decode(key) && decodeURIComponent(param[1]) === decode(oldVal)) {
|
305
|
+
index = i;
|
306
|
+
break;
|
307
|
+
}
|
308
|
+
}
|
309
|
+
if (index >= 0) {
|
310
|
+
this.deleteQueryParam(key, decode(oldVal)).addQueryParam(key, newVal, index);
|
311
|
+
}
|
312
|
+
} else {
|
313
|
+
for (i = 0; i < len; i++) {
|
314
|
+
param = this.queryPairs[i];
|
315
|
+
if (decode(param[0]) === decode(key)) {
|
316
|
+
index = i;
|
317
|
+
break;
|
318
|
+
}
|
319
|
+
}
|
320
|
+
this.deleteQueryParam(key);
|
321
|
+
this.addQueryParam(key, newVal, index);
|
322
|
+
}
|
323
|
+
return this;
|
324
|
+
};
|
325
|
+
|
326
|
+
/**
|
327
|
+
* Define fluent setter methods (setProtocol, setHasAuthorityPrefix, etc)
|
328
|
+
*/
|
329
|
+
['protocol', 'hasAuthorityPrefix', 'isColonUri', 'userInfo', 'host', 'port', 'path', 'query', 'anchor'].forEach(function(key) {
|
330
|
+
var method = 'set' + key.charAt(0).toUpperCase() + key.slice(1);
|
331
|
+
Uri.prototype[method] = function(val) {
|
332
|
+
this[key](val);
|
333
|
+
return this;
|
334
|
+
};
|
335
|
+
});
|
336
|
+
|
337
|
+
/**
|
338
|
+
* Scheme name, colon and doubleslash, as required
|
339
|
+
* @return {string} http:// or possibly just //
|
340
|
+
*/
|
341
|
+
Uri.prototype.scheme = function() {
|
342
|
+
var s = '';
|
343
|
+
|
344
|
+
if (this.protocol()) {
|
345
|
+
s += this.protocol();
|
346
|
+
if (this.protocol().indexOf(':') !== this.protocol().length - 1) {
|
347
|
+
s += ':';
|
348
|
+
}
|
349
|
+
s += '//';
|
350
|
+
} else {
|
351
|
+
if (this.hasAuthorityPrefix() && this.host()) {
|
352
|
+
s += '//';
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
return s;
|
357
|
+
};
|
358
|
+
|
359
|
+
/**
|
360
|
+
* Same as Mozilla nsIURI.prePath
|
361
|
+
* @return {string} scheme://user:password@host:port
|
362
|
+
* @see https://developer.mozilla.org/en/nsIURI
|
363
|
+
*/
|
364
|
+
Uri.prototype.origin = function() {
|
365
|
+
var s = this.scheme();
|
366
|
+
|
367
|
+
if (this.userInfo() && this.host()) {
|
368
|
+
s += this.userInfo();
|
369
|
+
if (this.userInfo().indexOf('@') !== this.userInfo().length - 1) {
|
370
|
+
s += '@';
|
371
|
+
}
|
372
|
+
}
|
373
|
+
|
374
|
+
if (this.host()) {
|
375
|
+
s += this.host();
|
376
|
+
if (this.port() || (this.path() && this.path().substr(0, 1).match(/[0-9]/))) {
|
377
|
+
s += ':' + this.port();
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
381
|
+
return s;
|
382
|
+
};
|
383
|
+
|
384
|
+
/**
|
385
|
+
* Adds a trailing slash to the path
|
386
|
+
*/
|
387
|
+
Uri.prototype.addTrailingSlash = function() {
|
388
|
+
var path = this.path() || '';
|
389
|
+
|
390
|
+
if (path.substr(-1) !== '/') {
|
391
|
+
this.path(path + '/');
|
392
|
+
}
|
393
|
+
|
394
|
+
return this;
|
395
|
+
};
|
396
|
+
|
397
|
+
/**
|
398
|
+
* Serializes the internal state of the Uri object
|
399
|
+
* @return {string}
|
400
|
+
*/
|
401
|
+
Uri.prototype.toString = function() {
|
402
|
+
var path, s = this.origin();
|
403
|
+
|
404
|
+
if (this.isColonUri()) {
|
405
|
+
if (this.path()) {
|
406
|
+
s += ':'+this.path();
|
407
|
+
}
|
408
|
+
} else if (this.path()) {
|
409
|
+
path = this.path();
|
410
|
+
if (!(re.ends_with_slashes.test(s) || re.starts_with_slashes.test(path))) {
|
411
|
+
s += '/';
|
412
|
+
} else {
|
413
|
+
if (s) {
|
414
|
+
s.replace(re.ends_with_slashes, '/');
|
415
|
+
}
|
416
|
+
path = path.replace(re.starts_with_slashes, '/');
|
417
|
+
}
|
418
|
+
s += path;
|
419
|
+
} else {
|
420
|
+
if (this.host() && (this.query().toString() || this.anchor())) {
|
421
|
+
s += '/';
|
422
|
+
}
|
423
|
+
}
|
424
|
+
if (this.query().toString()) {
|
425
|
+
s += this.query().toString();
|
426
|
+
}
|
427
|
+
|
428
|
+
if (this.anchor()) {
|
429
|
+
if (this.anchor().indexOf('#') !== 0) {
|
430
|
+
s += '#';
|
431
|
+
}
|
432
|
+
s += this.anchor();
|
433
|
+
}
|
434
|
+
|
435
|
+
return s;
|
436
|
+
};
|
437
|
+
|
438
|
+
/**
|
439
|
+
* Clone a Uri object
|
440
|
+
* @return {Uri} duplicate copy of the Uri
|
441
|
+
*/
|
442
|
+
Uri.prototype.clone = function() {
|
443
|
+
return new Uri(this.toString());
|
444
|
+
};
|
445
|
+
|
446
|
+
/**
|
447
|
+
* export via AMD or CommonJS, otherwise leak a global
|
448
|
+
*/
|
449
|
+
if (typeof define === 'function' && define.amd) {
|
450
|
+
define(function() {
|
451
|
+
return Uri;
|
452
|
+
});
|
453
|
+
} else if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
454
|
+
module.exports = Uri;
|
455
|
+
} else {
|
456
|
+
global.Uri = Uri;
|
457
|
+
}
|
458
|
+
}(this));
|