Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bdac9dd

Browse files
committed
feat(main): Add main wrapper
1 parent d65cb99 commit bdac9dd

File tree

8 files changed

+180
-7375
lines changed

8 files changed

+180
-7375
lines changed

dev/app.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import documentationSearch from '../index.js';
22

33
documentationSearch({
4-
apiKey: 'aaa',
5-
indexName: 'bbb',
6-
inputSelector: 'ccc'
4+
apiKey: '7cad300559017ed67717c9c6cba2666d',
5+
indexName: 'stripe',
6+
inputSelector: '#search-input'
77
});

index.js

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1 @@
1-
/* global google */
2-
3-
function documentationSearch({
4-
apiKey,
5-
indexName,
6-
inputSelector
7-
}) {
8-
console.info(apiKey, indexName, inputSelector);
9-
}
10-
11-
export default documentationSearch;
1+
module.exports = require('./src/lib/main.js');

npm-shrinkwrap.json

Lines changed: 0 additions & 7360 deletions
This file was deleted.

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@
3636
},
3737
"peerDependencies": {},
3838
"dependencies": {
39-
"lodash": "^3.10.1"
39+
"algoliasearch": "^3.9.2",
40+
"autocomplete.js": "^0.13.0",
41+
"hogan.js": "^3.0.2",
42+
"lodash": "^3.10.1",
43+
"npm-zepto": "^1.1.7",
44+
"to-factory": "^1.0.0"
4045
}
4146
}

src/lib/DocumentationSearch.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import Hogan from 'hogan.js';
2+
import algoliasearch from 'algoliasearch';
3+
import autocomplete from 'autocomplete.js';
4+
import groupBy from 'lodash/collection/groupBy';
5+
import templates from './templates.js';
6+
import utils from './utils.js';
7+
import $ from 'npm-zepto';
8+
9+
/**
10+
* Adds an autocomplete dropdown to an input fields
11+
* @function documentationSearch
12+
* @param {string} options.apiKey Read-only API key
13+
* @param {string} options.indexName Name of the index to target
14+
* @param {string} options.inputSelector CSS selector that targets the input
15+
* @param {Object} [options.algoliaOptions] Options to pass the underlying Algolia client
16+
* @param {Object} [options.autocompleteOptions] Options to pass to the underlying autocomplete instance
17+
* @return {Object}
18+
*/
19+
const usage = `Usage:
20+
documentationSearch({
21+
apiKey,
22+
indexName,
23+
inputSelector,
24+
[ options.{hint,debug} ]
25+
})`;
26+
class DocumentationSearch {
27+
constructor({
28+
apiKey,
29+
indexName,
30+
inputSelector,
31+
algoliaOptions = {
32+
hitsPerPage: 5
33+
},
34+
autocompleteOptions = {
35+
debug: true,
36+
hint: false
37+
}
38+
}) {
39+
this.checkArguments({apiKey, indexName, inputSelector, algoliaOptions, autocompleteOptions});
40+
41+
this.client = algoliasearch('BH4D9OD16A', this.apiKey);
42+
this.autocomplete = autocomplete(this.input, autocompleteOptions, [{
43+
source: this.getSource(),
44+
templates: {
45+
suggestion: this.getSuggestionTemplate()
46+
}
47+
}]);
48+
this.autocomplete.on('autocomplete:selected', this.handleSelected);
49+
}
50+
51+
// TEST:
52+
// - Usage error if no apiKey or no indexName
53+
// - Error if nothing matches
54+
// - Error if matches are not input
55+
// - apiKey nad indexName are set
56+
// - input is set to the Zepto-wrapped inputSelector
57+
checkArguments(args) {
58+
if (!args.apiKey || !args.indexName) {
59+
throw new Error(usage);
60+
}
61+
62+
const input = $(args.inputSelector).filter('input');
63+
if (input.length === 0) {
64+
throw new Error(`Error: No input element in the page matches ${args.inputSelector}`);
65+
}
66+
67+
this.apiKey = args.apiKey;
68+
this.indexName = args.indexName;
69+
this.input = input;
70+
this.algoliaOptions = args.algoliaOptions;
71+
this.autocompleteOptions = args.autocompleteOptions;
72+
}
73+
74+
// Returns a `source` method to be used by `autocomplete`. This will query the
75+
// Algolia index.
76+
getSource() {
77+
return (query, callback) => {
78+
this.client.search([{
79+
indexName: this.indexName,
80+
query: query,
81+
params: this.algoliaOptions
82+
}]).then((data) => {
83+
callback(this.formatHits(data.results[0].hits));
84+
});
85+
};
86+
}
87+
88+
// Given a list of hits returned by the API, will reformat them to be used in
89+
// a Hogan template
90+
formatHits(hits) {
91+
// Group hits by category / subcategory
92+
var groupedHits = groupBy(hits, 'category');
93+
groupedHits.each((list, category) => {
94+
var groupedHitsBySubCategory = groupBy(list, 'subcategory');
95+
var flattenedHits = utils.flattenObject(groupedHitsBySubCategory, 'isSubcategoryHeader');
96+
groupedHits[category] = flattenedHits;
97+
});
98+
groupedHits = utils.flattenObject(groupedHits, 'isCategoryHeader');
99+
100+
// Translate hits into smaller objects to be send to the template
101+
return groupedHits.map((hit) => {
102+
return {
103+
isCategoryHeader: hit.isCategoryHeader,
104+
isSubcategoryHeader: hit.isSubcategoryHeader,
105+
category: hit._highlightResult.category ? hit._highlightResult.category.value : hit.category,
106+
subcategory: hit._highlightResult.subcategory ? hit._highlightResult.subcategory.value : hit.category,
107+
title: hit._highlightResult.display_title ? hit._highlightResult.display_title.value : hit.display_title,
108+
text: hit._snippetResult ? hit._snippetResult.text.value : hit.text,
109+
url: hit.url
110+
};
111+
});
112+
}
113+
114+
getSuggestionTemplate() {
115+
const template = Hogan.compile(templates.suggestion);
116+
return (suggestion) => {
117+
return template.render(suggestion);
118+
};
119+
}
120+
121+
handleSelected(event, suggestion) {
122+
this.autocomplete.autocomplete.setVal('');
123+
window.location.href = suggestion.url;
124+
}
125+
}
126+
127+
export default DocumentationSearch;
128+
129+

