Re: [whatwg/dom] Add convenient, ergonomic, performant API for sorting siblings (#586)

One question: on what interface would this method exist?

Would it be on `parentNode`, and automatically apply to all child nodes? What about text nodes or comment nodes? Would they need to be handled by the sort function? Or would the sort function only get element nodes, and other nodes would automatically be dropped from the DOM? Or shunted to the end of the list?

________________________________


> an API that accepts the name of an attribute and sorts by its value (with an optional comparison function if the standard string-sorting algo wasn't sufficient).

You might want to sort by data that isn't stored in attributes (like the text content, or sorting by whether the checkboxes are currently checked).  And the things you're sorting on might be properties of child elements (e.g., when sorting table rows by the data in cells).  Finally, you may have a list of sort values (checked vs unchecked, then alphabetically by content). 

The simplest initial API would take a generic comparison function that is passed two element objects, inside the function, the author could then query child elements, attributes, or properties, and compare them in order.

Example:

```js
container.reorderChildren((el1, el2) => {
/* sort checked items before unchecked,
   then alphabetically by description */
  return (el1.querySelector(".ToDoList__done").checked 
          - el2.querySelector(".ToDoList__done").checked) ||
        (el1.querySelector(".ToDoList__description").textContent 
          - el2.querySelector(".ToDoList__description").textContent );
});
```

A more complex (but easier to optimize) API would take two arrays of functions:

- the first array would define accessor functions, each passed one element object & returning one key value
- the second array would be the comparator functions, which would be passed the key values accessed from two different elements by the matching accessor function. The first comparator to return a non-zero value would determine the relative order of the elements.  Comparators could be left null to use the natural comparison order of whatever data type is used for the key.  (Or, if people would prefer to be consistent with JS Array `sort()`, a null comparator could mean coerce to string and then compare using alphabetical order. But that's less useful.) 

The optimization benefit of this approach, compared to doing it all in a single sort function, is that you'd only run each accessor function (which might include things like `querySelector`, or normalizing strings, or parsing dates) once per element, instead of doing that work for every pairwise comparison.  In addition, for authoring, it makes it easier to dynamically change which keys you are sorting by.

Example of this second API:

```js
const sortingKeys = {
dueDate: (el)=>(new Date( el.querySelector(".ToDoList__dueDate").textContent)),
label: (el)=>(el.querySelector(".ToDoList_description").textContent),
done: (el)=>(el.querySelector(".ToDoList_done").checked),
}
const sortingComparators = {
dueDate: (a, b)=>( (isFinite(a)-isFinite(b)) || (a - b) ),
    //valid dates before invalid, then sort by Date
/* label would sort by default comparator */
done: (a,b)=>(a - b)
    //this would be default comparator if we don't convert boolean to string
}

let sortBy = [done, dueDate, label]; // this would change based on user selections
container.reorderChildrenBy( sortBy.map((key)=>sortingKeys[key]) ,
                             sortBy.map((key)=>sortingComparators[key] ) );

```

(One thing missing from that example is a way to reverse the sort order. Not sure if that should also be part of the API, or if it makes sense to require the author to adjust the comparator functions.)


-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/586#issuecomment-371576688

Received on Thursday, 8 March 2018 18:22:06 UTC