chore(test+lint): fixed tests & linting (#134)
This commit is contained in:
parent
254903ab7a
commit
6ba59acc4e
8 changed files with 91 additions and 58 deletions
|
|
@ -1,3 +1,4 @@
|
|||
coverage/
|
||||
dist/
|
||||
docs/
|
||||
dist-es5-module/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ you need to integrate your new search into your website.
|
|||
2. We'll configure your search experience,
|
||||
3. You'll need to add a bit of JavaScript and CSS code to your website.
|
||||
|
||||
If you prefer to DIY, you can run the [scraper][28] in your own infra.
|
||||
|
||||
## Setup
|
||||
|
||||
Once we've crawled your documentation website we'll send you the credentials you
|
||||
|
|
@ -39,7 +41,7 @@ docsearch({
|
|||
|
||||
## Customization
|
||||
|
||||
The default colorscheme is blue and gray:
|
||||
The default colorscheme is white and gray:
|
||||
|
||||
![Default colorscheme][17]
|
||||
|
||||
|
|
@ -103,6 +105,7 @@ You can regenerate the whole final `css` file from those `scss` files by running
|
|||
All you have to do now is change the `link` tag that was loading the default
|
||||
styling from our CDN, to one that is loading your newly compiled file.
|
||||
|
||||
|
||||
## Custom options
|
||||
|
||||
DocSearch is a wrapper around the [autocomplete.js][20] library that gets its
|
||||
|
|
@ -137,6 +140,19 @@ search.autocomplete.on('autocomplete:opened', function(e) {
|
|||
});
|
||||
```
|
||||
|
||||
We already bind the autocomplete:selected event inside the docsearch.
|
||||
If you want to replace the default behavior you can pass the handleSelected option
|
||||
|
||||
```javascript
|
||||
var search = docsearch({
|
||||
apiKey: '<API_KEY>',
|
||||
indexName: '<INDEX_NAME>',
|
||||
inputSelector: '<YOUR_INPUT_DOM_SELECTOR>',
|
||||
handleSelected: function (input, event, suggestion) {
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Algolia options
|
||||
|
||||
You can also pass any specific option to the Algolia API to change the way
|
||||
|
|
@ -163,7 +179,7 @@ You will find all Algolia API options in its [own documentation][23]
|
|||
[4]: https://img.shields.io/coveralls/algolia/docsearch/master.svg?style=flat-square
|
||||
[5]: http://img.shields.io/badge/license-MIT-green.svg?style=flat-square
|
||||
[6]: https://img.shields.io/npm/dm/docsearch.js.svg?style=flat-square
|
||||
[7]: ./docs/img/showcase/example-eslint.gif
|
||||
[7]: ./docs/img/showcase/example-apiary.gif
|
||||
[8]: #introduction
|
||||
[9]: #setup
|
||||
[10]: #customization
|
||||
|
|
@ -173,7 +189,7 @@ You will find all Algolia API options in its [own documentation][23]
|
|||
[14]: #documentation-website
|
||||
[15]: #macos
|
||||
[16]: https://community.algolia.com/docsearch/
|
||||
[17]: https://community.algolia.com/docsearch/img/default-colorscheme.png
|
||||
[17]: ./docs/img/default-colorscheme.png
|
||||
[18]: https://github.com/algolia/docsearch/blob/master/src/styles/_variables.scss
|
||||
[19]: https://github.com/algolia/docsearch/blob/master/src/styles/main.scss
|
||||
[20]: https://github.com/algolia/autocomplete.js
|
||||
|
|
@ -184,4 +200,5 @@ You will find all Algolia API options in its [own documentation][23]
|
|||
[25]: https://jekyllrb.com/
|
||||
[26]: https://www.ruby-lang.org/en/
|
||||
[27]: http://bundler.io/
|
||||
[28]: https://github.com/algolia/docsearch-scraper
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import autocomplete from 'autocomplete.js';
|
|||
import templates from './templates.js';
|
||||
import utils from './utils.js';
|
||||
import version from './version.js';
|
||||
import $ from 'autocomplete.js/zepto.js';
|
||||
import $ from './zepto.js';
|
||||
|
||||
/**
|
||||
* Adds an autocomplete dropdown to an input field
|
||||
|
|
@ -46,14 +46,16 @@ class DocSearch {
|
|||
enhancedSearchInput = false,
|
||||
layout = 'collumns'
|
||||
}) {
|
||||
DocSearch.checkArguments({apiKey, indexName, inputSelector, debug, algoliaOptions, autocompleteOptions, transformData, handleSelected, enhancedSearchInput, layout});
|
||||
DocSearch.checkArguments({apiKey, indexName, inputSelector, debug, algoliaOptions,
|
||||
autocompleteOptions, transformData, handleSelected, enhancedSearchInput, layout});
|
||||
|
||||
this.apiKey = apiKey;
|
||||
this.appId = appId;
|
||||
this.indexName = indexName;
|
||||
this.input = DocSearch.getInputFromSelector(inputSelector);
|
||||
this.algoliaOptions = {hitsPerPage: 5, ...algoliaOptions};
|
||||
let autocompleteOptionsDebug = autocompleteOptions && autocompleteOptions.debug ? autocompleteOptions.debug: false;
|
||||
const autocompleteOptionsDebug = autocompleteOptions && autocompleteOptions.debug ?
|
||||
autocompleteOptions.debug : false;
|
||||
autocompleteOptions.debug = debug || autocompleteOptionsDebug;
|
||||
this.autocompleteOptions = autocompleteOptions;
|
||||
this.autocompleteOptions.cssClasses = {
|
||||
|
|
@ -68,7 +70,7 @@ class DocSearch {
|
|||
this.client.addAlgoliaAgent('docsearch.js ' + version);
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
DocSearch.injectSearchBox(this.input, this);
|
||||
DocSearch.injectSearchBox(this.input);
|
||||
this.input = DocSearch.getInputFromSelector('#docsearch');
|
||||
}
|
||||
|
||||
|
|
@ -83,14 +85,14 @@ class DocSearch {
|
|||
this.autocomplete.on(
|
||||
'autocomplete:selected',
|
||||
handleSelected.bind(null, this.autocomplete.autocomplete)
|
||||
)
|
||||
);
|
||||
this.autocomplete.on(
|
||||
'autocomplete:shown',
|
||||
this.handleShown.bind(null, this.input)
|
||||
)
|
||||
);
|
||||
|
||||
if (enhancedSearchInput) {
|
||||
DocSearch.bindSearchBoxEvent(this.autocomplete);
|
||||
DocSearch.bindSearchBoxEvent();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,24 +112,24 @@ class DocSearch {
|
|||
}
|
||||
}
|
||||
|
||||
static injectSearchBox(input, docsearch) {
|
||||
static injectSearchBox(input) {
|
||||
input.before(templates.searchBox);
|
||||
input.remove();
|
||||
}
|
||||
|
||||
static bindSearchBoxEvent(autocomplete) {
|
||||
$(".searchbox [type='reset']").on("click", function() {
|
||||
$("input#docsearch").focus();
|
||||
$(this).addClass("hide");
|
||||
autocomplete.autocomplete.setVal("");
|
||||
static bindSearchBoxEvent() {
|
||||
$('.searchbox [type="reset"]').on('click', function() {
|
||||
$('input#docsearch').focus();
|
||||
$(this).addClass('hide');
|
||||
autocomplete.autocomplete.setVal('');
|
||||
});
|
||||
|
||||
$("input#docsearch").on("keyup", function() {
|
||||
var searchbox = document.querySelector("input#docsearch");
|
||||
var reset = document.querySelector(".searchbox [type='reset']");
|
||||
reset.className = "searchbox__reset";
|
||||
if (searchbox.value.length === 0){
|
||||
reset.className += " hide";
|
||||
$('input#docsearch').on('keyup', function() {
|
||||
var searchbox = document.querySelector('input#docsearch');
|
||||
var reset = document.querySelector('.searchbox [type="reset"]');
|
||||
reset.className = 'searchbox__reset';
|
||||
if (searchbox.value.length === 0) {
|
||||
reset.className += ' hide';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -148,6 +150,7 @@ class DocSearch {
|
|||
* Returns the `source` method to be passed to autocomplete.js. It will query
|
||||
* the Algolia index and call the callbacks with the formatted hits.
|
||||
* @function getAutocompleteSource
|
||||
* @param {function} transformData An optional function to transform the hits
|
||||
* @returns {function} Method to be passed as the `source` option of
|
||||
* autocomplete
|
||||
*/
|
||||
|
|
@ -181,30 +184,31 @@ class DocSearch {
|
|||
// Group hits by category / subcategory
|
||||
var groupedHits = utils.groupBy(hits, 'lvl0');
|
||||
$.each(groupedHits, (level, collection) => {
|
||||
let groupedHitsByLvl1 = utils.groupBy(collection, 'lvl1');
|
||||
let flattenedHits = utils.flattenAndFlagFirst(groupedHitsByLvl1, 'isSubCategoryHeader');
|
||||
const groupedHitsByLvl1 = utils.groupBy(collection, 'lvl1');
|
||||
const flattenedHits = utils.flattenAndFlagFirst(groupedHitsByLvl1, 'isSubCategoryHeader');
|
||||
groupedHits[level] = flattenedHits;
|
||||
});
|
||||
groupedHits = utils.flattenAndFlagFirst(groupedHits, 'isCategoryHeader');
|
||||
|
||||
// Translate hits into smaller objects to be send to the template
|
||||
return groupedHits.map((hit) => {
|
||||
let url = DocSearch.formatURL(hit);
|
||||
let category = utils.getHighlightedValue(hit, 'lvl0');
|
||||
let subcategory = utils.getHighlightedValue(hit, 'lvl1') || category;
|
||||
let displayTitle = utils.compact([
|
||||
const url = DocSearch.formatURL(hit);
|
||||
const category = utils.getHighlightedValue(hit, 'lvl0');
|
||||
const subcategory = utils.getHighlightedValue(hit, 'lvl1') || category;
|
||||
const displayTitle = utils.compact([
|
||||
utils.getHighlightedValue(hit, 'lvl2') || subcategory,
|
||||
utils.getHighlightedValue(hit, 'lvl3'),
|
||||
utils.getHighlightedValue(hit, 'lvl4'),
|
||||
utils.getHighlightedValue(hit, 'lvl5'),
|
||||
utils.getHighlightedValue(hit, 'lvl6')
|
||||
]).join('<span class="aa-suggestion-title-separator"> › </span>');
|
||||
let text = utils.getSnippetedValue(hit, 'content');
|
||||
let isTextOrSubcatoryNonEmpty = (subcategory && subcategory != "") || (displayTitle && displayTitle != "");
|
||||
let isLvl1EmptyOrDuplicate = ! subcategory || subcategory == '' || subcategory == category;
|
||||
let isLvl2 = displayTitle && displayTitle != '' && displayTitle != subcategory;
|
||||
let isLvl1 = !isLvl2 && (subcategory && subcategory != '' && subcategory != category);
|
||||
let isLvl0 = !isLvl1 && !isLvl2;
|
||||
const text = utils.getSnippetedValue(hit, 'content');
|
||||
const isTextOrSubcatoryNonEmpty = (subcategory && subcategory !== '') ||
|
||||
(displayTitle && displayTitle !== '');
|
||||
const isLvl1EmptyOrDuplicate = !subcategory || subcategory === '' || subcategory === category;
|
||||
const isLvl2 = displayTitle && displayTitle !== '' && displayTitle !== subcategory;
|
||||
const isLvl1 = !isLvl2 && (subcategory && subcategory !== '' && subcategory !== category);
|
||||
const isLvl0 = !isLvl1 && !isLvl2;
|
||||
|
||||
return {
|
||||
isLvl0: isLvl0,
|
||||
|
|
@ -245,7 +249,7 @@ class DocSearch {
|
|||
}
|
||||
|
||||
static getSuggestionTemplate(isSimpleLayout) {
|
||||
var stringTemplate = isSimpleLayout ? templates.suggestionSimple : templates.suggestion
|
||||
const stringTemplate = isSimpleLayout ? templates.suggestionSimple : templates.suggestion;
|
||||
const template = Hogan.compile(stringTemplate);
|
||||
return (suggestion) => {
|
||||
return template.render(suggestion);
|
||||
|
|
@ -257,20 +261,22 @@ class DocSearch {
|
|||
window.location.href = suggestion.url;
|
||||
}
|
||||
|
||||
handleShown(input, event) {
|
||||
var middleOfInput = input.offset().left + input.width() / 2;
|
||||
var middleOfWindow = $(document).width() / 2;
|
||||
handleShown(input) {
|
||||
const middleOfInput = input.offset().left + input.width() / 2;
|
||||
let middleOfWindow = $(document).width() / 2;
|
||||
|
||||
if (isNaN(middleOfWindow)) {
|
||||
middleOfWindow = 900;
|
||||
}
|
||||
|
||||
var alignClass = middleOfInput - middleOfWindow >= 0 ? 'algolia-autocomplete-right' : 'algolia-autocomplete-left';
|
||||
var otherAlignClass = middleOfInput - middleOfWindow < 0 ? 'algolia-autocomplete-right' : 'algolia-autocomplete-left';
|
||||
const alignClass = middleOfInput - middleOfWindow >= 0 ?
|
||||
'algolia-autocomplete-right' : 'algolia-autocomplete-left';
|
||||
const otherAlignClass = middleOfInput - middleOfWindow < 0 ?
|
||||
'algolia-autocomplete-right' : 'algolia-autocomplete-left';
|
||||
|
||||
var autocompleteWrapper = $('.algolia-autocomplete');
|
||||
if (! autocompleteWrapper.hasClass(alignClass)) {
|
||||
autocompleteWrapper.addClass(alignClass)
|
||||
const autocompleteWrapper = $('.algolia-autocomplete');
|
||||
if (!autocompleteWrapper.hasClass(alignClass)) {
|
||||
autocompleteWrapper.addClass(alignClass);
|
||||
}
|
||||
|
||||
if (autocompleteWrapper.hasClass(otherAlignClass)) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import toFactory from 'to-factory';
|
|||
import DocSearch from './DocSearch';
|
||||
import version from './version.js';
|
||||
|
||||
let docsearch = toFactory(DocSearch);
|
||||
const docsearch = toFactory(DocSearch);
|
||||
docsearch.version = version;
|
||||
|
||||
export default docsearch;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
let prefix = 'algolia-docsearch';
|
||||
let suggestionPrefix = `${prefix}-suggestion`;
|
||||
let footerPrefix = `${prefix}-footer`;
|
||||
const prefix = 'algolia-docsearch';
|
||||
const suggestionPrefix = `${prefix}-suggestion`;
|
||||
const footerPrefix = `${prefix}-footer`;
|
||||
|
||||
let templates = {
|
||||
/* eslint-disable max-len */
|
||||
|
||||
const templates = {
|
||||
suggestion: `
|
||||
<div class="${suggestionPrefix}
|
||||
{{#isCategoryHeader}}${suggestionPrefix}__main{{/isCategoryHeader}}
|
||||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
">
|
||||
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
<span class="${suggestionPrefix}--category-header-lvl0">{{{category}}}</span>
|
||||
</div>
|
||||
|
|
@ -32,7 +33,6 @@ let templates = {
|
|||
{{#isSubCategoryHeader}}${suggestionPrefix}__secondary{{/isSubCategoryHeader}}
|
||||
suggestion-layout-simple
|
||||
">
|
||||
|
||||
<div class="${suggestionPrefix}--category-header">
|
||||
{{^isLvl0}}
|
||||
<span class="${suggestionPrefix}--category-header-lvl0 ${suggestionPrefix}--category-header-item">{{{category}}}</span>
|
||||
|
|
@ -44,7 +44,6 @@ let templates = {
|
|||
{{/isLvl1EmptyOrDuplicate}}
|
||||
{{/isLvl1}}
|
||||
{{/isLvl0}}
|
||||
|
||||
<div class="${suggestionPrefix}--title ${suggestionPrefix}--category-header-item">
|
||||
{{#isLvl2}}
|
||||
{{{title}}}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import $ from 'autocomplete.js/zepto.js';
|
||||
import $ from './zepto.js';
|
||||
|
||||
let utils = {
|
||||
/*
|
||||
|
|
|
|||
10
src/lib/zepto.js
Normal file
10
src/lib/zepto.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* zepto work-around */
|
||||
|
||||
const current$ = window.$;
|
||||
const currentZepto = window.Zepto;
|
||||
require('autocomplete.js/zepto.js');
|
||||
const zepto = window.Zepto;
|
||||
window.$ = current$;
|
||||
window.Zepto = currentZepto;
|
||||
|
||||
export default zepto;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-env mocha */
|
||||
/* eslint no-new:0 */
|
||||
/* eslint-disable max-len */
|
||||
|
||||
import jsdom from 'mocha-jsdom';
|
||||
import expect from 'expect';
|
||||
|
|
@ -17,7 +18,7 @@ describe('DocSearch', () => {
|
|||
// We need to load DocSearch from here as it depends on Zepto, which itself
|
||||
// needs jsdom to be called before being loaded.
|
||||
DocSearch = require('../src/lib/DocSearch.js');
|
||||
$ = require('npm-zepto');
|
||||
$ = require('../src/lib/zepto.js');
|
||||
|
||||
// Note: If you edit this HTML while doing TDD with `npm run test:watch`,
|
||||
// you will have to restart `npm run test:watch` for the new HTML to be
|
||||
|
|
@ -168,7 +169,7 @@ describe('DocSearch', () => {
|
|||
// Then
|
||||
expect(typeof actual.algoliaOptions).toEqual('object');
|
||||
expect(actual.algoliaOptions.anOption).toEqual(42);
|
||||
expect(actual.autocompleteOptions).toEqual({debug: false, "cssClasses": { "prefix": "ds" }, anOption: 44});
|
||||
expect(actual.autocompleteOptions).toEqual({debug: false, cssClasses: {prefix: 'ds'}, anOption: 44});
|
||||
});
|
||||
it('should instantiate algoliasearch with the correct values', () => {
|
||||
// Given
|
||||
|
|
@ -205,7 +206,7 @@ describe('DocSearch', () => {
|
|||
|
||||
// Then
|
||||
expect(AutoComplete.calledOnce).toBe(true);
|
||||
expect(AutoComplete.calledWith($input, {anOption: '44', "cssClasses": { "prefix": "ds" }, debug: false})).toBe(true);
|
||||
expect(AutoComplete.calledWith($input, {anOption: '44', cssClasses: {prefix: 'ds'}, debug: false})).toBe(true);
|
||||
});
|
||||
it('should listen to the selected and shown event of autocomplete', () => {
|
||||
// Given
|
||||
|
|
@ -404,7 +405,6 @@ describe('DocSearch', () => {
|
|||
ds.autocomplete.trigger('autocomplete:shown');
|
||||
|
||||
expect($('.algolia-autocomplete').attr('class')).toEqual('algolia-autocomplete algolia-autocomplete-left');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -980,11 +980,11 @@ describe('DocSearch', () => {
|
|||
let actual = DocSearch.getSuggestionTemplate();
|
||||
|
||||
// When
|
||||
actual({'foo': 'bar'});
|
||||
actual({foo: 'bar'});
|
||||
|
||||
// Then
|
||||
expect(render.calledOnce).toBe(true);
|
||||
expect(render.args[0][0]).toEqual({'foo': 'bar'});
|
||||
expect(render.args[0][0]).toEqual({foo: 'bar'});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue