intercellular / cell

A self-driving web app framework
https://www.celljs.org
MIT License
1.51k stars 94 forks source link

Break out createElementNS(Hardcoded) into Monkey-Patchable Function - GeneReader ? #169

Open Corwin-Coderonin opened 6 years ago

Corwin-Coderonin commented 6 years ago

In the Cell code is this part hardcoded:

  if (model.$type === 'svg') {
    $node = $root.document.createElementNS('http://www.w3.org/2000/svg', model.$type);
    meta.namespace = $node.namespaceURI;
  } else if (namespace) {
    $node = $root.document.createElementNS(namespace, model.$type);
    meta.namespace = $node.namespaceURI;

which is intended to allow feeding the externally described object structure via XML. Edge cases might be a CD-distributed web technology app utilizing Electron running on a machine not connected or similar things, which could create problems if targeting offline first or feeding in on XML-descriptions or one wanted to implement object caching for objects with elaborate definitions. Hard coded URI seems not right in a library ;-)

Possible solutions - not growing size too much - I thought about revolved around ways to monkey-patch URI and/or object creation strategy. Probably 95% never use createElementNS(), so having 1 or 2 function calls more executing on the stack will not matter for them at all, but those few who actually call into using createElementNS() AND running into problems then can modify Cell behaviour without changing Cell sources - this keeps codesize small for all users.

Idea 1:

PatchableFuncURI = function (type, namesp) {
  return type === 'svg' ? 'http://www.w3.org/2000/svg' : namesp;
};
///
      if ((model.$type === 'svg')  || (namespace)){
        $node = $root.document.createElementNS(?.PatchableFuncURI(model.$type, namespace), model.$type);
        meta.namespace = $node.namespaceURI;

gives dev the option to overwrite the namespace fed into createElementNS(), perhaps redirecting it into file:// or elsewhere local (perhaps there is a local JETTY server service running, which some VAADIN including packages argue for for powerful mobile devices), while still keeping the current default behaviour working for almost all cases.

idea 2:

PatchableFuncCreate = function (type, namesp) {
  return $root.document.createElementNS(type === 'svg' ? 'http://www.w3.org/2000/svg' : namesp, type);
};
///
      if ((model.$type === 'svg')  || (namespace)){
        $node = ?.PatchableFuncCreate(model.$type, namespace);
        meta.namespace = $node.namespaceURI;

allows dev to implement enhancent strategies (redirect, cache and so on), still with about the same bytecount as original (mostly dependant on length of names used to implement) ;-) Consider an object taking some time to create from XML - it might be better to cache it somewhere and use it as the prototype of many other objects needed from same blueprint or use a faster deepcopy method to create new elements from it. Of course simply changing the URI as in idea 1 is possible in the monkey-patched replacement - the dev might write a few functions fitting each needed use case and monkey-patch with correct function for the need currently at hand.

The Rolls-Royce version allowing minute changes to both

PatchableFuncURI = function (type, namesp) {
  return type === 'svg' ? 'http://www.w3.org/2000/svg' : namesp;
};
PatchableFuncCreate = function (type, namesp) {
  return $root.document.createElementNS(?.PatchableFuncURI(type, namesp));
};
///
      if ((model.$type === 'svg')  || (namespace)){
        $node = ?.PatchableFuncCreate(model.$type, namespace);
        meta.namespace = $node.namespaceURI;

adds between 60 and 100 bytes of source - probably better to keep Cell small via idea 2 and ask developer needing to monkey patch to perhaps create different functions himself and pick the one fit for the use case at hand to attach to the hook Cell would offer.

I will try to add my thoughts on technical ways/options to empower users of Cell on #111, including the pros/cons I see with allowing users to monkey-patch some functions. Might take a bit, but will keep the mostly technical issue here free from architecture discussion more fitting in the other thread.

gliechtenstein commented 6 years ago

I think this is a great idea. As for the implementation, I think option2 is a bit better than option1 because it looks more flexible. I don't think we need to provide both since I think you can do pretty much everything with option2, right?