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

View File

@@ -0,0 +1,33 @@
var CoreView = require('backbone/core-view');
module.exports = CoreView.extend({
tagName: 'button',
initialize: function (opts) {
if (!opts.template) throw new Error('template is required');
if (!opts.editorModel) throw new Error('editorModel is required');
this.template = opts.template;
this._editorModel = opts.editorModel;
this._data = {};
if (opts.model) {
this._data = opts.model.toJSON();
}
this._initBinds();
},
_initBinds: function () {
this.listenTo(this._editorModel, 'change:edition', this._changeStyle);
this.add_related_model(this._editorModel);
},
render: function () {
this.clearSubViews();
this.$el.empty();
this.$el.append(this.template(this._data));
return this;
},
_changeStyle: function () {
this.$('.js-theme').toggleClass('is-white', this._editorModel.isEditing());
}
});

View File

@@ -0,0 +1 @@
<span data-action="<%- button %>" class="CDB-Text is-semibold u-lSpace u-actionTextColor u-upperCase"><%- button %></span>

View File

@@ -0,0 +1 @@
<div class="CDB-Shape-close is-blue is-large js-theme"></div>

View File

@@ -0,0 +1,22 @@
var Backbone = require('backbone');
var NotifierModel = require('./notifier-model');
module.exports = Backbone.Collection.extend({
model: function (attrs, opts) {
return new NotifierModel(attrs, opts);
},
findById: function (id) {
return this.findWhere({id: id});
},
addNotification: function (attrs, options) {
var notification = this._findNotificationByAttrs(attrs);
return notification ? notification.update(attrs) : this.add(attrs, options);
},
_findNotificationByAttrs: function (attrs) {
return this.findWhere({ info: attrs.info });
}
});

View File

@@ -0,0 +1,126 @@
var CoreView = require('backbone/core-view');
var Template = require('./notifier-item.tpl');
var ActionView = require('./notifier-action-view');
var closeTemplate = require('./notifier-close.tpl');
var actionTemplate = require('./notifier-action.tpl');
module.exports = CoreView.extend({
className: 'Notifier-inner',
tagName: 'li',
events: {
'click .js-close': '_closeHandler',
'click .js-action': '_actionHandler'
},
initialize: function (opts) {
if (!opts.notifierModel) throw new Error('notifierModel is required');
if (!opts.editorModel) throw new Error('editorModel is required');
this._editorModel = opts.editorModel;
this.template = this.options.template || Template;
this._notifierModel = opts.notifierModel;
this.$el.attr('id', this._notifierModel.get('id'));
this._delay = this._notifierModel.get('delay') || this._notifierModel.get('defaultDelay');
if (this._notifierModel.get('delay') && this._notifierModel.get('closable') !== false) {
this._timeout = setTimeout(this._autoClose.bind(this), this._delay);
}
this._initBinds();
},
render: function () {
this.clearSubViews();
this.$el.empty();
this._initViews();
this._changeStyle();
return this;
},
_initBinds: function () {
this.listenTo(this._notifierModel, 'change', this.render);
this.listenTo(this._notifierModel, 'change:status', this._onChangeStatus);
this.add_related_model(this._notifierModel);
this.listenTo(this._editorModel, 'change:edition', this._changeStyle);
this.add_related_model(this._editorModel);
},
_initViews: function () {
var actionable = this._notifierModel.getButton();
var closable = this._notifierModel.isClosable();
var view = this.template({
status: this._notifierModel.getStatus(),
info: this._notifierModel.getInfo(),
isActionable: actionable,
isClosable: closable
});
this.$el.append(view);
if (actionable) {
this._createActionView(actionable);
}
if (closable) {
this._createCloseView();
}
},
_createActionView: function (action) {
var actionView = new ActionView({
template: actionTemplate,
className: 'js-action',
model: this._notifierModel,
editorModel: this._editorModel
});
this.$('.js-actionButton').append(actionView.render().el);
this.addView(actionView);
},
_createCloseView: function () {
var actionView = new ActionView({
template: closeTemplate,
className: 'CDB-Shape js-close',
editorModel: this._editorModel
});
this.$('.js-closeButton').append(actionView.render().el);
this.addView(actionView);
},
_closeHandler: function () {
var status = this._notifierModel.getStatus();
var action = this._notifierModel.getAction();
this._notifierModel.trigger('notification:close', action || status);
clearTimeout(this._timeout);
if (this._notifierModel && this._notifierModel.collection) {
this._notifierModel.collection.remove(this._notifierModel);
}
},
_actionHandler: function () {
var status = this._notifierModel.getStatus();
var action = this._notifierModel.getAction();
this._notifierModel.trigger('notification:action', action || status);
},
_changeStyle: function () {
this.$('.Notifier-info').toggleClass('u-whiteTextColor', this._editorModel.isEditing());
this.$('.Notifier-actions .CDB-Shape-close').toggleClass('is-blue', !this._editorModel.isEditing());
this.$('.Notifier-actions .CDB-Shape-close').toggleClass('is-white', this._editorModel.isEditing());
},
_autoClose: function () {
this._notifierModel.set({action: 'autoclose'}, {silent: true});
this._closeHandler();
},
_onChangeStatus: function (model, status) {
if ((status === 'success' || status === 'error') && this._notifierModel.get('closable') !== false && this._notifierModel.get('autoclosable') !== false) {
this._timeout = setTimeout(this._autoClose.bind(this), this._delay);
}
}
});

View File

@@ -0,0 +1,34 @@
<div class="Notifier-item Notifier-item--<%- status %>">
<% if (status === 'loading') { %>
<div class="Notifier-icon CDB-LoaderIcon is-blue js-theme u-rSpace--m">
<svg class="CDB-LoaderIcon-spinner" viewBox="0 0 50 50">
<circle class="CDB-LoaderIcon-path" cx="25" cy="25" r="20" fill="none"></circle>
</svg>
</div>
<% } %>
<% if (status === 'success') { %>
<div class="Notifier-icon CDB-Shape u-rSpace--m">
<div class="CDB-Shape-CircleItem CDB-Shape-CircleItem--fill is-green">
<div class="CDB-Shape-tick is-medium is-white"></div>
</div>
</div>
<% } %>
<% if (status === 'error' || status === 'warning') { %>
<div class="Notifier-icon CDB-Shape u-rSpace--m">
<div class="CDB-Shape-CircleItem CDB-Shape-CircleItem--fill is-red">
<div class="CDB-Shape-close is-medium is-white"></div>
</div>
</div>
<% } %>
<div class="Notifier-info">
<p class="CDB-Text CDB-Size-medium"><%= info %> <% if (isActionable) { %> <span class="js-actionButton"></span> <% } %></p>
</div>
<% if (isClosable) { %>
<div class="Notifier-actions js-closeButton"></div>
<% } %>
</div>

View File

@@ -0,0 +1,72 @@
var Backbone = require('backbone');
module.exports = Backbone.Model.extend({
defaults: {
status: 'idle',
info: '',
closable: true
},
initialize: function (attrs, opts) {
if (attrs.id === undefined) {
this.set('id', 'notifier' + this.cid);
}
this.set('defaultDelay', opts.delay);
if (opts.visDefinitionModel) {
this._retriggerEvent(opts.visDefinitionModel, 'vis:reload');
this._retriggerEvent(opts.visDefinitionModel, 'vis:error');
}
},
isClosable: function () {
return this.get('closable') === true;
},
updateClosable: function (val) {
this.set({closable: val});
},
getButton: function () {
return this.get('button');
},
updateButton: function (val) {
this.set({button: val});
},
getStatus: function () {
return this.get('status');
},
updateStatus: function (val) {
this.set({status: val});
},
getInfo: function () {
return this.get('info');
},
getAction: function () {
return this.get('action');
},
setAction: function (val) {
this.set({action: val});
},
updateInfo: function (val) {
this.set({info: val});
},
update: function (state) {
this.set(state);
},
_retriggerEvent: function (model, event) {
model.on(event, function () {
this.trigger(event, arguments);
}, this);
}
});

