gretel-trails 0.0.1
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 +7 -0
- data/.gitignore +23 -0
- data/.travis.yml +11 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +123 -0
- data/Rakefile +10 -0
- data/gretel-trails.gemspec +28 -0
- data/lib/assets/javascripts/gretel.trails.hidden.js.coffee.erb +32 -0
- data/lib/assets/javascripts/gretel.trails.jsuri.js.coffee +370 -0
- data/lib/gretel/trails/engine.rb +6 -0
- data/lib/gretel/trails/strategies/hidden_strategy.rb +57 -0
- data/lib/gretel/trails/version.rb +5 -0
- data/lib/gretel/trails.rb +25 -0
- data/lib/gretel-trails.rb +1 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +16 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/categories_controller.rb +5 -0
- data/test/dummy/app/controllers/products_controller.rb +13 -0
- data/test/dummy/app/controllers/reviews_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/.gitkeep +0 -0
- data/test/dummy/app/models/category.rb +11 -0
- data/test/dummy/app/models/product.rb +11 -0
- data/test/dummy/app/views/categories/show.html.erb +9 -0
- data/test/dummy/app/views/layouts/application.html.erb +16 -0
- data/test/dummy/app/views/products/recent.html.erb +9 -0
- data/test/dummy/app/views/products/show.html.erb +17 -0
- data/test/dummy/app/views/reviews/index.html.erb +13 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/breadcrumbs.rb +21 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/gretel.rb +2 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +9 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20131016195709_create_products.rb +13 -0
- data/test/dummy/db/migrate/20131016195903_create_categories.rb +11 -0
- data/test/dummy/db/migrate/20131016201943_create_gretel_trails.rb +11 -0
- data/test/dummy/db/schema.rb +45 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/log/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/fixtures/categories.yml +9 -0
- data/test/dummy/test/fixtures/products.yml +11 -0
- data/test/gretel_trails_test.rb +67 -0
- data/test/test_helper.rb +28 -0
- metadata +272 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 75ba4eea078b14bb0d61eb137262d08d24388554
|
4
|
+
data.tar.gz: aacf75c20b0fea1e345149b423e73a38dc165c6f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ccee9ba8ed783a89dc99844d5d090b562f582a28520e68360ebe1e97c13d9a1cde904d3ceb78b3cd7a626e6365a813905d5ee7ecbb46bea2934316b371d7b48
|
7
|
+
data.tar.gz: 304d444bfdde884621754e8e9b3499dad62554e6092f7c2361cd117e9006ecdca79874f259b99a02f8c7071a543c8747d05d677e8f22458818a9c20b434fba0d
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
log/*.log
|
19
|
+
test/dummy/db/*.sqlite3
|
20
|
+
test/dummy/log/*.log
|
21
|
+
test/dummy/tmp/
|
22
|
+
test/dummy/.sass-cache
|
23
|
+
.DS_Store
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Declare your gem's dependencies in gretel.gemspec.
|
4
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
+
# development dependencies will be added by default to the :development group.
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
# Used by the dummy application
|
9
|
+
gem "jquery-rails"
|
10
|
+
gem "coffee-rails"
|
11
|
+
|
12
|
+
# Declare any dependencies that are still in development here instead of in
|
13
|
+
# your gemspec. These might include edge Rails or gems from your path or
|
14
|
+
# Git. Remember to move these dependencies to your gemspec before releasing
|
15
|
+
# your gem to rubygems.org.
|
16
|
+
|
17
|
+
# To use debugger
|
18
|
+
# gem 'debugger'
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Lasse Bunk
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
[](http://travis-ci.org/lassebunk/gretel-trails)
|
2
|
+
|
3
|
+
# Gretel::Trails
|
4
|
+
|
5
|
+
Gretel::Trails makes it easy to hide [Gretel](https://github.com/lassebunk/gretel) breadcrumb trails from the user, so they don't see them in URLs when navigating your site.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your Gemfile:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
gem 'gretel-trails'
|
13
|
+
```
|
14
|
+
|
15
|
+
And run:
|
16
|
+
|
17
|
+
```bash
|
18
|
+
$ bundle
|
19
|
+
```
|
20
|
+
|
21
|
+
In an initializer, e.g. *config/initializers/gretel.rb*:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
Gretel::Trails.strategy = :hidden
|
25
|
+
```
|
26
|
+
|
27
|
+
Add a data attribute with the trail to your `<body>` tag, in *application.html.erb*:
|
28
|
+
|
29
|
+
```erb
|
30
|
+
<body data-trail="<%= breadcrumb_trail %>">
|
31
|
+
...
|
32
|
+
```
|
33
|
+
|
34
|
+
And finally, at the bottom of *app/assets/javascripts/application.js*:
|
35
|
+
|
36
|
+
```js
|
37
|
+
//= require gretel.trails.hidden
|
38
|
+
```
|
39
|
+
|
40
|
+
Breadcrumb trails are now hidden from the user so they don't see them in URLs. It uses data attributes and `history.replaceState` to hide the trails from the URL.
|
41
|
+
For older browsers it falls back gracefully to showing trails in the URL, as specified by `Gretel.trail_param`.
|
42
|
+
|
43
|
+
Note: If you use [Turbolinks](https://github.com/rails/turbolinks), it's important that you add the require *after* you require Turbolinks. Else it won't work.
|
44
|
+
|
45
|
+
## Usage
|
46
|
+
|
47
|
+
When you want to invisibly add the current trail when the user clicks a link, you add a special JS selector to the link where you want the trail added on click:
|
48
|
+
|
49
|
+
```erb
|
50
|
+
<% @products.each do |product| %>
|
51
|
+
<%= link_to "My product", product, class: "js-append-trail" %>
|
52
|
+
<% end %>
|
53
|
+
```
|
54
|
+
|
55
|
+
Trails are now transferred invisibly to the next page when the user clicks a link.
|
56
|
+
|
57
|
+
See Customization below for info on changing the `.js-append-trail` selector.
|
58
|
+
|
59
|
+
### Custom links
|
60
|
+
|
61
|
+
Inside breadcrumbs, the links are automatically transformed with trails removed from the URLs and applied as data attributes instead.
|
62
|
+
If you want to do custom breadcrumb links with these changes applied, you can use the `breadcrumb_link_to` helper:
|
63
|
+
|
64
|
+
```erb
|
65
|
+
<% parent_breadcrumb do |parent| %>
|
66
|
+
<%= breadcrumb_link_to "Back to #{parent.text}", parent.url %>
|
67
|
+
<% end %>
|
68
|
+
```
|
69
|
+
|
70
|
+
The link will now have a URL without the trail param and `data-trail` containing the trail.
|
71
|
+
|
72
|
+
## Customization
|
73
|
+
|
74
|
+
### JS selector
|
75
|
+
|
76
|
+
If you want to customize the JS selector (the default is `.js-append-trail`), you can do so in an initializer:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
Gretel::Trails::HiddenStrategy.js_selector = ".my-other-selector"
|
80
|
+
```
|
81
|
+
|
82
|
+
It supports all [CSS selectors](http://api.jquery.com/category/selectors/) that you can use in jQuery.
|
83
|
+
|
84
|
+
### Data attribute
|
85
|
+
|
86
|
+
The default trail data attribute for `<body>` and links is `data-trail` but you can change this in an initializer:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
Gretel::Trails::HiddenStrategy.data_attribute = "other-data-attribute"
|
90
|
+
```
|
91
|
+
|
92
|
+
That's it. :)
|
93
|
+
|
94
|
+
### Trail param
|
95
|
+
|
96
|
+
The trail param that's hidden from the user is `params[:trail]` by default. You can change this in an initializer:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Gretel.trail_param = :other_param
|
100
|
+
```
|
101
|
+
|
102
|
+
## Requirements
|
103
|
+
|
104
|
+
* Ruby >= 1.9.3 (1.9.2 may work)
|
105
|
+
* Rails >= 3.2.0
|
106
|
+
* Gretel >= 3.0.0
|
107
|
+
* jQuery
|
108
|
+
|
109
|
+
## Contributing
|
110
|
+
|
111
|
+
You are very welcome to contribute with bug fixes or new features. To contribute:
|
112
|
+
|
113
|
+
1. Fork the project
|
114
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
115
|
+
3. Commit your changes (`git commit -am 'Add feature'`)
|
116
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
117
|
+
5. Create new pull request
|
118
|
+
|
119
|
+
## Versioning
|
120
|
+
|
121
|
+
Follows [semantic versioning](http://semver.org/).
|
122
|
+
|
123
|
+
Copyright (c) 2013 [Lasse Bunk](http://lassebunk.dk), released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gretel/trails/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gretel-trails"
|
8
|
+
spec.version = Gretel::Trails::VERSION
|
9
|
+
spec.authors = ["Lasse Bunk"]
|
10
|
+
spec.email = ["lassebunk@gmail.com"]
|
11
|
+
spec.description = %q{Gretel::Trails is a collection of strategies for handling Gretel trails.}
|
12
|
+
spec.summary = %q{Collection of strategies for handling Gretel trails.}
|
13
|
+
spec.homepage = "https://github.com/lassebunk/gretel-trails"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "gretel", ">= 3.0.0.beta4"
|
21
|
+
spec.add_dependency "rails", ">= 3.2.0"
|
22
|
+
spec.add_development_dependency "rails", "~> 3.2.13"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "sqlite3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "capybara", "~> 2.1.0"
|
27
|
+
spec.add_development_dependency "capybara-webkit", "~> 1.0.0"
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
//= require gretel.trails.jsuri
|
2
|
+
|
3
|
+
<%
|
4
|
+
unless defined?(Gretel::Trails::HiddenStrategy)
|
5
|
+
raise "Gretel::Trails::HiddenStrategy` was not found. Please add `Gretel::Trails.strategy = :hidden` to an initializer."
|
6
|
+
end
|
7
|
+
%>
|
8
|
+
|
9
|
+
# Remove trail from querystring
|
10
|
+
removeTrailFromUrl = ->
|
11
|
+
if history.replaceState?
|
12
|
+
return if location.href.indexOf("<%= Gretel.trail_param %>=") is -1
|
13
|
+
uri = new Gretel.Trails.Uri(location.href)
|
14
|
+
history.replaceState history.state, document.title, uri.deleteQueryParam("<%= Gretel.trail_param %>")
|
15
|
+
|
16
|
+
# Remove trail on load
|
17
|
+
removeTrailFromUrl()
|
18
|
+
|
19
|
+
if Turbolinks?
|
20
|
+
# Remove trail after page change
|
21
|
+
$(document).on "page:change", -> removeTrailFromUrl()
|
22
|
+
|
23
|
+
# Add trails to querystring
|
24
|
+
$ ->
|
25
|
+
$("body").on "click", "[data-<%= Gretel::Trails::HiddenStrategy.data_attribute %>], <%= Gretel::Trails::HiddenStrategy.js_selector %>", ->
|
26
|
+
if trail = $(this).data("<%= Gretel::Trails::HiddenStrategy.data_attribute %>") || $("body").data("<%= Gretel::Trails::HiddenStrategy.data_attribute %>")
|
27
|
+
href = $(this).attr("href")
|
28
|
+
uri = new Gretel.Trails.Uri(href)
|
29
|
+
href = uri.deleteQueryParam("<%= Gretel.trail_param %>").addQueryParam("<%= Gretel.trail_param %>", trail)
|
30
|
+
$(this).attr("href", href)
|
31
|
+
else
|
32
|
+
console?.log "[Gretel] No `data-<%= Gretel::Trails::HiddenStrategy.data_attribute %>` was found on the <body> tag or the link you just clicked. Please set it using the `breadcrumb_trail` helper or see the Gretel::Trails readme for more info."
|
@@ -0,0 +1,370 @@
|
|
1
|
+
#!
|
2
|
+
# * jsUri v1.1.1 – ported to CoffeeScript with http://js2coffee.org/
|
3
|
+
# * https://github.com/derek-watson/jsUri
|
4
|
+
# *
|
5
|
+
# * Copyright 2011, Derek Watson
|
6
|
+
# * Released under the MIT license.
|
7
|
+
# * http://jquery.org/license
|
8
|
+
# *
|
9
|
+
# * Includes parseUri regular expressions
|
10
|
+
# * http://blog.stevenlevithan.com/archives/parseuri
|
11
|
+
# * Copyright 2007, Steven Levithan
|
12
|
+
# * Released under the MIT license.
|
13
|
+
# *
|
14
|
+
# * Date: Mon Nov 14 20:06:34 2011 -0800
|
15
|
+
#
|
16
|
+
window.Gretel or= {}
|
17
|
+
window.Gretel.Trails or= {}
|
18
|
+
|
19
|
+
window.Gretel.Trails.Query = (queryString) ->
|
20
|
+
|
21
|
+
# query string parsing, parameter manipulation and stringification
|
22
|
+
"use strict"
|
23
|
+
# parseQuery(q) parses the uri query string and returns a multi-dimensional array of the components
|
24
|
+
parseQuery = (q) ->
|
25
|
+
arr = []
|
26
|
+
i = undefined
|
27
|
+
ps = undefined
|
28
|
+
p = undefined
|
29
|
+
keyval = undefined
|
30
|
+
return arr if typeof (q) is "undefined" or q is null or q is ""
|
31
|
+
q = q.substring(1) if q.indexOf("?") is 0
|
32
|
+
ps = q.toString().split(/[&;]/)
|
33
|
+
i = 0
|
34
|
+
while i < ps.length
|
35
|
+
p = ps[i]
|
36
|
+
keyval = p.split("=")
|
37
|
+
arr.push [keyval[0], keyval[1]]
|
38
|
+
i++
|
39
|
+
arr
|
40
|
+
|
41
|
+
params = parseQuery(queryString)
|
42
|
+
|
43
|
+
# toString() returns a string representation of the internal state of the object
|
44
|
+
toString = ->
|
45
|
+
s = ""
|
46
|
+
i = undefined
|
47
|
+
param = undefined
|
48
|
+
i = 0
|
49
|
+
while i < params.length
|
50
|
+
param = params[i]
|
51
|
+
s += "&" if s.length > 0
|
52
|
+
s += param.join("=")
|
53
|
+
i++
|
54
|
+
(if s.length > 0 then "?" + s else s)
|
55
|
+
|
56
|
+
decode = (s) ->
|
57
|
+
s = decodeURIComponent(s)
|
58
|
+
s = s.replace("+", " ")
|
59
|
+
s
|
60
|
+
|
61
|
+
|
62
|
+
# getParamValues(key) returns the first query param value found for the key 'key'
|
63
|
+
getParamValue = (key) ->
|
64
|
+
param = undefined
|
65
|
+
i = undefined
|
66
|
+
i = 0
|
67
|
+
while i < params.length
|
68
|
+
param = params[i]
|
69
|
+
return param[1] if decode(key) is decode(param[0])
|
70
|
+
i++
|
71
|
+
|
72
|
+
|
73
|
+
# getParamValues(key) returns an array of query param values for the key 'key'
|
74
|
+
getParamValues = (key) ->
|
75
|
+
arr = []
|
76
|
+
i = undefined
|
77
|
+
param = undefined
|
78
|
+
i = 0
|
79
|
+
while i < params.length
|
80
|
+
param = params[i]
|
81
|
+
arr.push param[1] if decode(key) is decode(param[0])
|
82
|
+
i++
|
83
|
+
arr
|
84
|
+
|
85
|
+
|
86
|
+
# deleteParam(key) removes all instances of parameters named (key)
|
87
|
+
# deleteParam(key, val) removes all instances where the value matches (val)
|
88
|
+
deleteParam = (args...) ->
|
89
|
+
[key, val] = args
|
90
|
+
arr = []
|
91
|
+
i = undefined
|
92
|
+
param = undefined
|
93
|
+
keyMatchesFilter = undefined
|
94
|
+
valMatchesFilter = undefined
|
95
|
+
i = 0
|
96
|
+
while i < params.length
|
97
|
+
param = params[i]
|
98
|
+
keyMatchesFilter = decode(param[0]) is decode(key)
|
99
|
+
valMatchesFilter = decode(param[1]) is decode(val)
|
100
|
+
arr.push param if (args.length is 1 and not keyMatchesFilter) or (args.length is 2 and not keyMatchesFilter and not valMatchesFilter)
|
101
|
+
i++
|
102
|
+
params = arr
|
103
|
+
this
|
104
|
+
|
105
|
+
|
106
|
+
# addParam(key, val) Adds an element to the end of the list of query parameters
|
107
|
+
# addParam(key, val, index) adds the param at the specified position (index)
|
108
|
+
addParam = (args...) ->
|
109
|
+
[key, val, index] = args
|
110
|
+
if args.length is 3 and index isnt -1
|
111
|
+
index = Math.min(index, params.length)
|
112
|
+
params.splice index, 0, [key, val]
|
113
|
+
else params.push [key, val] if args.length > 0
|
114
|
+
this
|
115
|
+
|
116
|
+
|
117
|
+
# replaceParam(key, newVal) deletes all instances of params named (key) and replaces them with the new single value
|
118
|
+
# replaceParam(key, newVal, oldVal) deletes only instances of params named (key) with the value (val) and replaces them with the new single value
|
119
|
+
# this function attempts to preserve query param ordering
|
120
|
+
replaceParam = (args...) ->
|
121
|
+
[key, newVal, oldVal] = args
|
122
|
+
index = -1
|
123
|
+
i = undefined
|
124
|
+
param = undefined
|
125
|
+
if args.length is 3
|
126
|
+
i = 0
|
127
|
+
while i < params.length
|
128
|
+
param = params[i]
|
129
|
+
if decode(param[0]) is decode(key) and decodeURIComponent(param[1]) is decode(oldVal)
|
130
|
+
index = i
|
131
|
+
break
|
132
|
+
i++
|
133
|
+
deleteParam(key, oldVal).addParam key, newVal, index
|
134
|
+
else
|
135
|
+
i = 0
|
136
|
+
while i < params.length
|
137
|
+
param = params[i]
|
138
|
+
if decode(param[0]) is decode(key)
|
139
|
+
index = i
|
140
|
+
break
|
141
|
+
i++
|
142
|
+
deleteParam key
|
143
|
+
addParam key, newVal, index
|
144
|
+
this
|
145
|
+
|
146
|
+
|
147
|
+
# public api
|
148
|
+
getParamValue: getParamValue
|
149
|
+
getParamValues: getParamValues
|
150
|
+
deleteParam: deleteParam
|
151
|
+
addParam: addParam
|
152
|
+
replaceParam: replaceParam
|
153
|
+
toString: toString
|
154
|
+
|
155
|
+
window.Gretel.Trails.Uri = (uriString) ->
|
156
|
+
|
157
|
+
# uri string parsing, attribute manipulation and stringification
|
158
|
+
"use strict"
|
159
|
+
|
160
|
+
#global Query: true
|
161
|
+
|
162
|
+
#jslint regexp: false, plusplus: false
|
163
|
+
strictMode = false
|
164
|
+
|
165
|
+
# parseUri(str) parses the supplied uri and returns an object containing its components
|
166
|
+
parseUri = (str) ->
|
167
|
+
|
168
|
+
#jslint unparam: true
|
169
|
+
parsers =
|
170
|
+
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/
|
171
|
+
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
|
172
|
+
|
173
|
+
keys = ["source", "protocol", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor"]
|
174
|
+
q =
|
175
|
+
name: "queryKey"
|
176
|
+
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
|
177
|
+
|
178
|
+
m = parsers[(if strictMode then "strict" else "loose")].exec(str)
|
179
|
+
uri = {}
|
180
|
+
i = 14
|
181
|
+
uri[keys[i]] = m[i] or "" while i--
|
182
|
+
uri[q.name] = {}
|
183
|
+
uri[keys[12]].replace q.parser, ($0, $1, $2) ->
|
184
|
+
uri[q.name][$1] = $2 if $1
|
185
|
+
|
186
|
+
uri
|
187
|
+
|
188
|
+
uriParts = parseUri(uriString or "")
|
189
|
+
queryObj = new Gretel.Trails.Query(uriParts.query)
|
190
|
+
|
191
|
+
#
|
192
|
+
# Basic get/set functions for all properties
|
193
|
+
#
|
194
|
+
protocol = (val) ->
|
195
|
+
uriParts.protocol = val if typeof val isnt "undefined"
|
196
|
+
uriParts.protocol
|
197
|
+
|
198
|
+
hasAuthorityPrefixUserPref = null
|
199
|
+
|
200
|
+
# hasAuthorityPrefix: if there is no protocol, the leading // can be enabled or disabled
|
201
|
+
hasAuthorityPrefix = (val) ->
|
202
|
+
hasAuthorityPrefixUserPref = val if typeof val isnt "undefined"
|
203
|
+
if hasAuthorityPrefixUserPref is null
|
204
|
+
uriParts.source.indexOf("//") isnt -1
|
205
|
+
else
|
206
|
+
hasAuthorityPrefixUserPref
|
207
|
+
|
208
|
+
userInfo = (val) ->
|
209
|
+
uriParts.userInfo = val if typeof val isnt "undefined"
|
210
|
+
uriParts.userInfo
|
211
|
+
|
212
|
+
host = (val) ->
|
213
|
+
uriParts.host = val if typeof val isnt "undefined"
|
214
|
+
uriParts.host
|
215
|
+
|
216
|
+
port = (val) ->
|
217
|
+
uriParts.port = val if typeof val isnt "undefined"
|
218
|
+
uriParts.port
|
219
|
+
|
220
|
+
path = (val) ->
|
221
|
+
uriParts.path = val if typeof val isnt "undefined"
|
222
|
+
uriParts.path
|
223
|
+
|
224
|
+
query = (val) ->
|
225
|
+
queryObj = new Gretel.Trails.Query(val) if typeof val isnt "undefined"
|
226
|
+
queryObj
|
227
|
+
|
228
|
+
anchor = (val) ->
|
229
|
+
uriParts.anchor = val if typeof val isnt "undefined"
|
230
|
+
uriParts.anchor
|
231
|
+
|
232
|
+
|
233
|
+
#
|
234
|
+
# Fluent setters for Uri uri properties
|
235
|
+
#
|
236
|
+
setProtocol = (val) ->
|
237
|
+
protocol val
|
238
|
+
this
|
239
|
+
|
240
|
+
setHasAuthorityPrefix = (val) ->
|
241
|
+
hasAuthorityPrefix val
|
242
|
+
this
|
243
|
+
|
244
|
+
setUserInfo = (val) ->
|
245
|
+
userInfo val
|
246
|
+
this
|
247
|
+
|
248
|
+
setHost = (val) ->
|
249
|
+
host val
|
250
|
+
this
|
251
|
+
|
252
|
+
setPort = (val) ->
|
253
|
+
port val
|
254
|
+
this
|
255
|
+
|
256
|
+
setPath = (val) ->
|
257
|
+
path val
|
258
|
+
this
|
259
|
+
|
260
|
+
setQuery = (val) ->
|
261
|
+
query val
|
262
|
+
this
|
263
|
+
|
264
|
+
setAnchor = (val) ->
|
265
|
+
anchor val
|
266
|
+
this
|
267
|
+
|
268
|
+
|
269
|
+
#
|
270
|
+
# Query method wrappers
|
271
|
+
#
|
272
|
+
getQueryParamValue = (key) ->
|
273
|
+
query().getParamValue key
|
274
|
+
|
275
|
+
getQueryParamValues = (key) ->
|
276
|
+
query().getParamValues key
|
277
|
+
|
278
|
+
deleteQueryParam = (args...) ->
|
279
|
+
[key, val] = args
|
280
|
+
if args.length is 2
|
281
|
+
query().deleteParam key, val
|
282
|
+
else
|
283
|
+
query().deleteParam key
|
284
|
+
this
|
285
|
+
|
286
|
+
addQueryParam = (args...) ->
|
287
|
+
[key, val, index] = args
|
288
|
+
if args.length is 3
|
289
|
+
query().addParam key, val, index
|
290
|
+
else
|
291
|
+
query().addParam key, val
|
292
|
+
this
|
293
|
+
|
294
|
+
replaceQueryParam = (args...) ->
|
295
|
+
[key, newVal, oldVal] = args
|
296
|
+
if args.length is 3
|
297
|
+
query().replaceParam key, newVal, oldVal
|
298
|
+
else
|
299
|
+
query().replaceParam key, newVal
|
300
|
+
this
|
301
|
+
|
302
|
+
|
303
|
+
#
|
304
|
+
# Serialization
|
305
|
+
#
|
306
|
+
|
307
|
+
# toString() stringifies the current state of the uri
|
308
|
+
toString = ->
|
309
|
+
s = ""
|
310
|
+
is_ = (s) ->
|
311
|
+
s isnt null and s isnt ""
|
312
|
+
|
313
|
+
if is_(protocol())
|
314
|
+
s += protocol()
|
315
|
+
s += ":" if protocol().indexOf(":") isnt protocol().length - 1
|
316
|
+
s += "//"
|
317
|
+
else
|
318
|
+
s += "//" if hasAuthorityPrefix() and is_(host())
|
319
|
+
if is_(userInfo()) and is_(host())
|
320
|
+
s += userInfo()
|
321
|
+
s += "@" if userInfo().indexOf("@") isnt userInfo().length - 1
|
322
|
+
if is_(host())
|
323
|
+
s += host()
|
324
|
+
s += ":" + port() if is_(port())
|
325
|
+
if is_(path())
|
326
|
+
s += path()
|
327
|
+
else
|
328
|
+
s += "/" if is_(host()) and (is_(query().toString()) or is_(anchor()))
|
329
|
+
if is_(query().toString())
|
330
|
+
s += "?" if query().toString().indexOf("?") isnt 0
|
331
|
+
s += query().toString()
|
332
|
+
if is_(anchor())
|
333
|
+
s += "#" if anchor().indexOf("#") isnt 0
|
334
|
+
s += anchor()
|
335
|
+
s
|
336
|
+
|
337
|
+
|
338
|
+
#
|
339
|
+
# Cloning
|
340
|
+
#
|
341
|
+
|
342
|
+
# clone() returns a new, identical Uri instance
|
343
|
+
clone = ->
|
344
|
+
new Uri(toString())
|
345
|
+
|
346
|
+
|
347
|
+
# public api
|
348
|
+
protocol: protocol
|
349
|
+
hasAuthorityPrefix: hasAuthorityPrefix
|
350
|
+
userInfo: userInfo
|
351
|
+
host: host
|
352
|
+
port: port
|
353
|
+
path: path
|
354
|
+
query: query
|
355
|
+
anchor: anchor
|
356
|
+
setProtocol: setProtocol
|
357
|
+
setHasAuthorityPrefix: setHasAuthorityPrefix
|
358
|
+
setUserInfo: setUserInfo
|
359
|
+
setHost: setHost
|
360
|
+
setPort: setPort
|
361
|
+
setPath: setPath
|
362
|
+
setQuery: setQuery
|
363
|
+
setAnchor: setAnchor
|
364
|
+
getQueryParamValue: getQueryParamValue
|
365
|
+
getQueryParamValues: getQueryParamValues
|
366
|
+
deleteQueryParam: deleteQueryParam
|
367
|
+
addQueryParam: addQueryParam
|
368
|
+
replaceQueryParam: replaceQueryParam
|
369
|
+
toString: toString
|
370
|
+
clone: clone
|