diff --git a/app/assets/javascripts/pretty-text/engines/markdown-it/bbcode-block.js.es6 b/app/assets/javascripts/pretty-text/engines/markdown-it/bbcode-block.js.es6 index 51050f9206d..db00edbea7e 100644 --- a/app/assets/javascripts/pretty-text/engines/markdown-it/bbcode-block.js.es6 +++ b/app/assets/javascripts/pretty-text/engines/markdown-it/bbcode-block.js.es6 @@ -11,6 +11,8 @@ function trailingSpaceOnly(src, start, max) { return true; } +const ATTR_REGEX = /(([a-z0-9]*)\s*=)/ig; + // parse a tag [test a=1 b=2] to a data structure // {tag: "test", attrs={a: "1", b: "2"} export function parseBBCodeTag(src, start, max, multiline) { @@ -71,31 +73,23 @@ export function parseBBCodeTag(src, start, max, multiline) { // trivial parser that is going to have to be rewritten at some point if (raw) { - // reading a key 0, reading a val = 1 - let readingKey = true; - let startSplit = 0; - let key; + let match, key, val; - for(i=0; i<raw.length; i++) { - if (raw[i] === '=' || i === (raw.length-1)) { - // one more offset to allow room to capture last - if (raw[i] !== '=' || i === (raw.length-1)) { - i+=1; - } - - let cur = raw.slice(startSplit, i).trim(); - if (readingKey) { - key = cur || '_default'; - } else { - let val = raw.slice(startSplit, i).trim(); - if (val && val.length > 0) { - val = val.replace(/^["'](.*)["']$/, '$1'); - attrs[key] = val; - } - } - readingKey = !readingKey; - startSplit = i+1; + while(match = ATTR_REGEX.exec(raw)) { + if (key) { + val = raw.slice(attrs[key],match.index) || ''; + val = val.trim(); + val = val.replace(/^["'](.*)["']$/, '$1'); + attrs[key] = val; } + key = match[2] || '_default'; + attrs[key] = match.index + match[0].length; + } + + if (key) { + val = raw.slice(attrs[key]); + val = val.replace(/^["'](.*)["']$/, '$1'); + attrs[key] = val; } } diff --git a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 index b7b41648e1e..65de3ce659b 100644 --- a/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 +++ b/plugins/poll/assets/javascripts/lib/discourse-markdown/poll.js.es6 @@ -127,7 +127,7 @@ const rule = { WHITELISTED_ATTRIBUTES.forEach(name => { if (attrs[name]) { - attributes[DATA_PREFIX + name] = attrs[name]; + attributes.push([DATA_PREFIX + name, attrs[name]]); } }); @@ -136,9 +136,9 @@ const rule = { } // we might need these values later... - let min = parseInt(attributes[DATA_PREFIX + "min"], 10); - let max = parseInt(attributes[DATA_PREFIX + "max"], 10); - let step = parseInt(attributes[DATA_PREFIX + "step"], 10); + let min = parseInt(attrs["min"], 10); + let max = parseInt(attrs["max"], 10); + let step = parseInt(attrs["step"], 10); let header = []; @@ -157,7 +157,7 @@ const rule = { header.push(token); // generate the options when the type is "number" - if (attributes[DATA_PREFIX + "type"] === "number") { + if (attrs["type"] === "number") { // default values if (isNaN(min)) { min = 1; } if (isNaN(max)) { max = md.options.discourse.pollMaximumOptions; } @@ -172,7 +172,7 @@ const rule = { header.push(token); for (let o = min; o <= max; o += step) { - token = new state.Token('list_item_open', '', 1); + token = new state.Token('list_item_open', 'li', 1); items.push([token, String(o)]); header.push(token); @@ -180,7 +180,7 @@ const rule = { token.content = String(o); header.push(token); - token = new state.Token('list_item_close', '', -1); + token = new state.Token('list_item_close', 'li', -1); header.push(token); } token = new state.Token('bullet_item_close', '', -1); diff --git a/plugins/poll/spec/lib/pretty_text_spec.rb b/plugins/poll/spec/lib/pretty_text_spec.rb index 417a2989f4f..083a9b2d9f4 100644 --- a/plugins/poll/spec/lib/pretty_text_spec.rb +++ b/plugins/poll/spec/lib/pretty_text_spec.rb @@ -12,6 +12,34 @@ describe PrettyText do SiteSetting.enable_experimental_markdown_it = true end + it 'supports multi choice polls' do + cooked = PrettyText.cook <<~MD + [poll type=multiple min=1 max=3 public=true] + * option 1 + * option 2 + * option 3 + [/poll] + MD + + expect(cooked).to include('class="poll"') + expect(cooked).to include('data-poll-status="open"') + expect(cooked).to include('data-poll-name="poll"') + expect(cooked).to include('data-poll-type="multiple"') + expect(cooked).to include('data-poll-min="1"') + expect(cooked).to include('data-poll-max="3"') + expect(cooked).to include('data-poll-public="true"') + end + + it 'can dynamically generate a poll' do + + cooked = PrettyText.cook <<~MD + [poll type=number min=1 max=20 step=1] + [/poll] + MD + + expect(cooked.scan('<li').length).to eq(20) + end + it 'can properly bake 2 polls' do md = <<~MD this is a test @@ -88,7 +116,7 @@ describe PrettyText do cooked = PrettyText.cook md expected = <<~MD - <div class="poll" data-poll-status="open" data-poll-name="poll"> + <div class="poll" data-poll-status="open" data-poll-name="poll" data-poll-type="multiple"> <div> <div class="poll-container"> <ol> diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb index 3c4089d058f..ea6c749d5d6 100644 --- a/spec/components/pretty_text_spec.rb +++ b/spec/components/pretty_text_spec.rb @@ -908,7 +908,6 @@ HTML <img src="http://png.com/my.png" alt="stuff"><br> <img src="http://png.com/my.png" alt width="110" height="50"></p> HTML - puts cooked expect(cooked).to eq(html.strip) end