1
0
Fork 0

chore(test+lint): fixed tests & linting (#134)

This commit is contained in:
Sylvain Utard 2016-08-03 23:14:29 +02:00 committed by maxiloc
parent 254903ab7a
commit 6ba59acc4e
8 changed files with 91 additions and 58 deletions

View file

@ -1,3 +1,4 @@
coverage/
dist/
docs/
dist-es5-module/

View file

@ -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

View file

@ -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)) {

View file

@ -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;

View file

@ -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}}}

View file

@ -1,4 +1,4 @@
import $ from 'autocomplete.js/zepto.js';
import $ from './zepto.js';
let utils = {
/*

10
src/lib/zepto.js Normal file
View 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;

View file

@ -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'});
});
});
});