gretel-trails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://secure.travis-ci.org/lassebunk/gretel-trails.png)](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
|