Skip to content

Commit

Permalink
replace gh-selectize with power-select in gh-search-input
Browse files Browse the repository at this point in the history
  • Loading branch information
acburdine authored and geekhuyang committed Nov 20, 2016
1 parent da73579 commit ea65747
Show file tree
Hide file tree
Showing 10 changed files with 291 additions and 95 deletions.
119 changes: 65 additions & 54 deletions core/client/app/components/gh-search-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,29 @@
import Ember from 'ember';

const {
$,
Component,
RSVP,
computed,
run,
inject: {service},
observer
isBlank,
isEmpty
} = Ember;
const {filterBy} = computed;

export function computedGroup(category) {
return computed('content', 'currentSearch', function () {
if (!this.get('currentSearch') || !this.get('content')) {
return [];
}

return this.get('content').filter((item) => {
let search = new RegExp(this.get('currentSearch'), 'ig');

return (item.category === category) &&
item.title.match(search);
});
});
}

export default Component.extend({

Expand All @@ -19,28 +34,25 @@ export default Component.extend({
isLoading: false,
contentExpiry: 10 * 1000,
contentExpiresAt: false,
currentSearch: '',

posts: filterBy('content', 'category', 'Posts'),
pages: filterBy('content', 'category', 'Pages'),
users: filterBy('content', 'category', 'Users'),
tags: filterBy('content', 'category', 'Tags'),
posts: computedGroup('Posts'),
pages: computedGroup('Pages'),
users: computedGroup('Users'),
tags: computedGroup('Tags'),

_store: service('store'),
_routing: service('-routing'),
ajax: service(),

_selectize: computed(function () {
return this.$('select')[0].selectize;
}),

refreshContent() {
let promises = [];
let now = new Date();
let contentExpiry = this.get('contentExpiry');
let contentExpiresAt = this.get('contentExpiresAt');

if (this.get('isLoading') || contentExpiresAt > now) {
return;
return RSVP.resolve();
}

this.set('isLoading', true);
Expand All @@ -49,19 +61,42 @@ export default Component.extend({
promises.pushObject(this._loadUsers());
promises.pushObject(this._loadTags());

RSVP.all(promises).then(() => { }).finally(() => {
return RSVP.all(promises).then(() => { }).finally(() => {
this.set('isLoading', false);
this.set('contentExpiresAt', new Date(now.getTime() + contentExpiry));
});
},

groupedContent: computed('posts', 'pages', 'users', 'tags', function () {
let groups = [];

if (!isEmpty(this.get('posts'))) {
groups.pushObject({groupName: 'Posts', options: this.get('posts')});
}

if (!isEmpty(this.get('pages'))) {
groups.pushObject({groupName: 'Pages', options: this.get('pages')});
}

if (!isEmpty(this.get('users'))) {
groups.pushObject({groupName: 'Users', options: this.get('users')});
}

if (!isEmpty(this.get('tags'))) {
groups.pushObject({groupName: 'Tags', options: this.get('tags')});
}

return groups;
}),

_loadPosts() {
let store = this.get('_store');
let postsUrl = `${store.adapterFor('post').urlForQuery({}, 'post')}/`;
let postsQuery = {fields: 'id,title,page', limit: 'all', status: 'all', staticPages: 'all'};
let content = this.get('content');

return this.get('ajax').request(postsUrl, {data: postsQuery}).then((posts) => {

content.pushObjects(posts.posts.map((post) => {
return {
id: `post.${post.id}`,
Expand Down Expand Up @@ -106,11 +141,17 @@ export default Component.extend({
});
},

_keepSelectionClear: observer('selection', function () {
if (this.get('selection') !== null) {
this.set('selection', null);
_performSearch(term, resolve, reject) {
if (isBlank(term)) {
return resolve([]);
}
}),

this.refreshContent().then(() => {
this.set('currentSearch', term);

return resolve(this.get('groupedContent'));
}).catch(reject);
},

_setKeymasterScope() {
key.setScope('search-input');
Expand All @@ -127,68 +168,38 @@ export default Component.extend({

actions: {
openSelected(selected) {
let transition = null;

if (!selected) {
return;
}

if (selected.category === 'Posts' || selected.category === 'Pages') {
let id = selected.id.replace('post.', '');
transition = this.get('_routing.router').transitionTo('editor.edit', id);
this.get('_routing.router').transitionTo('editor.edit', id);
}

if (selected.category === 'Users') {
let id = selected.id.replace('user.', '');
transition = this.get('_routing.router').transitionTo('team.user', id);
this.get('_routing.router').transitionTo('team.user', id);
}

if (selected.category === 'Tags') {
let id = selected.id.replace('tag.', '');
transition = this.get('_routing.router').transitionTo('settings.tags.tag', id);
this.get('_routing.router').transitionTo('settings.tags.tag', id);
}

transition.then(() => {
if (this.get('_selectize').$control_input.is(':focus')) {
this._setKeymasterScope();
}
});
},

focusInput() {
this.get('_selectize').focus();
},

onInit() {
let selectize = this.get('_selectize');
let html = '<div class="dropdown-empty-message">Nothing found&hellip;</div>';

selectize.$empty_results_container = $(html);
selectize.$empty_results_container.hide();
selectize.$dropdown.append(selectize.$empty_results_container);
},

onFocus() {
this._setKeymasterScope();
this.refreshContent();
},

onBlur() {
let selectize = this.get('_selectize');

this._resetKeymasterScope();
selectize.$empty_results_container.hide();
},

onType() {
let selectize = this.get('_selectize');

if (!selectize.hasOptions) {
selectize.open();
selectize.$empty_results_container.show();
} else {
selectize.$empty_results_container.hide();
}
search(term) {
return new RSVP.Promise((resolve, reject) => {
run.debounce(this, this._performSearch, term, resolve, reject, 200);
});
}
}

Expand Down
42 changes: 42 additions & 0 deletions core/client/app/components/gh-search-input/trigger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Ember from 'ember';

const {run, isBlank, Component} = Ember;

export default Component.extend({
open() {
this.get('select.actions').open();
},

close() {
this.get('select.actions').close();
},

actions: {
captureMouseDown(e) {
e.stopPropagation();
},

search(term) {
if (isBlank(term) === this.get('select.isOpen')) {
run.scheduleOnce('afterRender', this, isBlank(term) ? this.close : this.open);
}

this.get('select.actions.search')(term);
},

focusInput() {
this.$('input')[0].focus();
},

resetInput() {
this.$('input').val('');
},

handleKeydown(e) {
let select = this.get('select');
if (!select.isOpen) {
e.stopPropagation();
}
}
}
});
7 changes: 7 additions & 0 deletions core/client/app/helpers/highlighted-text.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Ember from 'ember';

export function highlightedText([text, termToHighlight]) {
return Ember.String.htmlSafe(text.replace(new RegExp(termToHighlight, 'ig'), '<span class="highlight">$&</span>'));
}

export default Ember.Helper.helper(highlightedText);
1 change: 1 addition & 0 deletions core/client/app/styles/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
@import "components/popovers.css";
@import "components/settings-menu.css";
@import "components/selectize.css";
@import "components/power-select.css";


/* Layouts: Groups of Components
Expand Down
108 changes: 108 additions & 0 deletions core/client/app/styles/components/power-select.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
.ember-power-select-trigger {
border: 1px solid #dfe1e3;
border-radius: var(--border-radius);
color: #666;
}

.ember-basic-dropdown--opened > .ember-power-select-trigger,
.ember-power-select-trigger[aria-expanded="true"],
.ember-power-select-search input {
outline: 0;
border-color: #b1b1b1;
}

.ember-power-select-dropdown {
position: absolute;
z-index: 1000;
box-sizing: border-box;
margin: -1px 0 0 0;
border: 1px solid #b1b1b1;
border-top: 0 none;
background: #fff;
border-radius: 0 0 var(--border-radius) var(--border-radius);
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1);
}

.ember-power-select-options:not([role="group"]) {
max-height: 200px;
}

.ember-power-select-search input {
display: inline-block !important;
margin: 0 1px !important;
padding: 0 !important;
min-height: 0 !important;
max-width: 100% !important;
max-height: none !important;
border: 0 none !important;
background: none !important;
box-shadow: none !important;
text-indent: 0 !important;
font-size: 1.3rem;
line-height: inherit !important;
}

.ember-power-select-group {
float: left;
box-sizing: border-box;
width: 100%;
border-top: 0 none;
border-right: 1px solid #f2f2f2;
}

.ember-power-select-group .ember-power-select-group-name {
position: relative;
display: inline-block;
padding: 7px 8px;
background: #fff;
color: var(--midgrey);
font-size: 0.85em;
font-weight: normal;
cursor: default;
}

.ember-power-select-group .ember-power-select-group-name:after {
content: "";
position: absolute;
top: 52%;
left: calc(100% + 3px);
display: block;
width: calc(189px - 100%);
height: 1px;
border-bottom: #dfe1e3 1px solid;
}

@media (max-width: 800px) {
.ember-power-select-group .ember-power-select-group-name:after {
width: calc(224px - 100%);
}
}

@media (max-width: 500px) {
.ember-power-select-group .ember-power-select-group-name:after {
width: calc(80vw - 45px - 100%);
}
}

.ember-power-select-group:first-of-type .ember-power-select-group-name {
margin-bottom: 7px;
padding-top: 0;
padding-bottom: 0;
}

.ember-power-select-group .ember-power-select-option {
overflow: hidden;
padding: 7px 8px;
line-height: 1.35em;
cursor: pointer;
}

.ember-power-select-group .ember-power-select-option .highlight {
background: #fff3b8;
border-radius: 1px;
}

.ember-power-select-group .ember-power-select-option[aria-current="true"] {
background: color(var(--blue) alpha(-85%));
color: var(--darkgrey);
}

0 comments on commit ea65747

Please sign in to comment.