diff --git a/packages/preserve-inputs/labeler.js b/packages/preserve-inputs/labeler.js new file mode 100644 index 0000000000..2fe0217f2c --- /dev/null +++ b/packages/preserve-inputs/labeler.js @@ -0,0 +1,38 @@ +PreserveInputs = {}; + +PreserveInputs.idNameLabeler = function(n) { + var label = null; + + if (n.nodeType === 1) { + if (n.id) { + label = '#' + n.id; + } else if (n.getAttribute("name")) { + label = n.getAttribute("name"); + // Radio button special case: radio buttons + // in a group all have the same name. Their value + // determines their identity. + // Checkboxes with the same name and different + // values are also sometimes used in apps, so + // we treat them similarly. + if (n.nodeName === 'INPUT' && + (n.type === 'radio' || n.type === 'checkbox') && + n.value) + label = label + ':' + n.value; + + // include parent names and IDs up to enclosing ID + // in the label + while (n.parentNode && + n.parentNode.nodeType === 1) { // ELEMENT + n = n.parentNode; + if (n.id) { + label = '#' + n.id + "/" + label; + break; + } else if (n.getAttribute('name')) { + label = n.getAttribute('name') + "/" + label; + } + } + } + } + + return label; +}; diff --git a/packages/preserve-inputs/package.js b/packages/preserve-inputs/package.js new file mode 100644 index 0000000000..1cc41f59fe --- /dev/null +++ b/packages/preserve-inputs/package.js @@ -0,0 +1,12 @@ +Package.describe({ + summary: "Preserve inputs and other form elements by ID" +}); + +Package.on_use(function (api, where) { + api.use(['underscore', 'spark', 'templating']); + api.add_files(["labeler.js", "preserve-inputs.js"], "client"); +}); + +/*Package.on_test(function (api) { + api.add_files('labeler.js', 'client'); +});*/ diff --git a/packages/preserve-inputs/preserve-inputs.js b/packages/preserve-inputs/preserve-inputs.js new file mode 100644 index 0000000000..e44dae3acf --- /dev/null +++ b/packages/preserve-inputs/preserve-inputs.js @@ -0,0 +1,9 @@ + +(function () { + var inputTags = 'input textarea button select option'.split(' '); + var selector = _.map(inputTags, function (t) { + return t.replace(/^.*$/, '$&[id], $&[name]'); + }).join(', '); + + Spark._globalPreserves[selector] = PreserveInputs.idNameLabeler; +})(); diff --git a/packages/spark/spark.js b/packages/spark/spark.js index e3cc7064f7..6706254e86 100644 --- a/packages/spark/spark.js +++ b/packages/spark/spark.js @@ -60,6 +60,8 @@ Spark._ANNOTATION_LIST_ITEM = "item"; // Set in tests to turn on extra UniversalEventListener sanity checks Spark._checkIECompliance = false; +Spark._globalPreserves = {}; + var makeRange = function (type, start, end, inner) { var range = new LiveRange(Spark._TAG, start, end, inner); range.type = type; @@ -575,6 +577,8 @@ Spark.renderToRange = function (range, htmlFunc) { while ((walk = findParentOfType(Spark._ANNOTATION_LANDMARK, walk))) pc.addRoot(walk.preserve, range, tempRange, walk.containerNode()); + pc.addRoot(Spark._globalPreserves, range, tempRange); + // compute preservations (must do this before destroying tempRange) var preservations = pc.computePreservations(range, tempRange);