praxis-docs-search 0.1.0
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 +0 -0
- data/Gemfile +3 -0
- data/demo.gif +0 -0
- data/lib/api_browser/bower.json +5 -0
- data/lib/api_browser/praxis-docs-search.scss +23 -0
- data/lib/api_browser/search.js +218 -0
- data/lib/api_browser/views/navbar.html +10 -0
- data/lib/api_browser/views/search_form.html +8 -0
- data/lib/api_browser/views/search_results.html +5 -0
- data/lib/praxis-docs-search.rb +12 -0
- data/lib/praxis-docs-search/version.rb +3 -0
- data/praxis-docs-search.gemspec +26 -0
- data/readme.md +36 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3b87c5a598e8934d2adc02815102130441fcca42
|
4
|
+
data.tar.gz: 883f4fef35d32169517eb3e5a1c8643681a3ed07
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5d7db10a0cf2fbc703864f59d91434c5d04f1677c1469dffe3555a3de302b65dedad7e316c7a300f72170bf4c57956484f2d9afed1802ac4c91927248801d834
|
7
|
+
data.tar.gz: a3c34a641de45578a9e8f1d327105bd84ea8b9ffe62f3dfd46d747b1b7860750c8373d1b528b41c8c4f0127e5a65533da8a9b026d35c47ba37e10ee9dc26d9ff
|
data/.gitignore
ADDED
File without changes
|
data/Gemfile
ADDED
data/demo.gif
ADDED
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
.praxis-docs-search {
|
2
|
+
input {
|
3
|
+
width: 280px;
|
4
|
+
}
|
5
|
+
.popover-content {
|
6
|
+
padding: 0;
|
7
|
+
.list-group-item {
|
8
|
+
width: 270px;
|
9
|
+
margin-right: 20px;
|
10
|
+
border-left: none;
|
11
|
+
border-right: none;
|
12
|
+
&:first-child {
|
13
|
+
border-top: none;
|
14
|
+
}
|
15
|
+
.result-type {
|
16
|
+
color: $text-muted;
|
17
|
+
position: absolute;
|
18
|
+
right: 12px;
|
19
|
+
bottom: 11px;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,218 @@
|
|
1
|
+
app.value('pathIndex', {});
|
2
|
+
app.provider('praxisDocsSearch', function() {
|
3
|
+
function localSearchFactory(Documentation, $timeout, $q, $state, pathIndex) {
|
4
|
+
'ngInject';
|
5
|
+
console.log('Using Local Search Index');
|
6
|
+
|
7
|
+
// Create the lunr index
|
8
|
+
var index = lunr(function() {
|
9
|
+
this.ref('path');
|
10
|
+
this.field('titleWords', {boost: 50});
|
11
|
+
this.field('members', {boost: 40});
|
12
|
+
this.field('keywords', {boost: 20});
|
13
|
+
this.field('parent', {boost: 30});
|
14
|
+
});
|
15
|
+
|
16
|
+
// Delay building the index by loading the data asynchronously
|
17
|
+
var indexReadyPromise = Documentation.versions().then(function(versions) {
|
18
|
+
// Delay building the index for 500ms to allow the page to render
|
19
|
+
return $timeout(function() {
|
20
|
+
$q.all(versions.map(function (version) {
|
21
|
+
return Documentation.items(version).then(function(items) {
|
22
|
+
function extractMembers(thing) {
|
23
|
+
return _.map(_.get(thing, 'type.attributes', {}), function(v, k) {
|
24
|
+
var res = [k];
|
25
|
+
if (v.description) {
|
26
|
+
res.push(v.description);
|
27
|
+
}
|
28
|
+
if (_.get(v, 'type.attributes')) {
|
29
|
+
res = res.concat(extractMembers(v));
|
30
|
+
}
|
31
|
+
return res.join(' ');
|
32
|
+
}).join(' ');
|
33
|
+
}
|
34
|
+
function extractActionMembers(action) {
|
35
|
+
var headers = _.keys(_.get(action, 'headers.type.attributes', {})).join(' '),
|
36
|
+
params = extractMembers(_.get(action, 'params', {})),
|
37
|
+
payload = extractMembers(_.get(action, 'payload', {})),
|
38
|
+
responses = _.map(_.get(action, 'responses'), function(v, k) { return k + ' ' + v.description; }).join(' '),
|
39
|
+
urls = _.map(_.get(action, 'urls'), 'path').join(' ');
|
40
|
+
return [headers, params, payload, responses, urls].join(' ');
|
41
|
+
}
|
42
|
+
function extractTypeMembers(type) {
|
43
|
+
return extractMembers({type: type});
|
44
|
+
}
|
45
|
+
_.each(items.resources, function(resource, id) {
|
46
|
+
var href = $state.href('root.controller', {version: version, controller: id});
|
47
|
+
index.add({
|
48
|
+
path: href,
|
49
|
+
titleWords: resource.display_name,
|
50
|
+
members: _.map(resource.actions, 'name').join(' ') + ' ' + _.get(resource.media_type, 'name') + ' ' + _.get(resource, 'traits', []).join(' '),
|
51
|
+
keywords: resource.description + ' ' + version,
|
52
|
+
parent: resource.parent ? items.resources[resource.parent].display_name : ''
|
53
|
+
});
|
54
|
+
pathIndex[href] = {
|
55
|
+
type: 'resource',
|
56
|
+
name: resource.display_name,
|
57
|
+
id: id,
|
58
|
+
version: version
|
59
|
+
};
|
60
|
+
|
61
|
+
_.each(resource.actions, function(action) {
|
62
|
+
var href = $state.href('root.action', {version: version, controller: id, action: action.name});
|
63
|
+
index.add({
|
64
|
+
path: $state.href('root.action', {version: version, controller: id, action: action.name}),
|
65
|
+
titleWords: action.name,
|
66
|
+
members: extractActionMembers(action),
|
67
|
+
keywords: action.description + ' ' + version,
|
68
|
+
parent: resource.display_name
|
69
|
+
});
|
70
|
+
|
71
|
+
pathIndex[href] = {
|
72
|
+
type: 'action',
|
73
|
+
name: resource.display_name + ' » ' + action.name,
|
74
|
+
id: action.name,
|
75
|
+
version: version,
|
76
|
+
resource: id
|
77
|
+
};
|
78
|
+
});
|
79
|
+
});
|
80
|
+
_.each(items.schemas, function(type) {
|
81
|
+
var href = $state.href('root.type', {version: version, type: type.id});
|
82
|
+
index.add({
|
83
|
+
path: href,
|
84
|
+
titleWords: type.display_name,
|
85
|
+
members: extractTypeMembers(type),
|
86
|
+
keywords: type.description + ' ' + version
|
87
|
+
});
|
88
|
+
pathIndex[href] = {
|
89
|
+
type: 'schema',
|
90
|
+
name: type.display_name,
|
91
|
+
id: type.id,
|
92
|
+
version: version
|
93
|
+
};
|
94
|
+
});
|
95
|
+
|
96
|
+
_.each(items.traits, function(trait, id) {
|
97
|
+
var href = $state.href('root.trait', {version: version, trait: id});
|
98
|
+
index.add({
|
99
|
+
path: href,
|
100
|
+
titleWords: id,
|
101
|
+
members: extractTypeMembers(trait),
|
102
|
+
keywords: trait.description + ' ' + version
|
103
|
+
});
|
104
|
+
pathIndex[href] = {
|
105
|
+
type: 'trait',
|
106
|
+
name: id,
|
107
|
+
id: id,
|
108
|
+
version: version
|
109
|
+
};
|
110
|
+
});
|
111
|
+
});
|
112
|
+
}));
|
113
|
+
}, 500);
|
114
|
+
});
|
115
|
+
|
116
|
+
// The actual service is a function that takes a query string and
|
117
|
+
// returns a promise to the search results
|
118
|
+
// (In this case we just resolve the promise immediately as it is not
|
119
|
+
// inherently an async process)
|
120
|
+
return function(q) {
|
121
|
+
return indexReadyPromise.then(function() {
|
122
|
+
return index.search(q);
|
123
|
+
});
|
124
|
+
};
|
125
|
+
}
|
126
|
+
|
127
|
+
return {
|
128
|
+
$get:localSearchFactory //window.Worker ? webWorkerSearchFactory : localSearchFactory
|
129
|
+
};
|
130
|
+
});
|
131
|
+
|
132
|
+
app.controller('DocsSearchCtrl', function($scope, $location, praxisDocsSearch, pathIndex, $timeout) {
|
133
|
+
|
134
|
+
function clearResults() {
|
135
|
+
$scope.results = [];
|
136
|
+
$scope.showResults = false;
|
137
|
+
$scope.colClassName = null;
|
138
|
+
$scope.hasResults = false;
|
139
|
+
}
|
140
|
+
|
141
|
+
clearResults();
|
142
|
+
$scope.focus = false;
|
143
|
+
|
144
|
+
$scope.search = function(q) {
|
145
|
+
var MIN_SEARCH_LENGTH = 2;
|
146
|
+
if(q.length >= MIN_SEARCH_LENGTH) {
|
147
|
+
praxisDocsSearch(q).then(function(hits) {
|
148
|
+
$scope.hasResults = hits.length > 0;
|
149
|
+
$scope.results = _.map(_.take(hits, 10), function(hit) {
|
150
|
+
var result = pathIndex[hit.ref];
|
151
|
+
result.path = hit.ref;
|
152
|
+
return result;
|
153
|
+
});
|
154
|
+
});
|
155
|
+
} else {
|
156
|
+
clearResults();
|
157
|
+
}
|
158
|
+
if(!$scope.$$phase) $scope.$apply();
|
159
|
+
};
|
160
|
+
|
161
|
+
$scope.submit = function() {
|
162
|
+
var result;
|
163
|
+
for(var i in $scope.results) {
|
164
|
+
result = $scope.results[i];
|
165
|
+
if(result) {
|
166
|
+
break;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
if(result) {
|
170
|
+
$location.path(result.path);
|
171
|
+
$scope.hideResults();
|
172
|
+
}
|
173
|
+
};
|
174
|
+
|
175
|
+
$scope.hideResults = function() {
|
176
|
+
clearResults();
|
177
|
+
$scope.q = '';
|
178
|
+
};
|
179
|
+
|
180
|
+
$scope.goToResult = function(result) {
|
181
|
+
var str = $scope.q;
|
182
|
+
$scope.hideResults();
|
183
|
+
$timeout(function() {
|
184
|
+
if (window.find) { // Firefox, Google Chrome, Safari
|
185
|
+
// if some content is selected, the start position of the search
|
186
|
+
// will be the end position of the selection
|
187
|
+
window.find(str, false, false, true);
|
188
|
+
} else {
|
189
|
+
if (document.selection && document.selection.createRange) { // Internet Explorer, Opera before version 10.5
|
190
|
+
var textRange = document.selection.createRange ();
|
191
|
+
if (textRange.findText) { // Internet Explorer
|
192
|
+
// if some content is selected, the start position of the search
|
193
|
+
// will be the position after the start position of the selection
|
194
|
+
if (textRange.text.length > 0) {
|
195
|
+
textRange.collapse(true);
|
196
|
+
textRange.mov("character", 1);
|
197
|
+
}
|
198
|
+
if (textRange.findText(str)) {
|
199
|
+
textRange.select();
|
200
|
+
}
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}, 200);
|
205
|
+
};
|
206
|
+
|
207
|
+
$scope.$watch('focus && hasResults', function(val) {
|
208
|
+
$scope.showResults = val;
|
209
|
+
});
|
210
|
+
});
|
211
|
+
|
212
|
+
app.directive('searchForm', function() {
|
213
|
+
return {
|
214
|
+
restrict: 'E',
|
215
|
+
controller: 'DocsSearchCtrl',
|
216
|
+
templateUrl: 'views/search_form.html'
|
217
|
+
};
|
218
|
+
});
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="header">
|
2
|
+
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
|
3
|
+
<div class="container">
|
4
|
+
<div class="navbar-header">
|
5
|
+
<a class="navbar-brand" href="#/">{{:: title}}</a>
|
6
|
+
</div>
|
7
|
+
<search-form class="navbar-form navbar-right"></search-form>
|
8
|
+
</div>
|
9
|
+
</div>
|
10
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<form ng-controller="DocsSearchCtrl" class="praxis-docs-search" role="search" ng-class="{focus:focus}" ng-submit="submit()">
|
2
|
+
<div class="form-group">
|
3
|
+
<input type="search" class="form-control" placeholder="Search" ng-focus="focus=true"
|
4
|
+
ng-blur="focus=false"
|
5
|
+
ng-change="search(q)"
|
6
|
+
ng-model="q" autocomplete="off" popover-template="'views/search_results.html'" popover-is-open="showResults" popover-placement="bottom" popover-trigger="none" />
|
7
|
+
</div>
|
8
|
+
</form>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'praxis-docs-search/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "praxis-docs-search"
|
8
|
+
spec.version = PraxisDocsSearch::VERSION
|
9
|
+
spec.authors = ["Jakub Hampl"]
|
10
|
+
spec.summary = %q{Doc Browser Search plugin for Praxis.}
|
11
|
+
spec.email = ["jakub.hampl@rightscale.com"]
|
12
|
+
|
13
|
+
spec.homepage = "https://github.com/rightscale/praxis-docs-search"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">=2.1"
|
16
|
+
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'praxis', [">= 0.18"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
24
|
+
spec.add_development_dependency "rake", "~> 0"
|
25
|
+
|
26
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Praxis Docs Search
|
2
|
+
|
3
|
+
This plugin for Praxis adds the capability to search the doc browser.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
Add this to your gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'praxis-docs-search'
|
13
|
+
```
|
14
|
+
|
15
|
+
In your `config.ru` add it to the Praxis Bootloader:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
application.bootloader.use Praxis::DocsSearch
|
19
|
+
```
|
20
|
+
|
21
|
+
Finally if you would like to use the default styling, add this to your `docs/styles.scss`:
|
22
|
+
|
23
|
+
```scss
|
24
|
+
@import "praxis-docs-search.scss";
|
25
|
+
```
|
26
|
+
|
27
|
+
If you are using your own navbar, you can include the search form anywhere by using
|
28
|
+
the `<search-form></search-form>` element in a custom template.
|
29
|
+
|
30
|
+
## Authors
|
31
|
+
|
32
|
+
Jakub Hampl @gampleman
|
33
|
+
|
34
|
+
MIT LICENSE
|
35
|
+
|
36
|
+
(c) RightScale, Inc. 2015
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: praxis-docs-search
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jakub Hampl
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: praxis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.18'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.18'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- jakub.hampl@rightscale.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- Gemfile
|
64
|
+
- demo.gif
|
65
|
+
- lib/api_browser/bower.json
|
66
|
+
- lib/api_browser/praxis-docs-search.scss
|
67
|
+
- lib/api_browser/search.js
|
68
|
+
- lib/api_browser/views/navbar.html
|
69
|
+
- lib/api_browser/views/search_form.html
|
70
|
+
- lib/api_browser/views/search_results.html
|
71
|
+
- lib/praxis-docs-search.rb
|
72
|
+
- lib/praxis-docs-search/version.rb
|
73
|
+
- praxis-docs-search.gemspec
|
74
|
+
- readme.md
|
75
|
+
homepage: https://github.com/rightscale/praxis-docs-search
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '2.1'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.2.2
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: Doc Browser Search plugin for Praxis.
|
99
|
+
test_files: []
|
100
|
+
has_rdoc:
|