guardian / scribe

DEPRECATED: A rich text editor framework for the web platform
http://guardian.github.io/scribe/
Apache License 2.0
3.5k stars 245 forks source link

node.elementHasClass arguments #463

Closed mindplay-dk closed 8 years ago

mindplay-dk commented 8 years ago

What's going on here?

  function elementHasClass(Node, className) {
    return function(node) {
      return (node.nodeType === Node.ELEMENT_NODE && node.className === className)
    }
  }

  function isSelectionMarkerNode(node) {
    return elementHasClass(Node, 'scribe-marker')(node);
  }

  function isCaretPositionNode(node) {
    return elementHasClass(Node, 'caret-position')(node);
  }

  function isNotObservableNode(node) {
    return elementHasClass(Node, 'scribe-not-observable')(node);
  }

Why is Node being passed as an argument?

For the sake of testing?

The test is the only place that function is actually being called from outside - perhaps this was intended as an internal function supporting those other three functions? It's being exported though.

rrees commented 8 years ago

Yes exactly it makes the function work only on it's parameters rather than global state. The base function is the "general" case and the other three are specialisations designed for readability.

mindplay-dk commented 8 years ago

Yes exactly it makes the function work only on it's parameters rather than global state.

Not really - you're still grabbing the Node global in those three functions, so the net result is dependency on the Node global for all of the functions that are actually called from outside.

You might as well simplify:

  function elementHasClass(node, className) {
    return (node.nodeType === Node.ELEMENT_NODE && node.className === className)
  }

  function isSelectionMarkerNode(node) {
    return elementHasClass(node, 'scribe-marker');
  }

  function isCaretPositionNode(node) {
    return elementHasClass(node, 'caret-position');
  }

  function isNotObservableNode(node) {
    return elementHasClass(node, 'scribe-not-observable');
  }

This saves the overhead of creating and executing an extra function on-the-fly for every call to those three functions.

The base function is the "general" case and the other three are specialisations designed for readability.

There is no case where the "general" function is actually used from the outside - it's used only internally by those three functions, all of which depend on the Node global.

If you're concerned about accessing the Node global, perhaps the thing to do is to import it?

Just like you're doing for other global dependencies, such as MutationObserver.

rrees commented 8 years ago

It's a global dependency for the special-case functions not the underlying implementation.

I would generally trade readability for performance overhead. But feel free to attach some performance tests to illustrate the difference, I've been known to change my mind in the past!

mindplay-dk commented 8 years ago

IMO elementHasClass(Node, 'caret-position')(node) looks peculiar.

I find elementHasClass(node, 'caret-position') is much easier to read. (and understand.)

I guess that's a matter of opinion :-)

rrees commented 8 years ago

Learn to love the Curry! (Node)('caret-position')(node) would probably be better but I'm a bit lazy.

mindplay-dk commented 8 years ago

Learn to love the Curry!

Learn to KISS ;-)

  function elementHasClass(Node, className) {
    return function(node) {
      return (node.nodeType === Node.ELEMENT_NODE && node.className === className)
    }
  }

  /* delete redundant functions */

  return {
    isSelectionMarkerNode: elementHasClass(Node, 'scribe-marker'),
    isCaretPositionNode: elementHasClass(Node, 'caret-position'),
    isNotObservableNode: elementHasClass(Node, 'scribe-not-observable'),
    // ...
  }

At least then you're not recreating the functions on every call for no reason.

rrees commented 8 years ago

Yeah, that's a fair improvement.

rrees commented 8 years ago

Tried it today and I the reference to Node in the exports breaks compilation as Node needs to be resolved at compilation.

Lazy is actually better.