[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/vendor/s9e/text-formatter/src/Plugins/BBCodes/ -> Parser.js (source)

   1  /**
   2  * @type {!Object} Attributes of the BBCode being parsed
   3  */
   4  var attributes;
   5  
   6  /**
   7  * @type {!Object} Configuration for the BBCode being parsed
   8  */
   9  var bbcodeConfig;
  10  
  11  /**
  12  * @type {!string} Name of the BBCode being parsed
  13  */
  14  var bbcodeName;
  15  
  16  /**
  17  * @type {!string} Suffix of the BBCode being parsed, including its colon
  18  */
  19  var bbcodeSuffix;
  20  
  21  /**
  22  * @type {!number} Position of the cursor in the original text
  23  */
  24  var pos;
  25  
  26  /**
  27  * @type {!number} Position of the start of the BBCode being parsed
  28  */
  29  var startPos;
  30  
  31  /**
  32  * @type {!number} Length of the text being parsed
  33  */
  34  var textLen = text.length;
  35  
  36  /**
  37  * @type {!string} Text being parsed, normalized to uppercase
  38  */
  39  var uppercaseText = '';
  40  
  41  matches.forEach(function(m)
  42  {
  43      bbcodeName = m[1][0].toUpperCase();
  44      if (!(bbcodeName in config.bbcodes))
  45      {
  46          return;
  47      }
  48      bbcodeConfig = config.bbcodes[bbcodeName];
  49      startPos     = m[0][1];
  50      pos          = startPos + m[0][0].length;
  51  
  52      try
  53      {
  54          parseBBCode();
  55      }
  56      catch (e)
  57      {
  58          // Do nothing
  59      }
  60  });
  61  
  62  /**
  63  * Add the end tag that matches current BBCode
  64  *
  65  * @return {!Tag}
  66  */
  67  function addBBCodeEndTag()
  68  {
  69      return addEndTag(getTagName(), startPos, pos - startPos);
  70  }
  71  
  72  /**
  73  * Add the self-closing tag that matches current BBCode
  74  *
  75  * @return {!Tag}
  76  */
  77  function addBBCodeSelfClosingTag()
  78  {
  79      var tag = addSelfClosingTag(getTagName(), startPos, pos - startPos);
  80      tag.setAttributes(attributes);
  81  
  82      return tag;
  83  }
  84  
  85  /**
  86  * Add the start tag that matches current BBCode
  87  *
  88  * @return {!Tag}
  89  */
  90  function addBBCodeStartTag()
  91  {
  92      var tag = addStartTag(getTagName(), startPos, pos - startPos);
  93      tag.setAttributes(attributes);
  94  
  95      return tag;
  96  }
  97  
  98  /**
  99  * Parse the end tag that matches given BBCode name and suffix starting at current position
 100  *
 101  * @return {Tag}
 102  */
 103  function captureEndTag()
 104  {
 105      if (!uppercaseText)
 106      {
 107          uppercaseText = text.toUpperCase();
 108      }
 109      var match     = '[/' + bbcodeName + bbcodeSuffix + ']',
 110          endTagPos = uppercaseText.indexOf(match, pos);
 111      if (endTagPos < 0)
 112      {
 113          return null;
 114      }
 115  
 116      return addEndTag(getTagName(), endTagPos, match.length);
 117  }
 118  
 119  /**
 120  * Get the tag name for current BBCode
 121  *
 122  * @return string
 123  */
 124  function getTagName()
 125  {
 126      // Use the configured tagName if available, or reuse the BBCode's name otherwise
 127      return bbcodeConfig.tagName || bbcodeName;
 128  }
 129  
 130  /**
 131  * Parse attributes starting at current position
 132  *
 133  * @return array Associative array of [name => value]
 134  */
 135  function parseAttributes()
 136  {
 137      var firstPos = pos, attrName;
 138      attributes = {};
 139      while (pos < textLen)
 140      {
 141          var c = text[pos];
 142          if (" \n\t".indexOf(c) > -1)
 143          {
 144              ++pos;
 145              continue;
 146          }
 147          if ('/]'.indexOf(c) > -1)
 148          {
 149              return;
 150          }
 151  
 152          // Capture the attribute name
 153          var spn = /^[-\w]*/.exec(text.substr(pos, 100))[0].length;
 154          if (spn)
 155          {
 156              attrName = text.substr(pos, spn).toLowerCase();
 157              pos += spn;
 158              if (pos >= textLen)
 159              {
 160                  // The attribute name extends to the end of the text
 161                  throw '';
 162              }
 163              if (text[pos] !== '=')
 164              {
 165                  // It's an attribute name not followed by an equal sign, ignore it
 166                  continue;
 167              }
 168          }
 169          else if (c === '=' && pos === firstPos)
 170          {
 171              // This is the default param, e.g. [quote=foo]
 172              attrName = bbcodeConfig.defaultAttribute || bbcodeName.toLowerCase();
 173          }
 174          else
 175          {
 176              throw '';
 177          }
 178  
 179          // Move past the = and make sure we're not at the end of the text
 180          if (++pos >= textLen)
 181          {
 182              throw '';
 183          }
 184  
 185          attributes[attrName] = parseAttributeValue();
 186      }
 187  }
 188  
 189  /**
 190  * Parse the attribute value starting at current position
 191  *
 192  * @return string
 193  */
 194  function parseAttributeValue()
 195  {
 196      // Test whether the value is in quotes
 197      if (text[pos] === '"' || text[pos] === "'")
 198      {
 199          return parseQuotedAttributeValue();
 200      }
 201  
 202      // Capture everything up to whichever comes first:
 203      //  - an endline
 204      //  - whitespace followed by a slash and a closing bracket
 205      //  - a closing bracket, optionally preceded by whitespace
 206      //  - whitespace followed by another attribute (name followed by equal sign)
 207      //
 208      // NOTE: this is for compatibility with some forums (such as vBulletin it seems)
 209      //       that do not put attribute values in quotes, e.g.
 210      //       [quote=John Smith;123456] (quoting "John Smith" from post #123456)
 211      var match = /[^\]\n]*?(?=\s*(?:\s\/)?\]|\s+[-\w]+=)/.exec(text.substr(pos));
 212      if (!match)
 213      {
 214          throw '';
 215      }
 216  
 217      var attrValue = match[0];
 218      pos += attrValue.length;
 219  
 220      return attrValue;
 221  }
 222  
 223  /**
 224  * Parse current BBCode
 225  *
 226  * @return void
 227  */
 228  function parseBBCode()
 229  {
 230      parseBBCodeSuffix();
 231  
 232      // Test whether this is an end tag
 233      if (text[startPos + 1] === '/')
 234      {
 235          // Test whether the tag is properly closed and whether this tag has an identifier.
 236          // We skip end tags that carry an identifier because they're automatically added
 237          // when their start tag is processed
 238          if (text[pos] === ']' && bbcodeSuffix === '')
 239          {
 240              ++pos;
 241              addBBCodeEndTag();
 242          }
 243  
 244          return;
 245      }
 246  
 247      // Parse attributes and fill in the blanks with predefined attributes
 248      parseAttributes();
 249      if (bbcodeConfig.predefinedAttributes)
 250      {
 251          for (var attrName in bbcodeConfig.predefinedAttributes)
 252          {
 253              if (!(attrName in attributes))
 254              {
 255                  attributes[attrName] = bbcodeConfig.predefinedAttributes[attrName];
 256              }
 257          }
 258      }
 259  
 260      // Test whether the tag is properly closed
 261      if (text[pos] === ']')
 262      {
 263          ++pos;
 264      }
 265      else
 266      {
 267          // Test whether this is a self-closing tag
 268          if (text.substr(pos, 2) === '/]')
 269          {
 270              pos += 2;
 271              addBBCodeSelfClosingTag();
 272          }
 273  
 274          return;
 275      }
 276  
 277      // Record the names of attributes that need the content of this tag
 278      var contentAttributes = [];
 279      if (bbcodeConfig.contentAttributes)
 280      {
 281          bbcodeConfig.contentAttributes.forEach(function(attrName)
 282          {
 283              if (!(attrName in attributes))
 284              {
 285                  contentAttributes.push(attrName);
 286              }
 287          });
 288      }
 289  
 290      // Look ahead and parse the end tag that matches this tag, if applicable
 291      var requireEndTag = (bbcodeSuffix || bbcodeConfig.forceLookahead),
 292          endTag = (requireEndTag || contentAttributes.length) ? captureEndTag() : null;
 293      if (endTag)
 294      {
 295          contentAttributes.forEach(function(attrName)
 296          {
 297              attributes[attrName] = text.substr(pos, endTag.getPos() - pos);
 298          });
 299      }
 300      else if (requireEndTag)
 301      {
 302          return;
 303      }
 304  
 305      // Create this start tag
 306      var tag = addBBCodeStartTag();
 307  
 308      // If an end tag was created, pair it with this start tag
 309      if (endTag)
 310      {
 311          tag.pairWith(endTag);
 312      }
 313  }
 314  
 315  /**
 316  * Parse the BBCode suffix starting at current position
 317  *
 318  * Used to explicitly pair specific tags together, e.g.
 319  *   [code:123][code]type your code here[/code][/code:123]
 320  *
 321  * @return void
 322  */
 323  function parseBBCodeSuffix()
 324  {
 325      bbcodeSuffix = '';
 326      if (text[pos] === ':')
 327      {
 328          // Capture the colon and the (0 or more) digits following it
 329          bbcodeSuffix = /^:\d*/.exec(text.substr(pos))[0];
 330  
 331          // Move past the suffix
 332          pos += bbcodeSuffix.length;
 333      }
 334  }
 335  
 336  /**
 337  * Parse a quoted attribute value that starts at current offset
 338  *
 339  * @return {!string}
 340  */
 341  function parseQuotedAttributeValue()
 342  {
 343      var quote    = text[pos],
 344          valuePos = pos + 1;
 345      while (1)
 346      {
 347          // Look for the next quote
 348          pos = text.indexOf(quote, pos + 1);
 349          if (pos < 0)
 350          {
 351              // No matching quote. Apparently that string never ends...
 352              throw '';
 353          }
 354  
 355          // Test for an odd number of backslashes before this character
 356          var n = 0;
 357          do
 358          {
 359              ++n;
 360          }
 361          while (text[pos - n] === '\\');
 362  
 363          if (n % 2)
 364          {
 365              // If n is odd, it means there's an even number of backslashes. We can exit this loop
 366              break;
 367          }
 368      }
 369  
 370      // Unescape special characters ' " and \
 371      var attrValue = text.substr(valuePos, pos - valuePos).replace(/\\([\\'"])/g, '$1');
 372  
 373      // Skip past the closing quote
 374      ++pos;
 375  
 376      return attrValue;
 377  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1