Created
July 30, 2015 09:55
-
-
Save josephj/f3f5a361f84cf56dca33 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*global $ */ | |
'use strict'; | |
var Stackla = require('./stackla.js'), | |
Base = require('./base.js'), | |
Sortable = null, | |
Mustache = require('mustache'), | |
// Constant | |
NAME = 'sortable', | |
ORDER_BY_ATTR = 'data-sortable-orderby', | |
SELECTOR = '[data-uikit=sortable]', | |
SORT_BY_ATTR = 'data-sortable-sortby', | |
ACTIVE_CLASS = 'is-active', | |
LOADING_CLASS = 'is-loading', | |
WRAPPER_CLASS = 'st-sortable-wrapper', | |
FIELD_CLASS = 'st-sortable', | |
INDICATOR_CLASS = 'st-sortable-indicator', | |
UP_ICON_CLASS = 'fs fs-arrow-up5', | |
SORT_ICON_CLASS = 'fs fs-sort', | |
LOAD_ICON_CLASS = 'fs fs-spin fs-spinner', | |
DOWN_ICON_CLASS = 'fs fs-arrow-down5'; | |
Sortable = Stackla.createClass(Base, { | |
initializer: function ($el, options) { | |
var that = this; | |
options = options || {}; | |
// Validation | |
if (!options.url || !options.template || !options.target) { | |
throw new Error('The url, template, and target config options are required!'); | |
} | |
// Public attributes | |
that.$el = $($el); | |
that.url = options.url; | |
that.template = $(options.template).html(); | |
that.$target = $(options.target); | |
that.sortBy = null; | |
that.orderBy = null; | |
// Private attributes, just for internal use | |
that._isLoading = false; | |
that.$_active = null; | |
that.bind(); | |
}, | |
toString: function () { | |
return 'Sortable'; | |
}, | |
//================= | |
// Event Handlers | |
//================= | |
_handleClick: function (e) { | |
var that = this, | |
$current = $(e.currentTarget), | |
$prev = that.$_active; | |
// Stop if the previous request hasn't finished. | |
if (that._isLoading) { | |
return; | |
} | |
that.log('_handleClick() is executed'); | |
// Reset previous active field | |
if (!$current.is($prev)) { | |
$prev.removeAttr(ORDER_BY_ATTR); | |
$prev.removeClass(ACTIVE_CLASS); | |
} | |
// Update direction | |
if ($current.attr(ORDER_BY_ATTR) === 'asc') { | |
$current.attr(ORDER_BY_ATTR, 'desc'); | |
} else { | |
$current.attr(ORDER_BY_ATTR, 'asc'); | |
} | |
that.$_active = $current; | |
that.sortBy = $current.attr(SORT_BY_ATTR); | |
that.orderBy = $current.attr(ORDER_BY_ATTR); | |
that._makeRequest(); | |
}, | |
//================= | |
// Private Methods | |
//================= | |
_makeRequest: function () { | |
var that = this , | |
url = that.url + '?sort_by=' + encodeURIComponent(that.sortBy) + | |
'&order_by=' + encodeURIComponent(that.orderBy); | |
that.log('_makeRequest() is executed'); | |
that.$_active.addClass(LOADING_CLASS + ' ' + ACTIVE_CLASS); | |
that._isLoading = true; | |
that._uiSetIndicator(that.$_active, 'loading'); | |
$.ajax({ | |
url: url, | |
dataType: 'json', | |
success: function (data) { | |
var html; | |
that.emit('load', [data]); | |
html = Mustache.render(that.template, data); | |
that.$target.html(html); | |
that._uiSetIndicator(that.$_active, that.orderBy); | |
}, | |
error: function (xhr, status, err) { | |
that.emit('error', [err]); | |
}, | |
complete: function () { | |
that.$_active.removeClass(LOADING_CLASS); | |
that._isLoading = false; | |
} | |
}); | |
}, | |
_uiSetIndicator: function ($sort, orderBy) { | |
var that = this, | |
$indicator; | |
that.log('_uiSetIndicator() is executed'); | |
// Remove exisiting indicator | |
that.$el.find('.' + INDICATOR_CLASS).removeClass([ | |
UP_ICON_CLASS, | |
DOWN_ICON_CLASS, | |
LOAD_ICON_CLASS | |
].join(' ')); | |
that.$el.find('.' + INDICATOR_CLASS).addClass(SORT_ICON_CLASS); | |
$indicator = $sort.find('.' + INDICATOR_CLASS); | |
$indicator.removeClass(SORT_ICON_CLASS); | |
if (orderBy === 'desc') { | |
$indicator.addClass(DOWN_ICON_CLASS); | |
} else if (orderBy === 'asc') { | |
$indicator.addClass(UP_ICON_CLASS); | |
} else if (orderBy === 'loading') { | |
$indicator.addClass(LOAD_ICON_CLASS); | |
} | |
}, | |
//=================== | |
// Lifecycle Methods | |
//=================== | |
bind: function () { | |
var that = this, | |
$el = that.$el; | |
that.log('bind() is executed'); | |
$el.on('click', '.' + FIELD_CLASS, $.proxy(that._handleClick, that)); | |
}, | |
render: function () { | |
var that = this, | |
$el = that.$el, | |
$active, | |
$fields, | |
$field, | |
$indicator; | |
that.log('render() is executed'); | |
$fields = that.$el.find('[' + SORT_BY_ATTR + ']'); | |
$fields.addClass(FIELD_CLASS); | |
// Append indicator with up icon to all fields by default | |
$fields.each(function (i, el) { | |
$field = $(el); | |
$indicator = $field.find('.' + INDICATOR_CLASS); | |
if (!$indicator.length) { | |
$indicator = $('<i class="' + INDICATOR_CLASS + ' ' + SORT_ICON_CLASS + '"></i>'); | |
$field.append($indicator); | |
} | |
}); | |
// Apply correct class to active field | |
$active = $el.find('[' + ORDER_BY_ATTR + ']'); | |
if ($active.length) { | |
that.sortBy = $active.attr(SORT_BY_ATTR); | |
that.orderBy = $active.attr(ORDER_BY_ATTR); | |
if (that.orderBy === 'desc') { | |
$active.find('.' + INDICATOR_CLASS).removeClass([SORT_ICON_CLASS, UP_ICON_CLASS].join(' ')).addClass(DOWN_ICON_CLASS); | |
} | |
$active.addClass(ACTIVE_CLASS); | |
} | |
that.$_active = $active; | |
// Add class to wrapper | |
that.$el.addClass(WRAPPER_CLASS); | |
} | |
}, 'Sortable'); | |
Stackla.smartBind({ | |
pluginName: NAME, | |
selector: SELECTOR, | |
classFn: Stackla.Sortable, | |
autoBind: true | |
}); | |
module.exports = Stackla.Sortable; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var React = require('react'), | |
LogMixin = require('js/common/log-mixin'); | |
module.exports = React.createClass({ | |
mixins: [LogMixin], | |
toString: function () { | |
return 'Sortable'; | |
}, | |
propTypes: { | |
active: React.PropTypes.bool, | |
disabled: React.PropTypes.bool, | |
orderBy: React.PropTypes.string, | |
orderBydirection: React.PropTypes.string, | |
onClick: React.PropTypes.func | |
}, | |
getDefaultProps: function () { | |
return { | |
active: false, | |
disabled: false, | |
orderBy: 'id', | |
orderByDirection: 'desc' | |
} | |
}, | |
handleClick: function (orderBy, orderByDirection) { | |
var that = this; | |
that.log('handleClick() is executed'); | |
that.props.onClick(orderBy, orderByDirection); | |
}, | |
render: function () { | |
var that = this, | |
props = that.props, | |
linkProps = (props.disabled) ? {disabled: 'disabled'} : {}, | |
direction = (props.orderByDirection === 'asc') ? 'up' : 'down', | |
className = 'Sortable', | |
iconClassName = ['Sortable-indicator'], | |
nextDirection = props.orderByDirection; | |
that.log('render() is executed'); | |
if (props.active) { | |
nextDirection = (props.orderByDirection === 'asc') ? 'desc' : 'asc'; | |
className += ' is-active'; | |
iconClassName.push('fs', 'fs-arrow-' + direction + '5'); | |
} else { | |
iconClassName.push('fs', 'fs-sort'); | |
} | |
return ( | |
<a {...linkProps} href="javascript:void(0)" className={className} | |
onClick={that.handleClick.bind(that, props.orderBy, nextDirection)}> | |
{props.children}{' '} | |
<i className={iconClassName.join(' ')}></i> | |
</a> | |
); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment