diff options
| -rw-r--r-- | CHANGELOG.md | 2 | ||||
| -rw-r--r-- | src/markups.js | 17 | ||||
| -rw-r--r-- | src/sanitizer.js | 6 | ||||
| -rw-r--r-- | test/markupSpec.js | 36 | ||||
| -rw-r--r-- | test/sanitizerSpec.js | 46 |
5 files changed, 96 insertions, 11 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a6ca359..5a4b4e9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # <angular/> 0.9.11 snow-maker (in-progress) # +### Bug Fixes +- <option> value attribute gets clobbered when the element contains new line character(s). # <angular/> 0.9.10 flea-whisperer (2011-01-26) # diff --git a/src/markups.js b/src/markups.js index 21dab128..0aa7170e 100644 --- a/src/markups.js +++ b/src/markups.js @@ -60,11 +60,18 @@ angularTextMarkup('{{}}', function(text, textNode, parentElement) { // TODO: this should be widget not a markup angularTextMarkup('OPTION', function(text, textNode, parentElement){ if (nodeName_(parentElement) == "OPTION") { - var select = document.createElement('select'); - select.insertBefore(parentElement[0].cloneNode(true), _null); - if (!select.innerHTML.match(/<option(\s.*\s|\s)value\s*=\s*.*>.*<\/\s*option\s*>/gi)) { - parentElement.attr('value', text); - } + var select = jqLite('<select>'); + select.append(parentElement.clone()); + htmlParser(select.html(), { + start: function(tag, attrs) { + if (isUndefined(attrs.value)) { + parentElement.attr('value', text); + } + }, + chars: noop, + end: noop, + comment: noop + }); } }); diff --git a/src/sanitizer.js b/src/sanitizer.js index c8a7b9f1..8f4b87a6 100644 --- a/src/sanitizer.js +++ b/src/sanitizer.js @@ -15,9 +15,9 @@ */ // Regular Expressions for parsing tags and attributes -var START_TAG_REGEXP = /^<\s*([\w:]+)((?:\s+\w+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, - END_TAG_REGEXP = /^<\s*\/\s*([\w:]+)[^>]*>/, - ATTR_REGEXP = /(\w+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, +var START_TAG_REGEXP = /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, + END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, BEGIN_TAG_REGEXP = /^</, BEGING_END_TAGE_REGEXP = /^<\s*\//, COMMENT_REGEXP = /<!--(.*?)-->/g, diff --git a/test/markupSpec.js b/test/markupSpec.js index f78112d7..f629378d 100644 --- a/test/markupSpec.js +++ b/test/markupSpec.js @@ -41,9 +41,39 @@ describe("markups", function(){ expect(element.attr('src')).toEqual("http://server/a/b.png"); }); - it('should populate value attribute on OPTION', function(){ - compile('<select name="x"><option>a</option></select>'); - expect(sortedHtml(element).replace(' selected="true"', '')).toEqual('<select name="x"><option value="a">a</option></select>'); + describe('OPTION value', function(){ + beforeEach(function(){ + this.addMatchers({ + toHaveValue: function(expected){ + this.message = function(){ + return 'Expected "' + sortedHtml(this.actual) + '" to have value="' + expected + '".'; + }; + + return this.actual.html().indexOf('value="' + expected + '"') != -1; + } + }); + }); + + it('should populate value attribute on OPTION', function(){ + compile('<select name="x"><option>abc</option></select>'); + expect(element).toHaveValue('abc'); + }); + + it('should ignore value if already exists', function(){ + compile('<select name="x"><option value="abc">xyz</option></select>'); + expect(element).toHaveValue('abc'); + }); + + it('should set value even if newlines present', function(){ + compile('<select name="x"><option attr="\ntext\n" \n>\nabc\n</option></select>'); + expect(element).toHaveValue('\nabc\n'); + }); + + it('should set value even if self closing HTML', function(){ + compile('<select name="x"><option>\n</option></select>'); + expect(element).toHaveValue('\n'); + }); + }); it('should bind href', function() { diff --git a/test/sanitizerSpec.js b/test/sanitizerSpec.js index 57eedec9..7158fbee 100644 --- a/test/sanitizerSpec.js +++ b/test/sanitizerSpec.js @@ -4,6 +4,52 @@ describe('HTML', function(){ return expect(new HTML(html).get()); } + describe('htmlParser', function(){ + var handler, start, text; + beforeEach(function(){ + handler = { + start: function(tag, attrs, unary){ + start = { + tag: tag, + attrs: attrs, + unary: unary + }; + }, + chars: function(text_){ + text = text_; + }, + end:function(tag) { + expect(tag).toEqual(start.tag); + } + }; + }); + + it('should parse basic format', function(){ + htmlParser('<tag attr="value">text</tag>', handler); + expect(start).toEqual({tag:'tag', attrs:{attr:'value'}, unary:false}); + expect(text).toEqual('text'); + }); + + it('should parse newlines in tags', function(){ + htmlParser('<\ntag\n attr="value"\n>text<\n/\ntag\n>', handler); + expect(start).toEqual({tag:'tag', attrs:{attr:'value'}, unary:false}); + expect(text).toEqual('text'); + }); + + it('should parse newlines in attributes', function(){ + htmlParser('<tag attr="\nvalue\n">text</tag>', handler); + expect(start).toEqual({tag:'tag', attrs:{attr:'\nvalue\n'}, unary:false}); + expect(text).toEqual('text'); + }); + + it('should parse namespace', function(){ + htmlParser('<ns:t-a-g ns:a-t-t-r="\nvalue\n">text</ns:t-a-g>', handler); + expect(start).toEqual({tag:'ns:t-a-g', attrs:{'ns:a-t-t-r':'\nvalue\n'}, unary:false}); + expect(text).toEqual('text'); + }); + + }); + it('should echo html', function(){ expectHTML('hello<b class="1\'23" align=\'""\'>world</b>.'). toEqual('hello<b class="1\'23" align="""">world</b>.'); |
