Skip to content

Commit 0705b3e

Browse files
committed
Merge branch 'develop' into cursorchanged-fired-on-hover
2 parents 656be52 + d0ac6cb commit 0705b3e

File tree

11 files changed

+116
-35
lines changed

11 files changed

+116
-35
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,17 @@ When initializing an autocomplete, there are a number of options you can configu
279279
* `header` – the header to prepend to the dropdown menu
280280
* `footer` – the footer to append to the dropdown menu
281281

282+
* `cssClasses` – An optional hash overriding the default css classes.
283+
* `root` – the root classes. Defaults to `algolia-autocomplete`.
284+
* `prefix` – the CSS class prefix of all nested elements. Defaults to `aa`.
285+
* `dropdownMenu` – the dropdown menu CSS class. Defaults to `dropdownMenu`.
286+
* `input` – the input CSS class. Defaults to `input`.
287+
* `hint` – the hint CSS class. Defaults to `hint`.
288+
* `suggestions` – the suggestions list CSS class. Defaults to `suggestions`.
289+
* `suggestion` – the suggestion wrapper CSS class. Defaults to `suggestion`.
290+
* `cursor` – the cursor CSS class. Defaults to `cursor`.
291+
* `dataset` – the dataset CSS class. Defaults to `dataset`.
292+
282293
```html
283294
<script type="text/template" id="my-custom-menu-template">
284295
<div class="my-custom-menu">

src/angular/directive.js

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ angular.module('algolia.autocomplete', [])
7171
openOnFocus: scope.options.openOnFocus,
7272
templates: scope.options.templates,
7373
debug: scope.options.debug,
74+
cssClasses: scope.options.cssClasses,
7475
datasets: scope.datasets
7576
});
7677
}

src/autocomplete/css.js

+11
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ var css = {
4949
rtl: {
5050
left: 'auto',
5151
right: '0'
52+
},
53+
defaultClasses: {
54+
root: 'algolia-autocomplete',
55+
prefix: 'aa',
56+
dropdownMenu: 'dropdown-menu',
57+
input: 'input',
58+
hint: 'hint',
59+
suggestions: 'suggestions',
60+
suggestion: 'suggestion',
61+
cursor: 'cursor',
62+
dataset: 'dataset'
5263
}
5364
};
5465

src/autocomplete/dataset.js

+21-7
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,16 @@ function Dataset(o) {
3636

3737
this.templates = getTemplates(o.templates, this.displayFn);
3838

39-
this.$el = o.$menu && o.$menu.find('.aa-dataset-' + this.name).length > 0 ?
40-
DOM.element(o.$menu.find('.aa-dataset-' + this.name)[0]) :
41-
DOM.element(html.dataset.replace('%CLASS%', this.name));
39+
this.cssClasses = _.mixin({}, css.defaultClasses, o.cssClasses || {});
40+
41+
var clazz = _.className(this.cssClasses.prefix, this.cssClasses.dataset);
42+
this.$el = o.$menu && o.$menu.find(clazz + '-' + this.name).length > 0 ?
43+
DOM.element(o.$menu.find(clazz + '-' + this.name)[0]) :
44+
DOM.element(
45+
html.dataset.replace('%CLASS%', this.name)
46+
.replace('%PREFIX%', this.cssClasses.prefix)
47+
.replace('%DATASET%', this.cssClasses.dataset)
48+
);
4249

4350
this.$menu = o.$menu;
4451
}
@@ -96,8 +103,8 @@ _.mixin(Dataset.prototype, EventEmitter, {
96103
}
97104

98105
if (this.$menu) {
99-
this.$menu.addClass('aa-' + (hasSuggestions ? 'with' : 'without') + '-' + this.name)
100-
.removeClass('aa-' + (hasSuggestions ? 'without' : 'with') + '-' + this.name);
106+
this.$menu.addClass(this.cssClasses.prefix + '-' + (hasSuggestions ? 'with' : 'without') + '-' + this.name)
107+
.removeClass(this.cssClasses.prefix + '-' + (hasSuggestions ? 'without' : 'with') + '-' + this.name);
101108
}
102109

103110
this.trigger('rendered');
@@ -112,8 +119,12 @@ _.mixin(Dataset.prototype, EventEmitter, {
112119
var args = [].slice.call(arguments, 0);
113120
var $suggestions;
114121
var nodes;
122+
var self = this;
115123

116-
$suggestions = DOM.element(html.suggestions).css(css.suggestions);
124+
var suggestionsHtml = html.suggestions.
125+
replace('%PREFIX%', this.cssClasses.prefix).
126+
replace('%SUGGESTIONS%', this.cssClasses.suggestions);
127+
$suggestions = DOM.element(suggestionsHtml).css(css.suggestions);
117128

118129
// jQuery#append doesn't support arrays as the first argument
119130
// until version 1.8, see http://bugs.jquery.com/ticket/11231
@@ -125,7 +136,10 @@ _.mixin(Dataset.prototype, EventEmitter, {
125136
function getSuggestionNode(suggestion) {
126137
var $el;
127138

128-
$el = DOM.element(html.suggestion)
139+
var suggestionHtml = html.suggestion.
140+
replace('%PREFIX%', self.cssClasses.prefix).
141+
replace('%SUGGESTION%', self.cssClasses.suggestion);
142+
$el = DOM.element(suggestionHtml)
129143
.append(that.templates.suggestion.apply(this, [suggestion].concat(args)));
130144

131145
$el.data(datasetKey, that.name);

src/autocomplete/dropdown.js

+12-10
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,24 @@ function Dropdown(o) {
3030

3131
this.isOpen = false;
3232
this.isEmpty = true;
33+
this.cssClasses = _.mixin({}, css.defaultClasses, o.cssClasses || {});
3334

3435
// bound functions
3536
onSuggestionClick = _.bind(this._onSuggestionClick, this);
3637
onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);
3738
onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);
3839

40+
var cssClass = _.className(this.cssClasses.prefix, this.cssClasses.suggestion);
3941
this.$menu = DOM.element(o.menu)
40-
.on('click.aa', '.aa-suggestion', onSuggestionClick)
41-
.on('mouseenter.aa', '.aa-suggestion', onSuggestionMouseEnter)
42-
.on('mouseleave.aa', '.aa-suggestion', onSuggestionMouseLeave);
42+
.on('click.aa', cssClass, onSuggestionClick)
43+
.on('mouseenter.aa', cssClass, onSuggestionMouseEnter)
44+
.on('mouseleave.aa', cssClass, onSuggestionMouseLeave);
4345

4446
if (o.templates && o.templates.header) {
4547
this.$menu.prepend(_.templatify(o.templates.header)());
4648
}
4749

48-
this.datasets = _.map(o.datasets, function(oDataset) { return initializeDataset(that.$menu, oDataset); });
50+
this.datasets = _.map(o.datasets, function(oDataset) { return initializeDataset(that.$menu, oDataset, o.cssClasses); });
4951
_.each(this.datasets, function(dataset) {
5052
var root = dataset.getRoot();
5153
if (root && root.parent().length === 0) {
@@ -108,20 +110,20 @@ _.mixin(Dropdown.prototype, EventEmitter, {
108110
},
109111

110112
_getSuggestions: function getSuggestions() {
111-
return this.$menu.find('.aa-suggestion');
113+
return this.$menu.find(_.className(this.cssClasses.prefix, this.cssClasses.suggestion));
112114
},
113115

114116
_getCursor: function getCursor() {
115-
return this.$menu.find('.aa-cursor').first();
117+
return this.$menu.find(_.className(this.cssClasses.prefix, this.cssClasses.cursor)).first();
116118
},
117119

118120
_setCursor: function setCursor($el) {
119-
$el.first().addClass('aa-cursor');
121+
$el.first().addClass(_.className(this.cssClasses.prefix, this.cssClasses.cursor, true));
120122
this.trigger('cursorMoved');
121123
},
122124

123125
_removeCursor: function removeCursor() {
124-
this._getCursor().removeClass('aa-cursor');
126+
this._getCursor().removeClass(_.className(this.cssClasses.prefix, this.cssClasses.cursor, true));
125127
},
126128

127129
_moveCursor: function moveCursor(increment) {
@@ -277,8 +279,8 @@ _.mixin(Dropdown.prototype, EventEmitter, {
277279
// ----------------
278280
Dropdown.Dataset = Dataset;
279281

280-
function initializeDataset($menu, oDataset) {
281-
return new Dropdown.Dataset(_.mixin({$menu: $menu}, oDataset));
282+
function initializeDataset($menu, oDataset, cssClasses) {
283+
return new Dropdown.Dataset(_.mixin({$menu: $menu, cssClasses: cssClasses}, oDataset));
282284
}
283285

284286
module.exports = Dropdown;

src/autocomplete/html.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use strict';
22

33
module.exports = {
4-
wrapper: '<span class="algolia-autocomplete"></span>',
5-
dropdown: '<span class="aa-dropdown-menu"></span>',
6-
dataset: '<div class="aa-dataset-%CLASS%"></div>',
7-
suggestions: '<span class="aa-suggestions"></span>',
8-
suggestion: '<div class="aa-suggestion"></div>'
4+
wrapper: '<span class="%ROOT%"></span>',
5+
dropdown: '<span class="%PREFIX%-%DROPDOWN_MENU%"></span>',
6+
dataset: '<div class="%PREFIX%-%DATASET%-%CLASS%"></div>',
7+
suggestions: '<span class="%PREFIX%-%SUGGESTIONS%"></span>',
8+
suggestion: '<div class="%PREFIX%-%SUGGESTION%"></div>'
99
};

src/autocomplete/typeahead.js

+16-12
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ function Typeahead(o) {
3030
this.autoselect = !!o.autoselect;
3131
this.openOnFocus = !!o.openOnFocus;
3232
this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
33+
this.cssClasses = o.cssClasses = _.mixin({}, css.defaultClasses, o.cssClasses || {});
3334
this.$node = buildDom(o);
3435

35-
$menu = this.$node.find('.aa-dropdown-menu');
36-
$input = this.$node.find('.aa-input');
37-
$hint = this.$node.find('.aa-hint');
36+
$menu = this.$node.find(_.className(this.cssClasses.prefix, this.cssClasses.dropdownMenu));
37+
$input = this.$node.find(_.className(this.cssClasses.prefix, this.cssClasses.input));
38+
$hint = this.$node.find(_.className(this.cssClasses.prefix, this.cssClasses.hint));
3839

3940
if (o.dropdownMenuContainer) {
4041
DOM.element(o.dropdownMenuContainer)
@@ -62,7 +63,7 @@ function Typeahead(o) {
6263

6364
this.eventBus = o.eventBus || new EventBus({el: $input});
6465

65-
this.dropdown = new Typeahead.Dropdown({menu: $menu, datasets: o.datasets, templates: o.templates})
66+
this.dropdown = new Typeahead.Dropdown({menu: $menu, datasets: o.datasets, templates: o.templates, cssClasses: this.cssClasses})
6667
.onSync('suggestionClicked', this._onSuggestionClicked, this)
6768
.onSync('cursorMoved', this._onCursorMoved, this)
6869
.onSync('cursorRemoved', this._onCursorRemoved, this)
@@ -365,7 +366,7 @@ _.mixin(Typeahead.prototype, {
365366
this.input.destroy();
366367
this.dropdown.destroy();
367368

368-
destroyDomStructure(this.$node);
369+
destroyDomStructure(this.$node, this.cssClasses);
369370

370371
this.$node = null;
371372
}
@@ -378,22 +379,25 @@ function buildDom(options) {
378379
var $hint;
379380

380381
$input = DOM.element(options.input);
381-
$wrapper = DOM.element(html.wrapper).css(css.wrapper);
382+
$wrapper = DOM.element(html.wrapper.replace('%ROOT%', options.cssClasses.root)).css(css.wrapper);
382383
// override the display property with the table-cell value
383384
// if the parent element is a table and the original input was a block
384385
// -> https://github.com/algolia/autocomplete.js/issues/16
385386
if ($input.css('display') === 'block' && $input.parent().css('display') === 'table') {
386387
$wrapper.css('display', 'table-cell');
387388
}
388-
$dropdown = DOM.element(html.dropdown).css(css.dropdown);
389+
var dropdownHtml = html.dropdown.
390+
replace('%PREFIX%', options.cssClasses.prefix).
391+
replace('%DROPDOWN_MENU%', options.cssClasses.dropdownMenu);
392+
$dropdown = DOM.element(dropdownHtml).css(css.dropdown);
389393
if (options.templates && options.templates.dropdownMenu) {
390394
$dropdown.html(_.templatify(options.templates.dropdownMenu)());
391395
}
392396
$hint = $input.clone().css(css.hint).css(getBackgroundStyles($input));
393397

394398
$hint
395399
.val('')
396-
.addClass('aa-hint')
400+
.addClass(_.className(options.cssClasses.prefix, options.cssClasses.hint, true))
397401
.removeAttr('id name placeholder required')
398402
.prop('readonly', true)
399403
.attr({autocomplete: 'off', spellcheck: 'false', tabindex: -1});
@@ -411,7 +415,7 @@ function buildDom(options) {
411415
});
412416

413417
$input
414-
.addClass('aa-input')
418+
.addClass(_.className(options.cssClasses.prefix, options.cssClasses.input, true))
415419
.attr({autocomplete: 'off', spellcheck: false})
416420
.css(options.hint ? css.input : css.inputWithNoHint);
417421

@@ -444,8 +448,8 @@ function getBackgroundStyles($el) {
444448
};
445449
}
446450

447-
function destroyDomStructure($node) {
448-
var $input = $node.find('.aa-input');
451+
function destroyDomStructure($node, cssClasses) {
452+
var $input = $node.find(_.className(cssClasses.prefix, cssClasses.input));
449453

450454
// need to remove attrs that weren't previously defined and
451455
// revert attrs that originally had a value
@@ -459,7 +463,7 @@ function destroyDomStructure($node) {
459463

460464
$input
461465
.detach()
462-
.removeClass('aa-input')
466+
.removeClass(_.className(cssClasses.prefix, cssClasses.input, true))
463467
.insertAfter($node);
464468
if ($input.removeData) {
465469
$input.removeData(attrsKey);

src/common/utils.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,9 @@ module.exports = {
8282

8383
defer: function(fn) { setTimeout(fn, 0); },
8484

85-
noop: function() {}
85+
noop: function() {},
86+
87+
className: function(prefix, clazz, skipDot) {
88+
return (skipDot ? '' : '.') + prefix + '-' + clazz;
89+
}
8690
};

src/jquery/plugin.js

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ methods = {
5858
openOnFocus: o.openOnFocus,
5959
templates: o.templates,
6060
debug: o.debug,
61+
cssClasses: o.cssClasses,
6162
datasets: datasets
6263
});
6364

src/standalone/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function autocomplete(selector, options, datasets, typeaheadObject) {
4545
openOnFocus: options.openOnFocus,
4646
templates: options.templates,
4747
debug: options.debug,
48+
cssClasses: options.cssClasses,
4849
datasets: datasets
4950
});
5051

test/unit/typeahead_spec.js

+32
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,38 @@ describe('Typeahead', function() {
687687
});
688688
});
689689

690+
describe('when instantiated with a custom CSS classes', function() {
691+
beforeEach(function() {
692+
appendSetFixtures(fixtures.html.customMenu);
693+
694+
this.view.destroy();
695+
this.view = new Typeahead({
696+
input: this.$input,
697+
hint: true,
698+
cssClasses: {
699+
root: 'my-root',
700+
prefix: 'pp',
701+
dropdownMenu: 'my-menu',
702+
input: 'my-bar',
703+
hint: 'my-clue',
704+
suggestions: 'list',
705+
suggestion: 'item',
706+
cursor: 'pointer',
707+
dataset: 'resultset'
708+
},
709+
datasets: {}
710+
});
711+
});
712+
713+
it('should include the template in the menu', function() {
714+
var $fixture = $('#jasmine-fixtures');
715+
expect($fixture.find('.my-root').length).toEqual(1);
716+
expect($fixture.find('.my-root .pp-my-menu').length).toEqual(1);
717+
expect($fixture.find('.my-root .pp-my-bar').length).toEqual(1);
718+
expect($fixture.find('.my-root .pp-my-clue').length).toEqual(1);
719+
});
720+
});
721+
690722
describe('when instantiated with a custom menu container', function() {
691723
beforeEach(function() {
692724
appendSetFixtures(fixtures.html.customMenuContainer);

0 commit comments

Comments
 (0)