src/lib/main.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import toFactory from 'to-factory';
2+
import DocumentationSearch from './DocumentationSearch';
3+
4+
let documentationSearch = toFactory(DocumentationSearch);
5+
6+
export default documentationSearch;

src/lib/templates.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
let prefix = 'documentationsearch--suggestion';
2+
3+
let templates = {
4+
suggestion: `
5+
<div class="${prefix} {{#isCategoryHeader}}${prefix}__main{{/isCategoryHeader}} {{#isSubcategoryHeader}}${prefix}__secondary{{/isSubcategoryHeader}}">
6+
<div class="${prefix}--category-header">{{{category}}}</div>
7+
<div class="${prefix}--wrapper">
8+
<div class="${prefix}--subcategory">{{{subcategory}}}</div>
9+
<div class="${prefix}--content">
10+
<div class="${prefix}--subcategory">{{{subcategory}}}</div>
11+
<div class="${prefix}--title">{{{title}}}</div>
12+
<div class="${prefix}--text">{{{text}}}</div>
13+
</div>
14+
</div>
15+
</div>
16+
`
17+
};
18+
19+
export default templates;
20+

src/lib/utils.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import values from 'lodash/object/values';
2+
import flatten from 'lodash/array/flatten';
3+
4+
let utils = {
5+
// Flatten all values into one array, marking the first element with
6+
// `flagName`
7+
flattenObject(o, flagName) {
8+
values(o).map((value) => {
9+
value[0][flagName] = true;
10+
});
11+
return flatten(values);
12+
}
13+
};
14+
15+
export default utils;

0 commit comments

Comments
 (0)