-4

I would like to take this:

var sneed = { feed: "and", seed: [ "formerly", "chucks" ] };

And produce this:

feed="and" seed="formerly,chucks"

But how? It needs to work in older javascript versions.

My solution:

function arg( d = {} ) { 

        var sl = []; 
        for ( var key in d ) { 
                sl.push( key + '="' + d[key] + '"' );  
        } 
        return sl.join(" "); 
}

The problem is, that this will quickly fail if any " is found within any of the strings, which leads me to ask if there is actually a simpler more straightforward way of doing this.

Thanks.

Anon
  • 2,267
  • 3
  • 34
  • 51
  • Check if any of the values contain `"` and use `'` around the attribute instead of `"`. – Barmar Jun 22 '22 at 23:14
  • The real solution is to not generate HTML in the first place. Create DOM elements and set the attributes directly. – Barmar Jun 22 '22 at 23:15
  • @Barmar If the value is a string, that is simple and straightforward. It gets convoluted as different types are introduced. – Anon Jun 22 '22 at 23:15
  • You're converting it to a string. You can check after the conversion. – Barmar Jun 22 '22 at 23:16
  • Note that if `d[key]` is an object, you'll get `seed="[Object object]"`. If you need to handle that, you'll have to check the type before just concatenating. – Barmar Jun 22 '22 at 23:18
  • @Barmar mmm yeah I see what you are saying. As for "create dom elements", I'm afraid I don't follow. – Anon Jun 22 '22 at 23:19
  • 1
    or just `JSON.stringify` – pilchard Jun 22 '22 at 23:20
  • @Ry- QBS is a build system based on QML, which itself is based on Qt, which is a framework for c++. Anyways, it uses right now a very old version of javascript, old enough that it doesnt support `let` -- In any case, it is useful for building files which is what I am attempting with this. – Anon Jun 22 '22 at 23:23
  • But it supports default arguments to functions? – Barmar Jun 22 '22 at 23:24
  • @Barmar I am by no means a javascript developer, so don't grill me on this. All I know is that it does not error when I use default arguments. It does however when I use ` or let or other modern conventions. – Anon Jun 22 '22 at 23:26
  • @Ry- I don't know if QBS supports the DOM API. – Anon Jun 22 '22 at 23:59

2 Answers2

1

You can escape a string to put it inside an HTML attribute value safely and accurately by replacing the ampersand and quote character with their corresponding HTML entities:

function escapeDoubleQuotedAttributeValue(str) {
    return str.replace(/&/g, "&")
              .replace(/"/g, """);
}

Turning whatever objects you want to support into strings is a separate issue.

function valueToString(value) {
    if (typeof value === 'string') {
        return value;
    }

    if (Object.prototype.toString.call(value) === '[object Array]') {
        return String(value);
    }

    throw new TypeError('Unsupported value');
}

function htmlAttributes(d) {
    var attributes = [];

    for (var key in d) {
        var stringValue = valueToString(d[key]);
        var escapedValue = escapeDoubleQuotedAttributeValue(stringValue);
        attributes.push(key + '="' + escapedValue + '"');
    }

    return attributes.join(" ");
}
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • You need to account for the value type. – Anon Jun 22 '22 at 23:32
  • @Anon: Sorry, that was the change I meant to be pointing out with the paragraph above. Still won’t serialize arbitrary objects faithfully, though, as there was discussion about in the question comments. What is the generated HTML used for? Are you going to need to deserialize back out of it? – Ry- Jun 22 '22 at 23:34
  • When I say general, I mean to say that I am not a fan of advanced website frameworks like react, typescript, or even anything with embedded javascript. I am producing a very plain, minimal site. As to the arbitrary objects, it isnt the end of the world if `[object]` or `undefined` ends up making it into the html, although it would be nice if it threw an error. – Anon Jun 22 '22 at 23:38
  • @Barmar said, "Because there are no escapes in HTML attributes. – ` when I asked him why he didnt just put in `"` -- Does that mean that your code here needs to be fixed? Barmar seemed to imply that you could however use the numberd escape, `"` – Anon Jun 22 '22 at 23:56
  • 1
    @Anon Barmar is just not correct in saying "there are no escapes in HTML attributes". `"` will also work. – Ry- Jun 23 '22 at 00:36
0

Check whether converting the value to a string results in a value containing quotes. If so, use the opposite type of quotes around the attribute value in the HTML string.

if it contains both, use double quotes as the delimiters, and replace any embedded double quotes with ".

function arg(d = {}) {
  var sl = [];
  for (var key in d) {
    var value = d[key].toString();
    var delim;
    if (value.includes('"') && value.includes("'")) {
      value = value.replace(/"/g, '"');
      delim = '"';
    } else if (value.includes('"')) {
      delim = "'";
    } else {
      delim = '"';
    }
    sl.push(key + '=' + delim + value + delim);
  }
  return sl.join(" ");
}

console.log(arg({ feed: "and", seed: [ "formerly", "chucks" ] }));
console.log(arg({ feed: "and", seed: [ 'The "first"', "chucks" ] }));
console.log(arg({ feed: "and", seed: [ "formerly", "chuc'ks" ] }));
console.log(arg({ feed: "and", seed: [ 'for"erly', "chuc'ks" ] }));
Barmar
  • 741,623
  • 53
  • 500
  • 612