app/scripts/ui-lib/widgets/sort.coffee

Sort

The Sort class provides a sorting widget.

author: Julien Ramboz version: 1.0 usage: Sort examples

AMD loader

Try loading as AMD module or fall back to default loading

((widget) -> if typeof define is "function" and define.amd define ["jslib", "core", "widget"], widget else widget @$, _, _.AbstractWidget ) toolbar = ($, _, AbstractWidget) -> "use strict"

Widget

The actual widget class

class SortElements extends AbstractWidget

Default options for the widget

@defaultOptions:
  • triggers: a selector pointing to the sort triggers
triggers: ""
  • items: a selector pointing to the items
items: ""

Initialisation

Initializer function.

initialize: (options) -> super options @triggers = @findTriggers() @items = @findItems() sortFunction = (ascending, selector, value = (($v) -> $v.toString())) -> compare = (a, b) -> valA = value(if selector then $(selector, a) else $(a)) valB = value(if selector then $(selector, b) else $(b)) if valA < valB then 1-ascending*2 else ascending*2-1 @sorters = "text": (ascending, selector) -> sortFunction(ascending, selector, (($v) -> $v.text().toLowerCase())) "numeric-eu": (ascending, selector) -> sortFunction(ascending, selector, (($v) -> parseFloat($v.text().replace(/[' ]/g, "").replace(/,/g, ".")))) "numeric": (ascending, selector) -> sortFunction(ascending, selector, (($v) -> parseFloat($v.text().replace(/[, ]/g, "")))) "date": (ascending, selector) -> sortFunction(ascending, selector, (($v) -> Date.parse($v.text()))) $.extend @sorters, options.sorters

Accessibility markup

Add aria attributes

aria: () -> super() @triggers.attr("data-role", "sort-trigger").each () -> if this.nodeName isnt "TH" this.setAttribute("role", "columnheader") parent = @triggers.parent().get(0) parent.setAttribute("role", "row") if this.nodeName isnt "TR" @items.attr("data-role", "sort-items").each () -> if this.nodeName isnt "TD" this.setAttribute("role", "gridcell") if this.parentNode.nodeName isnt "TR" this.parentNode.setAttribute("role", "row") group = @items.parents(":not([role='row'])").get(0) group.setAttribute("role", "rowgroup") if group.nodeName isnt "TBODY" @element.attr "role": "grid" "aria-readonly": "true"

Event handling

Attach evenets to the widget

bindEvents: () -> @element.on "click", "[data-role='sort-trigger']", (e) => return if e.target.getAttribute("aria-disabled") is "true" type = @getType(e.target) order = @getOrder(e.target) selector = @getSelector(e.target) @triggers.removeAttr("aria-sort") e.target.setAttribute("aria-sort", if order isnt "ascending" then "ascending" else "descending") @sort type, order isnt "ascending", selector

Sort the items

sort: (type, ascending, selector) -> sorter = @sorters[type](ascending, selector) $parent = @items.parent() @items.sort sorter @items.detach() $parent.append(@items)

Structure discovery

Find the widget structure using the specified configuration

Sort triggers

Find the sorting triggers, specified in one of the following ways:

  • elements with data-role="sort-trigger"
  • using triggers option, specified as a selector
  • using thead th, if the widget contains a table
findTriggers: () -> $triggers = @element.find("[data-role='sort-trigger']") return $triggers if $triggers.length return $triggers = $(@options.triggers, @element) if @options.triggers $triggers = @element.find("thead th") return $triggers if $triggers.length $()

Sort items

Find the sort items, specified in one of the following ways:

  • elements with data-role="sort-item"
  • using items option, specified as a selector
  • using tbody tr, if the widget contains a table
  • using li, if the widget contains a list
findItems: () -> $items = @element.find("[data-role='sort-item']") return $items if $items.length return $items = $(@options.items, @element) if @options.items $items = @element.find("tbody tr") return $items if $items.length $items = @element.find("li") return $items if $items.length $()

Get the selector for a specific item. Its value will be used for the comparison instead of that of the item.

  • elements specified by the data-selector on the sort-trigger
  • td with the same index as the th in the context of a table
getSelector: (trigger) -> $selector = $(trigger).get(0).getAttribute "data-selector" return $item.find($selector) if $selector if trigger.nodeName is "TH" return ":nth-child(#{@triggers.index(trigger)+1})"

Get the data type to use for a specific trigger

getType: (trigger) -> $(trigger).get(0).getAttribute("data-type") or "text"

Get sort order

getOrder: (trigger) -> $(trigger).get(0).getAttribute("aria-sort")

Key handling

Cleanup

Cleanup the widget and remove remaining references

destructor: () ->

Installation

Install the widget into the JS library

SortElements.install("SortElements", () -> $("[data-widget='sort']")["#{_.namespace}sortelements"]() )