@@ -31,12 +31,15 @@ define(function (require, exports, module) {
3131 var CodeMirror = require ( "thirdparty/CodeMirror2/lib/codemirror" ) ,
3232 TokenUtils = require ( "utils/TokenUtils" ) ;
3333
34- //constants
34+ // Constants
3535 var TAG_NAME = "tagName" ,
3636 CLOSING_TAG = "closingTag" ,
3737 ATTR_NAME = "attr.name" ,
3838 ATTR_VALUE = "attr.value" ;
3939
40+ // Regular expression for token types with "tag" prefixed
41+ var tagPrefixedRegExp = / ^ t a g / ;
42+
4043 /**
4144 * @private
4245 * Sometimes as attr values are getting typed, if the quotes aren't balanced yet
@@ -114,7 +117,13 @@ define(function (require, exports, module) {
114117 var mode = ctx . editor . getMode ( ) ,
115118 innerModeData = CodeMirror . innerMode ( mode , ctx . token . state ) ;
116119
117- return innerModeData . state . tagName ;
120+ if ( ctx . token . type === "tag bracket" ) {
121+ return innerModeData . state . tagName ;
122+ }
123+
124+ // If the ctx is inside the tag name of an end tag, innerModeData.state.tagName is
125+ // undefined. So return token string as the tag name.
126+ return innerModeData . state . tagName || ctx . token . string ;
118127 }
119128
120129 /**
@@ -129,8 +138,8 @@ define(function (require, exports, module) {
129138 forwardCtx = $ . extend ( { } , backwardCtx ) ;
130139
131140 if ( editor . getModeForSelection ( ) === "html" ) {
132- if ( backwardCtx . token && backwardCtx . token . type !== "tag" ) {
133- while ( TokenUtils . movePrevToken ( backwardCtx ) && backwardCtx . token . type !== "tag" ) {
141+ if ( backwardCtx . token && ! tagPrefixedRegExp . test ( backwardCtx . token . type ) ) {
142+ while ( TokenUtils . movePrevToken ( backwardCtx ) && ! tagPrefixedRegExp . test ( backwardCtx . token . type ) ) {
134143 if ( backwardCtx . token . type === "error" && backwardCtx . token . string . indexOf ( "<" ) === 0 ) {
135144 break ;
136145 }
@@ -139,7 +148,7 @@ define(function (require, exports, module) {
139148 }
140149 }
141150
142- while ( TokenUtils . moveNextToken ( forwardCtx ) && forwardCtx . token . type !== "tag" ) {
151+ while ( TokenUtils . moveNextToken ( forwardCtx ) && ! tagPrefixedRegExp . test ( forwardCtx . token . type ) ) {
143152 if ( forwardCtx . token . type === "attribute" ) {
144153 // If the current tag is not closed, codemirror may return the next opening
145154 // tag as an attribute. Stop the search loop in that case.
@@ -310,12 +319,12 @@ define(function (require, exports, module) {
310319 tagInfo ,
311320 tokenType ;
312321
313- // check if this is inside a style block.
322+ // Check if this is inside a style block.
314323 if ( editor . getModeForSelection ( ) !== "html" ) {
315324 return createTagInfo ( ) ;
316325 }
317326
318- //check and see where we are in the tag
327+ // Check and see where we are in the tag
319328 if ( ctx . token . string . length > 0 && ! / \S / . test ( ctx . token . string ) ) {
320329
321330 // token at (i.e. before) pos is whitespace, so test token at next pos
@@ -331,8 +340,9 @@ define(function (require, exports, module) {
331340 // pos has whitespace before it and non-whitespace after it, so use token after
332341 ctx . token = testToken ;
333342
334- if ( ctx . token . type === "tag" ||
335- ( ctx . token . type && ctx . token . type . indexOf ( "error" ) !== - 1 ) ) {
343+ // Check whether the token type is one of the types prefixed with "tag"
344+ // (e.g. "tag", "tag error", "tag brackets")
345+ if ( tagPrefixedRegExp . test ( ctx . token . type ) ) {
336346 // Check to see if the cursor is just before a "<" but not in any tag.
337347 if ( ctx . token . string . charAt ( 0 ) === "<" ) {
338348 return createTagInfo ( ) ;
@@ -365,17 +375,17 @@ define(function (require, exports, module) {
365375
366376 if ( ctx . token . type === "comment" ) {
367377 return createTagInfo ( ) ;
368- } else if ( ctx . token . type !== "tag" && ctx . token . string !== "=" ) {
378+ } else if ( ! tagPrefixedRegExp . test ( ctx . token . type ) && ctx . token . string !== "=" ) {
369379 // If it wasn't the tag name, assume it was an attr value
370380 // Also we don't handle the "=" here.
371381 tagInfo = _getTagInfoStartingFromAttrValue ( ctx ) ;
372382
373383 // Check to see if this is the closing of a tag (either the start or end)
374384 // or a comment tag.
375385 if ( ctx . token . type === "comment" ||
376- ( ctx . token . type === "tag" &&
386+ ( tagPrefixedRegExp . test ( ctx . token . type ) &&
377387 ( ctx . token . string === ">" || ctx . token . string === "/>" ||
378- ( ctx . token . string . charAt ( 0 ) === "<" && ctx . token . string . charAt ( 1 ) === "/" ) ) ) ) {
388+ ctx . token . string === "</" ) ) ) {
379389 return createTagInfo ( ) ;
380390 }
381391
@@ -398,28 +408,47 @@ define(function (require, exports, module) {
398408 }
399409 }
400410
401- if ( ctx . token . type === "tag" ||
402- ( ctx . token . type && ctx . token . type . indexOf ( "error" ) !== - 1 ) ) {
403- // Check if the user just typed a white space after "<" that made an existing tag invalid.
404- if ( ctx . token . string . match ( / ^ < \s + / ) && offset !== 1 ) {
405- return createTagInfo ( ) ;
411+ if ( tagPrefixedRegExp . test ( ctx . token . type ) ) {
412+ if ( ctx . token . type !== "tag bracket" ) {
413+ // Check if the user just typed a white space after "<" that made an existing tag invalid.
414+ if ( TokenUtils . movePrevToken ( ctx ) && ! / \S / . test ( ctx . token . string ) ) {
415+ return createTagInfo ( ) ;
416+ }
417+
418+ // Check to see if this is a closing tag
419+ if ( ctx . token . type === "tag bracket" && ctx . token . string === "</" ) {
420+ tokenType = CLOSING_TAG ;
421+ }
422+
423+ // Restore the original ctx by moving back to next context since we call
424+ // movePrevToken above to detect "<" or "</".
425+ TokenUtils . moveNextToken ( ctx ) ;
406426 }
407427
408428 // Check to see if this is the closing of a start tag or a self closing tag
409429 if ( ctx . token . string === ">" || ctx . token . string === "/>" ) {
410430 return createTagInfo ( ) ;
411431 }
412432
413- // Check to see if this is a closing tag
414- if ( ctx . token . string . charAt ( 0 ) === "<" && ctx . token . string . charAt ( 1 ) === "/" ) {
415- return createTagInfo ( CLOSING_TAG , offset - 2 , ctx . token . string . slice ( 2 ) ) ;
416- }
417-
418433 // Make sure the cursor is not after an equal sign or a quote before we report the context as a tag.
419434 if ( ctx . token . string !== "=" && ctx . token . string . match ( / ^ [ " ' ] / ) === null ) {
420435 if ( ! tokenType ) {
421436 tokenType = TAG_NAME ;
422- offset -- ; //need to take off 1 for the leading "<"
437+ if ( ctx . token . type === "tag bracket" ) {
438+ // Check to see if this is a closing tag
439+ if ( ctx . token . string === "</" ) {
440+ tokenType = CLOSING_TAG ;
441+ offset -= 2 ;
442+ } else {
443+ offset = 0 ;
444+ }
445+ // If the cursor is right after the "<" or "</", then
446+ // move context to next one so that _extractTagName
447+ // call below can get the tag name if there is one.
448+ if ( offset === 0 ) {
449+ TokenUtils . moveNextToken ( ctx ) ;
450+ }
451+ }
423452 }
424453
425454 // We're actually in the tag, just return that as we have no relevant
0 commit comments