Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions
@@ -0,0 +1,47 @@
var Backbone = require('backbone');
/**
* Model representing the query string params for a "paged search" of a collection (matching the server-side APIs).
*
* @example usage
* pagedSearch = new PaginationSearchModel({ … })
* pagedSearch.fetch(collection) // => jqXHR, GET /collection/123?page=1&per_page20
* pagedSearch.set({ page: 2, per_page: 10, q: 'test' });
* pagedSearch.fetch(collection) // => GET /collection/123?page=2&per_page10&q=test
*/
module.exports = Backbone.Model.extend({
defaults: {
per_page: 20,
page: 1,
q: ''
},
initialize: function (attrs, opts) {
if (!opts.collection) throw new Error('collection is required');
if (!opts.collection.totalCount) throw new Error('collection requires to implement totalCount method');
this.collection = opts.collection;
this._initBinds();
},
_initBinds: function () {
this.collection.on('sync', this._updateStateFetched, this);
this.collection.on('error', this._updateStateError, this);
},
fetch: function () {
this.trigger('fetching', this);
return this.collection.fetch({
data: this.attributes
}, {reset: true});
},
_updateStateFetched: function () {
this.trigger('fetched', this);
},
_updateStateError: function () {
this.trigger('error', this);
}
});
@@ -0,0 +1,210 @@
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var _ = require('underscore');
var PaginationModel = require('builder/components/pagination/pagination-model');
var PaginationSearchModel = require('./pagination-search-model');
var renderLoading = require('builder/components/loading/render-loading');
var renderNoResults = require('builder/components/no-results/render-no-results');
var ErrorView = require('builder/components/error/error-view');
var template = require('./pagination-search.tpl');
var Utils = require('builder/helpers/utils');
var PaginationView = require('builder/components/pagination/pagination-view');
var paginationTemplate = require('./pagination.tpl');
/**
* View to render a searchable/pageable collection.
* Also allows to filter/search list.
*
*/
var REQUIRED_OPTS = [
'listCollection',
'createContentView'
];
var ENTER_KEY_CODE = 13;
var ESCAPE_KEY_CODE = 27;
module.exports = CoreView.extend({
events: {
'click .js-search-link': '_onSearchClick',
'click .js-clean-search': '_onCleanSearchClick',
'keydown .js-search-input': '_onKeyDown'
},
initialize: function (opts) {
_.each(REQUIRED_OPTS, function (item) {
if (opts[item] === undefined) throw new Error(item + ' is required');
this['_' + item] = opts[item];
}, this);
this._paginationModel = new PaginationModel({
current_page: 1
});
this._paginationSearchModel = new PaginationSearchModel({}, {
collection: this._listCollection
});
this._stateModel = new Backbone.Model({
state: 'idle'
});
this._initBinds();
this._initPagination();
this._paginationSearchModel.fetch();
},
render: function () {
this.clearSubViews();
this.$el.html(template({
q: this._paginationSearchModel.get('q')
}));
this._initViews();
return this;
},
_initBinds: function () {
this._paginationSearchModel.on('fetching', this.showLoading, this);
this._paginationSearchModel.on('fetched', this._updateStateFetched, this);
this._paginationSearchModel.on('error', this.showError, this);
this._paginationModel.bind('change:current_page', this._fetchByPagination, this);
this._stateModel.on('change:state', this.render, this);
this.add_related_model(this._paginationModel);
this.add_related_model(this._stateModel);
this.add_related_model(this._stateModel);
},
_fetchByPagination: function () {
this._paginationSearchModel.set('page', this._paginationModel.get('current_page'));
this._paginationSearchModel.fetch();
},
showError: function () {
this._stateModel.set('state', 'error');
},
showLoading: function () {
this._stateModel.set('state', 'loading');
},
_updateStateFetched: function () {
this._paginationModel.set({
per_page: this._paginationSearchModel.get('per_page'),
total_count: this._listCollection.totalCount()
});
if (this._listCollection.length > 0) {
this._stateModel.set('state', 'show');
} else {
this._stateModel.set('state', 'no-results');
}
},
_initPagination: function () {
this._paginationView = new PaginationView({
className: 'Pagination Pagination--search Pagination--searchShare',
model: this._paginationModel,
template: paginationTemplate
});
this.addView(this._paginationView);
},
_initViews: function () {
var state = this._stateModel.get('state');
var view;
this.$el.append(this._paginationView.render().el);
if (state === 'loading') {
this._content().html(renderLoading({
title: _t('components.pagination-search.loading.title')
}));
}
if (state === 'error') {
var errorView = new ErrorView({
title: _t('components.pagination-search.error.title'),
desc: _t('components.pagination-search.error.desc')
});
this._content().html(errorView.render().el);
this.addView(errorView);
}
if (state === 'show') {
view = this._createContentView({
hasOrganization: this._paginationSearchModel.get('q') === ''
});
this._content().html(view.render().el);
this.addView(view);
}
if (state === 'no-results') {
this._content().html(renderNoResults({
icon: 'CDB-IconFont-defaultUser',
title: _t('components.pagination-search.no-results.title'),
desc: _t('components.pagination-search.no-results.desc')
}));
}
},
_focusSearchInput: function () {
this._searchInput().focus().val();
},
_onSearchClick: function (e) {
this.killEvent(e);
this._searchInput().focus();
},
_onCleanSearchClick: function (e) {
this.killEvent(e);
this._cleanSearch();
},
_onKeyDown: function (e) {
if (e.which === ENTER_KEY_CODE) {
this.killEvent(e);
this._submitSearch();
} else if (e.which === ESCAPE_KEY_CODE) {
if (this._paginationSearchModel.get('q')) {
this.killEvent(e);
this._cleanSearch();
}
}
},
_submitSearch: function (e) {
this._makeNewSearch(Utils.stripHTML(this._searchInput().val().trim()));
},
_cleanSearch: function () {
this._searchInput().val('');
this._makeNewSearch('');
},
_makeNewSearch: function (query) {
this._paginationSearchModel.set({
q: query,
page: 1
});
this._paginationSearchModel.fetch();
},
_searchInput: function () {
return this.$('.js-search-input');
},
_cleanSearchBtn: function () {
return this.$('.js-clean-search');
},
_content: function () {
return this.$('.js-content');
}
});
@@ -0,0 +1,20 @@
<div class="Filters is-relative">
<div class="Filters-inner">
<div class="Filters-row Share-filtersRow js-filters">
<div class="Filters-typeItem Filters-typeItem--searchEnabler">
<p class="Filters-searchLink js-search-link u-alignCenter CDB-Text CDB-Size-medium u-upperCase">
<i class="Filters-searchLinkIcon CDB-IconFont CDB-IconFont-lens u-rSpace--xl"></i> <%- _t('components.pagination-search.filter.search') %>
</p>
</div>
<div class="Filters-typeItem Filters-typeItem--searchField">
<input class="Filters-searchInput CDB-Text CDB-Size-medium js-search-input" type="text" value="<%- q %>" placeholder="<%- _t('components.pagination-search.filter.placeholder') %>" />
<% if (q !== '') { %>
<button type="button" class="CDB-Shape Filters-cleanSearch js-clean-search u-actionTextColor">
<div class="CDB-Shape-close is-blue is-large"></div>
</button>
<% } %>
</div>
</div>
</div>
</div>
<div class="js-content"></div>
@@ -0,0 +1,16 @@
<span class="CDB-Text CDB-Size-medium u-altTextColor Pagination-label">
Page <%- currentPage %> of <%- pagesCount %>
</span>
<ul class="Pagination-list CDB-Text CDB-Size-medium">
<% m.pagesToDisplay().forEach(function(page) { %>
<% if (page > 0) { %>
<li class="Pagination-listItem <%- m.isCurrentPage(page) ? 'is-current' : '' %>">
<button class="Pagination-listItemInner Pagination-listItemInner--link u-actionTextColor js-listItem" data-page="<%- page %>"><%- page %></button>
</li>
<% } else { %>
<li class="Pagination-listItem Pagination-listItem">
<span class="Pagination-listItemInner Pagination-listItemInner--more">&hellip;</span>
</li>
<% } %>
<% }) %>
</ul>