View File

@@ -0,0 +1,96 @@
var CoreView = require('backbone/core-view');
var _ = require('underscore');
var NotifierItemView = require('./notifier-item-view');
var template = require('./notifier.tpl');
module.exports = CoreView.extend({
className: 'Notifier',
initialize: function (opts) {
if (!opts.collection) throw new Error('collection is mandatory');
if (!opts.editorModel) throw new Error('editorModel is mandatory');
this._editorModel = opts.editorModel;
this._initBinds();
},
render: function () {
this.clearSubViews();
this.$el.html(template());
this._renderAllSubviews();
this._renderLoading();
return this;
},
rebindEvents: function () {
// Just in case
this.stopListening(this.collection);
this.stopListening(this._editorModel);
this._initBinds();
return this;
},
_initBinds: function () {
this.listenTo(this.collection, 'reset update change:status', this.render);
this.add_related_model(this.collection);
this.listenTo(this._editorModel, 'change:edition', this._changeStyle);
this.add_related_model(this._editorModel);
},
_renderAllSubviews: function () {
this.collection.each(this._renderSubview, this);
},
_renderSubview: function (model) {
var view = new NotifierItemView({
notifierModel: model,
editorModel: this._editorModel
});
var status = model.get('status');
var container = (status === 'success' || status === 'error')
? this._getDoneContainer()
: this._getLoadingContainer();
container.append(view.render().el);
this.addView(view);
},
_removeSubview: function (model) {
var id = model.get('id');
var view = _.first(_.filter(this._subviews, function (subview) {
return subview._notifierModel.get('id') === id;
}));
if (view) {
this.removeView(view);
view.remove();
}
},
_renderLoading: function () {
this._getLoader().toggleClass('is-visible', this._anyNotificationLoading());
},
_anyNotificationLoading: function () {
return this.collection.any(function (model) {
return !_.contains(['success', 'error', 'warning'], model.get('status'));
});
},
_changeStyle: function () {
this.$el.toggleClass('is-dark', this._editorModel.isEditing());
},
_getDoneContainer: function () {
return this.$('.js-status-done');
},
_getLoadingContainer: function () {
return this.$('.js-status-loading');
},
_getLoader: function () {
return this.$('.js-loader');
}
});

View File

@@ -0,0 +1,81 @@
var NotifierView = require('./notifier-view');
var NotifierCollection = require('./notifier-collection');
var manager = (function () {
var initialized = false;
var notifierView;
var collection = new NotifierCollection();
var editorModel;
function init (opts) {
if (!editorModel && !opts) {
throw new Error('editorModel is required');
}
if (!editorModel && opts && opts.editorModel) {
editorModel = opts.editorModel;
}
initialized = true;
notifierView = new NotifierView({
collection: collection,
editorModel: editorModel
});
}
return {
DEFAULT_DELAY: 5000,
init: function (opts) {
if (opts.visDefinitionModel) {
this._visDefinitionModel = opts.visDefinitionModel;
}
init(opts);
},
// For testing porposes only
off: function () {
if (__ENV__ === 'test') {
collection.reset();
initialized = false;
notifierView.remove();
notifierView = null;
}
},
getView: function () {
if (!initialized) init();
return notifierView.rebindEvents();
},
getCollection: function () {
return collection;
},
getCount: function () {
return collection.size();
},
getNotification: function (model) {
return typeof model === 'string'
? collection.findById(model)
: collection.findById(model.id);
},
addNotification: function (attrs) {
return collection.addNotification(attrs, {
visDefinitionModel: this._visDefinitionModel,
delay: this.DEFAULT_DELAY
});
},
removeNotification: function (model) {
var notification = typeof model === 'string'
? collection.findById(model)
: collection.findById(model.id);
return collection.remove(notification);
}
};
})();
module.exports = manager;

View File

@@ -0,0 +1,3 @@
<div class="CDB-Loader js-loader"></div>
<ul class="Notifier-list js-status-loading"></ul>
<ul class="Notifier-list js-status-done"></ul>