PageRenderTime 56ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/netbeans-7.3/web.core.syntax/src/org/netbeans/modules/web/core/syntax/JspSyntaxSupport.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 973 lines | 689 code | 96 blank | 188 comment | 196 complexity | 6698d3aced1a116a42225b3514de5799 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. package org.netbeans.modules.web.core.syntax;
  45. import java.io.File;
  46. import java.util.*;
  47. import java.net.URL;
  48. import java.util.logging.Level;
  49. import java.util.logging.Logger;
  50. import javax.swing.text.BadLocationException;
  51. import javax.swing.text.Document;
  52. import javax.swing.text.EditorKit;
  53. import javax.swing.text.JTextComponent;
  54. import javax.servlet.jsp.tagext.*;
  55. import org.netbeans.api.lexer.Language;
  56. import org.netbeans.api.lexer.TokenHierarchy;
  57. import org.netbeans.api.lexer.TokenSequence;
  58. import org.netbeans.modules.web.core.syntax.completion.api.JspCompletionItem;
  59. import org.netbeans.modules.web.core.syntax.deprecated.ELTokenContext;
  60. import org.netbeans.modules.web.core.syntax.deprecated.JspDirectiveTokenContext;
  61. import org.netbeans.modules.web.core.syntax.deprecated.JspMultiTokenContext;
  62. import org.netbeans.modules.web.core.syntax.deprecated.JspTagTokenContext;
  63. import org.netbeans.modules.web.core.api.JspContextInfo;
  64. import org.netbeans.modules.web.jsps.parserapi.JspParserAPI.JspOpenInfo;
  65. import org.netbeans.spi.editor.completion.CompletionItem;
  66. import org.openide.filesystems.FileAttributeEvent;
  67. import org.openide.filesystems.FileChangeListener;
  68. import org.openide.filesystems.FileEvent;
  69. import org.openide.filesystems.FileObject;
  70. import org.openide.filesystems.FileRenameEvent;
  71. import org.openide.loaders.DataObject;
  72. import org.netbeans.modules.web.jsps.parserapi.JspParserAPI;
  73. import org.netbeans.modules.web.jsps.parserapi.PageInfo;
  74. import org.netbeans.editor.*;
  75. import org.netbeans.editor.ext.ExtSyntaxSupport;
  76. import org.netbeans.editor.ext.java.JavaTokenContext;
  77. import org.netbeans.modules.editor.NbEditorUtilities;
  78. import org.netbeans.modules.html.editor.api.completion.HtmlCompletionItem;
  79. import org.openide.filesystems.FileUtil;
  80. import org.openide.modules.InstalledFileLocator;
  81. import org.openide.text.CloneableEditorSupport;
  82. import org.openide.util.WeakListeners;
  83. /**
  84. *
  85. * @author Petr Jiricka, Petr Nejedly
  86. * @author Marek.Fukala@Sun.COM
  87. */
  88. public class JspSyntaxSupport extends ExtSyntaxSupport implements FileChangeListener {
  89. /** ErrorManager shared by whole module (package) for logging */
  90. static final Logger err =
  91. Logger.getLogger("org.netbeans.modules.web.jspsyntax"); // NOI18N
  92. /* Constants for various contexts in the text from the point of
  93. view of JSP completion.*/
  94. /** Completion context for JSP tags (standard or custom) */
  95. public static final int TAG_COMPLETION_CONTEXT = 1;
  96. /** Completion context for JSP end tags (standard or custom) */
  97. public static final int ENDTAG_COMPLETION_CONTEXT = 2;
  98. /** Completion context for JSP directives */
  99. public static final int DIRECTIVE_COMPLETION_CONTEXT = 3;
  100. /** Completion context for JSP comments */
  101. public static final int COMMENT_COMPLETION_CONTEXT = 4;
  102. /** Completion context for other JSP text - such as body of custom tags
  103. * with TAG_DEPENDENT body content. */
  104. public static final int TEXT_COMPLETION_CONTEXT = 5;
  105. /** Completion context for the content language */
  106. public static final int CONTENTL_COMPLETION_CONTEXT = 6;
  107. /** Completion context for the scripting language */
  108. public static final int SCRIPTINGL_COMPLETION_CONTEXT = 7;
  109. /** Completion context for error */
  110. public static final int ERROR_COMPLETION_CONTEXT = 8;
  111. /** Completion context for expression language */
  112. public static final int EL_COMPLETION_CONTEXT = 9;
  113. private static final String STANDARD_JSP_PREFIX = "jsp"; // NOI18N
  114. /** Data for completion: TreeMap for standard JSP tags
  115. * (tag name, array of attributes). */
  116. private static TagInfo[] standardJspTagDatas;
  117. private static TagInfo[] standardTagTagDatas;
  118. /** Data for completion, when the jsp page is in XML syntax
  119. **/
  120. private static TagInfo[] xmlJspTagDatas;
  121. /** Data for completion, when the tag file is in XML syntax
  122. **/
  123. private static TagInfo[] xmlTagFileTagDatas;
  124. /** Data for completion: TreeMap for JSP directives
  125. * (directive name, array of attributes). */
  126. private static TagInfo[] directiveJspData;
  127. private static TagInfo[] directiveTagFileData;
  128. /** Mapping the URI of tag library -> URL where the help files are.
  129. */
  130. private static HashMap helpMap = null;
  131. private static final TokenID[] JSP_BRACKET_SKIP_TOKENS = new TokenID[] {
  132. JavaTokenContext.LINE_COMMENT,
  133. JavaTokenContext.BLOCK_COMMENT,
  134. JavaTokenContext.CHAR_LITERAL,
  135. JavaTokenContext.STRING_LITERAL,
  136. JspTagTokenContext.ATTR_VALUE,
  137. JspTagTokenContext.COMMENT
  138. };
  139. protected FileObject fobj;
  140. /** Special bracket finder is used when caret is in JSP context */
  141. private boolean useCustomBracketFinder = true;
  142. /** Creates new JspSyntaxSupport */
  143. public static synchronized JspSyntaxSupport get(Document doc) {
  144. JspSyntaxSupport sup = (JspSyntaxSupport)doc.getProperty(JspSyntaxSupport.class);
  145. if(sup == null) {
  146. sup = new JspSyntaxSupport((BaseDocument)doc);
  147. doc.putProperty(JspSyntaxSupport.class, sup);
  148. }
  149. return sup;
  150. }
  151. public JspSyntaxSupport(BaseDocument doc) {
  152. super(doc);
  153. fobj = null;
  154. if (doc != null){
  155. initFileObject();
  156. }
  157. }
  158. private void initFileObject() {
  159. DataObject dobj = NbEditorUtilities.getDataObject(getDocument());
  160. if(dobj != null) {
  161. fobj = NbEditorUtilities.getDataObject(getDocument()).getPrimaryFile();
  162. fobj.addFileChangeListener(WeakListeners.create(FileChangeListener.class, this, fobj));
  163. }
  164. }
  165. public String[] getImports(){
  166. JspParserAPI.ParseResult pre = getParseResult();
  167. if (pre != null){
  168. PageInfo pi = pre.getPageInfo();
  169. if(pi == null) {
  170. //report error but do not break the entire CC
  171. err.log(Level.WARNING, null, new NullPointerException("PageInfo obtained from JspParserAPI.ParseResult is null"));
  172. return null;
  173. }
  174. List<String> imports = pi.getImports();
  175. return imports.toArray(new String[imports.size()]);
  176. }
  177. return null;
  178. }
  179. public boolean isXmlSyntax(){
  180. JspContextInfo jspCO = JspContextInfo.getContextInfo(fobj);
  181. if(jspCO == null) {
  182. return false;
  183. }
  184. JspOpenInfo jspOpenInfo = jspCO.getCachedOpenInfo(fobj, false);
  185. if(jspOpenInfo == null) {
  186. return false;
  187. }
  188. return jspOpenInfo.isXmlSyntax();
  189. }
  190. protected JspParserAPI.ParseResult getParseResult() {
  191. JspParserAPI.ParseResult result = JspUtils.getCachedParseResult(fobj, true, false);
  192. if (result == null) {
  193. result = JspUtils.getCachedParseResult(fobj, false, false);
  194. }
  195. return result;
  196. }
  197. /** Returns a map of prefix -> URI that maps tag libraries on prefixes.
  198. * For the XML syntax this mapping may only be approximate.
  199. */
  200. protected Map getPrefixMapper() {
  201. // PENDING - must also take xmlPrefixMapper into account
  202. JspParserAPI.ParseResult result = getParseResult();
  203. Map prefixMapper = null;
  204. if (result != null && result.getPageInfo() != null) {
  205. //if (result.isParsingSuccess()) {
  206. // PENDING - can we somehow get incomplete parsed information ?
  207. if (result.getPageInfo().getXMLPrefixMapper().size() > 0) {
  208. prefixMapper = result.getPageInfo().getApproxXmlPrefixMapper();
  209. if (prefixMapper.size() == 0){
  210. prefixMapper = result.getPageInfo().getXMLPrefixMapper();
  211. }
  212. prefixMapper.putAll(result.getPageInfo().getJspPrefixMapper());
  213. } else {
  214. prefixMapper = result.getPageInfo().getJspPrefixMapper();
  215. }
  216. //}
  217. }
  218. return prefixMapper;
  219. }
  220. private Map getTagLibraries(boolean requiresFresh) {
  221. //refresh tag libraries mappings - this call causes the WebAppParseSupport to refresh taglibs mapping
  222. getTagLibraryMappings();
  223. //if requiresFresh force the parser to update the parse information for the file
  224. JspParserAPI.ParseResult result = JspUtils.getCachedParseResult(fobj, false, requiresFresh, requiresFresh);
  225. if (result != null) {
  226. PageInfo pi = result.getPageInfo();
  227. if(pi == null) {
  228. //report error but do not break the entire CC
  229. err.log(Level.INFO, null, new NullPointerException("PageInfo obtained from JspParserAPI.ParseResult is null"));
  230. return null;
  231. } else {
  232. return pi.getTagLibraries();
  233. }
  234. }
  235. return null; //an error
  236. }
  237. private TagInfo[] getSortedTagInfos(TagInfo[] tinfos) {
  238. Arrays.sort(tinfos, new Comparator() {
  239. public int compare(Object o1, Object o2) {
  240. TagInfo ti1 = (TagInfo)o1;
  241. TagInfo ti2 = (TagInfo)o2;
  242. String tname1 = (ti1.getDisplayName() == null ? ti1.getTagName() : ti1.getDisplayName());
  243. String tname2 = (ti2.getDisplayName() == null ? ti2.getTagName() : ti2.getDisplayName());
  244. if(tname1 == null || tname2 == null) return 0;
  245. return tname1.compareTo(tname2);
  246. }
  247. @Override
  248. public boolean equals(Object o) {
  249. return o.equals(this);
  250. }
  251. });
  252. return tinfos;
  253. }
  254. private TagLibraryInfo getTagLibrary(String prefix, boolean requiresFresh) {
  255. Map mapper = getPrefixMapper();
  256. if (mapper != null) {
  257. Object uri = mapper.get(prefix);
  258. if (uri != null) {
  259. Map taglibs = getTagLibraries(requiresFresh);
  260. if (taglibs != null) {
  261. return (TagLibraryInfo)taglibs.get(uri);
  262. }
  263. }
  264. }
  265. return null;
  266. }
  267. @Override
  268. protected SyntaxSupport createSyntaxSupport(Class syntaxSupportClass) {
  269. SyntaxSupport support = super.createSyntaxSupport(syntaxSupportClass);
  270. if (support != null)
  271. return support;
  272. EditorKit kit;
  273. // try the content language support
  274. kit = CloneableEditorSupport.getEditorKit("text/html"); //NOI18N
  275. if (kit instanceof BaseKit) {
  276. support = ((BaseKit)kit).createSyntaxSupport(getDocument());
  277. if (support != null)
  278. return support;
  279. }
  280. // try the scripting language support
  281. kit = CloneableEditorSupport.getEditorKit("text/x-java"); //NOI18N
  282. if (kit instanceof BaseKit) {
  283. support = ((BaseKit)kit).createSyntaxSupport(getDocument());
  284. if (support != null)
  285. return support;
  286. }
  287. return null;
  288. }
  289. /** This method decides what kind of completion (html, java, jsp-tag, ...) should be opened
  290. * or whether the completion window should be closed if it is opened.
  291. */
  292. @Override
  293. public int checkCompletion(JTextComponent target, String typedText, boolean visible ) {
  294. char first = typedText.charAt(0); //get typed char
  295. TokenItem item = null; //get token on the cursor
  296. try{
  297. item = getItemAtOrBefore(target.getCaret().getDot());
  298. }catch(BadLocationException e) {
  299. return COMPLETION_HIDE;
  300. }
  301. if (item == null) return COMPLETION_HIDE;
  302. TokenContextPath tcp = item.getTokenContextPath();
  303. if(tcp.contains(JavaTokenContext.contextPath)) {
  304. return COMPLETION_CANCEL; //the JavaCompletionProvider handles this
  305. }
  306. //JSP tag or directive
  307. if(tcp.contains(JspTagTokenContext.contextPath)) {
  308. //need to distinguish tag/end_tag/directive - search back throught the token chain for <%@ , </ or < tokens
  309. TokenItem tracking = item;
  310. //the maxBacktrace number says how far back we are willing to look for
  311. //the start tag tokens <%, </ and < (simply the JSP tag or directive beginning).
  312. //There may happen a situation when user starts to write a tag that the a large
  313. //part of the document behind the cursor is recognized as a jsp tag.
  314. //In such a case typing somewhere in the end of this 'badly' recognized block
  315. //would slow down the typing rapidy due to the backtracking oven a long token chain.
  316. //
  317. //So we suppose that tag has less than 20 attributes (and one attribute-value pair consumes 4 tokens)
  318. int maxBacktrace = 20 * 4;
  319. do {
  320. //test whether the token is not an error token
  321. if(tracking.getTokenID() == JspTagTokenContext.ERROR) return COMPLETION_HIDE;
  322. String image = tracking.getImage();
  323. //System.out.println("tracking: " + tracking);
  324. //this is a case when use types %> which is recognized as a JspTagToken, but before that there are java tokens
  325. if(image.equals("%>")) return COMPLETION_HIDE;
  326. if(tracking.getImage().startsWith("<%")) {
  327. //we are in a directive
  328. if (err.isLoggable(Level.FINE)) err.log(Level.FINE, "DIRECTIVE_COMPLETION_CONTEXT"); // NOI18N
  329. //open completion also in such a case: <%=|
  330. if( !visible && first == '=' && tracking.getImage().equals("<%")) return COMPLETION_POPUP;
  331. if( !visible && first == '%' || first == '@' || first == ' ' ) return COMPLETION_POPUP;
  332. if( visible && first == '=' || first == '>' ) return COMPLETION_HIDE;
  333. return visible ? COMPLETION_POST_REFRESH : COMPLETION_CANCEL;
  334. }
  335. if(tracking.getImage().equals("<")) {
  336. //we are in a tag
  337. if (err.isLoggable(Level.FINE)) err.log(Level.FINE, "TAG_COMPLETION_CONTEXT"); // NOI18N
  338. if( !visible && first == ' ' || first == ':' ) return COMPLETION_POPUP;
  339. if( visible && first == '>' ) return COMPLETION_HIDE;
  340. return visible ? COMPLETION_POST_REFRESH : COMPLETION_CANCEL;
  341. }
  342. if(tracking.getImage().equals("</")) {
  343. //we are in an end tag
  344. if (err.isLoggable(Level.FINE)) err.log(Level.FINE, "ENDTAG_COMPLETION_CONTEXT"); // NOI18N
  345. if( visible && first == '>' ) return COMPLETION_HIDE;
  346. return visible ? COMPLETION_POST_REFRESH : COMPLETION_CANCEL;
  347. }
  348. //test whether we are still in the tag context
  349. if(!tracking.getTokenContextPath().contains(JspTagTokenContext.contextPath)) {
  350. if (err.isLoggable(Level.FINE)) err.log(Level.FINE, "We are out of jsp tag without finding any tag start token!");
  351. break;
  352. }
  353. if(tracking.getImage().equals(">")) {
  354. try {
  355. //check if the cursor is behind an open tag
  356. SyntaxElement se = getElementChain(tracking.getOffset());
  357. if(se != null && (se instanceof SyntaxElement.Tag)) {
  358. return COMPLETION_POPUP;
  359. }
  360. }catch(BadLocationException e) {
  361. //do nothing
  362. }
  363. return COMPLETION_HIDE;
  364. }
  365. //search previous token
  366. tracking = tracking.getPrevious();
  367. } while((maxBacktrace-- > 0) && (tracking != null));
  368. }//eof JSP tag
  369. if(tcp.contains(ELTokenContext.contextPath)) {
  370. if(first == '.') {
  371. return COMPLETION_POPUP;
  372. }
  373. }
  374. return COMPLETION_HIDE;
  375. }
  376. /** Returns offset where the next offset after this offset starts. */
  377. private final int getTokenEnd( TokenItem item ) {
  378. if (item == null)
  379. return 0; //getDocument().getLength();
  380. return item.getOffset() + item.getImage().length();
  381. }
  382. /** Filters list of strings so only strings starting
  383. * with a given prefix are returned in the new List. */
  384. public static final List<Object> filterList(List<? extends Object> toFilter, String prefix) {
  385. List<Object> newList = new ArrayList<Object>();
  386. Object item;
  387. for (int i = 0; i < toFilter.size(); i++) {
  388. item = toFilter.get(i);
  389. String txt;
  390. if (item instanceof TagInfo)
  391. txt = ((TagInfo)item).getTagName();
  392. else if (item instanceof TagAttributeInfo)
  393. txt = ((TagAttributeInfo)item).getName();
  394. else
  395. txt = (String)item;
  396. if (txt != null && txt.startsWith(prefix)) {
  397. newList.add(item);
  398. }
  399. }
  400. return newList;
  401. }
  402. /** Filters list of strings so only strings starting
  403. * with a given prefix are returned in the new List. */
  404. public static final List<String> filterStrings(List<String> toFilter, String prefix) {
  405. List<String> newList = new ArrayList<String>();
  406. for(String val : toFilter) {
  407. if(val.startsWith(prefix)) {
  408. newList.add(val);
  409. }
  410. }
  411. return newList;
  412. }
  413. /** Gets all 'jsp prefixes' whose 'string prefix' matches complPrefix as a list of Strings. */
  414. public final List<Object> getTagPrefixes(String complPrefix) {
  415. return filterList(getAllTagPrefixes(), complPrefix);
  416. }
  417. /** Gets all tags whose 'string prefix' matches complPrefix as a list of Strings.
  418. * Assumes that complPrefix also includes the 'jsp prefix'.
  419. */
  420. public final List getTags(String complPrefix) {
  421. int colonIndex = complPrefix.indexOf(":"); // NOI18N
  422. if (colonIndex == -1)
  423. throw new IllegalArgumentException();
  424. return getTags(complPrefix.substring(0, colonIndex),
  425. complPrefix.substring(colonIndex + 1));
  426. }
  427. /** Gets all tags whose 'string prefix' matches complPrefix and whose 'jsp prefix'
  428. * is tagPrefix as a list of Strings.
  429. * Assumes that complPrefix does not include the 'jsp prefix'.
  430. */
  431. public final List getTags(String tagPrefix, String complPrefix) {
  432. return filterList(getAllTags(tagPrefix, true), complPrefix);
  433. }
  434. /** Gets attributes for tag whose prefix + name
  435. * is tagPrefixName as a list of Strings.
  436. * The attribute's 'string prefix' must match complPrefix.
  437. */
  438. public final List getTagAttributes(String tagPrefixName, String complPrefix) {
  439. int colonIndex = tagPrefixName.indexOf(":"); // NOI18N
  440. if (colonIndex == -1)
  441. throw new IllegalArgumentException();
  442. return getTagAttributes(tagPrefixName.substring(0, colonIndex),
  443. tagPrefixName.substring(colonIndex + 1), complPrefix);
  444. }
  445. /** Gets attributes for tag whose 'jsp prefix'
  446. * is tagPrefix and whose tag name is tagName as a list of Strings.
  447. * The attribute's 'string prefix' must match complPrefix.
  448. */
  449. protected final List getTagAttributes(String tagPrefix, String tagName, String complPrefix) {
  450. return filterList(getAllTagAttributes(tagPrefix, tagName), complPrefix);
  451. }
  452. /** Gets all directives whose 'string prefix' matches complPrefix as a list of Strings. */
  453. public final List getDirectives(String complPrefix) {
  454. return filterList(getAllDirectives(), complPrefix);
  455. }
  456. /** Gets attributes for directive <code>directive</code> as a list of Strings.
  457. * The attribute's 'string prefix' must match complPrefix. */
  458. public final List getDirectiveAttributes(String directive, String complPrefix) {
  459. return filterList(getAllDirectiveAttributes(directive), complPrefix);
  460. }
  461. /**
  462. * Returns a list of strings - prefixes available in this support context (JSP file).
  463. */
  464. protected List getAllTagPrefixes() {
  465. List items = new ArrayList();
  466. // jsp: prefix
  467. items.add(STANDARD_JSP_PREFIX);
  468. Map mapper = getPrefixMapper();
  469. if (mapper != null) {
  470. // sort it
  471. TreeSet ts = new TreeSet();
  472. ts.addAll(mapper.keySet());
  473. ts.remove("jsp"); // remove jsp prefix when is declared in xml syntax
  474. items.addAll(ts);
  475. }
  476. // prefixes for tag libraries
  477. /* TagLibParseSupport support = (dobj == null) ?
  478. null : (TagLibParseSupport)dobj.getCookie(TagLibParseSupport.class);
  479. if (support != null) {
  480. // add all prefixes from the support
  481. TagLibParseSupport.TagLibData[] tagLibData = support.getTagLibEditorData().getTagLibData();
  482. for (int i = 0; i < tagLibData.length; i++)
  483. items.add(tagLibData[i].getPrefix());
  484. }
  485. */
  486. return items;
  487. }
  488. /** This method merges tagInfos of tags and file tags from a tagLibrary.
  489. * @param tagLibrary
  490. * @return array of TagInfo of all tags and tag files from the library
  491. * or an empty array of if there is not any tag or tagfile defined in the library.
  492. */
  493. private TagInfo[] getAllTagInfos(TagLibraryInfo tagLibrary) {
  494. // if there is not any tag or file tag, then the empty array is returned
  495. TagInfo[] allTags = new TagInfo[0];
  496. if (tagLibrary != null) {
  497. int tagInfosLength = 0;
  498. int tagAllInfosLength = 0;
  499. TagInfo[] tagInfos = tagLibrary.getTags();
  500. TagFileInfo[] tagFileInfos = tagLibrary.getTagFiles();
  501. if (tagInfos != null) { // it can be null, when the jsp parser finished unexpectedly
  502. tagInfosLength = tagInfos.length;
  503. tagAllInfosLength = tagInfosLength;
  504. }
  505. if (tagFileInfos != null) { // it can be null, when the jsp parser finished unexpectedly
  506. tagAllInfosLength = tagAllInfosLength + tagFileInfos.length;
  507. }
  508. allTags = new TagInfo[tagAllInfosLength];
  509. if (tagInfos != null) {
  510. for (int i = 0; i < tagInfosLength; i++) {
  511. allTags[i] = tagInfos[i];
  512. }
  513. }
  514. if (tagFileInfos != null) {
  515. for (int i = 0; i < tagFileInfos.length; i++) {
  516. allTags[tagInfosLength + i] = tagFileInfos[i].getTagInfo();
  517. }
  518. }
  519. }
  520. return allTags;
  521. }
  522. /** Returns a list of strings - tag names available for a particular prefix.
  523. */
  524. protected List getAllTags(String prefix, boolean requiresFresh) {
  525. List items = new ArrayList();
  526. // standard JSP tags (jsp:)
  527. initCompletionData();
  528. if (STANDARD_JSP_PREFIX.equals(prefix)) {
  529. TagInfo[] stanTagDatas = getTagInfos();
  530. for (int i=0; i<stanTagDatas.length; i++) {
  531. items.add(stanTagDatas[i]);
  532. }
  533. }
  534. TagLibraryInfo info = getTagLibrary(prefix, requiresFresh);
  535. TagInfo[] tags = null;
  536. if (info != null) {
  537. tags = getAllTagInfos(info);
  538. }
  539. if (tags != null) {
  540. tags = getSortedTagInfos(tags);
  541. String url = (String)helpMap.get(info.getURI());
  542. if (url != null && !url.equals("")){
  543. for (int i = 0; i < tags.length; i++) {
  544. items.add(new TagInfo(tags[i].getTagName(),
  545. tags[i].getTagClassName(), tags[i].getBodyContent(),
  546. url + tags[i].getTagName() + ".html#tag-start-" + tags[i].getTagName()
  547. + "#tag-end-" + tags[i].getTagName(), info,
  548. tags[i].getTagExtraInfo(), tags[i].getAttributes(),
  549. tags[i].getDisplayName(), tags[i].getSmallIcon(), tags[i].getLargeIcon(),
  550. tags[i].getTagVariableInfos(), tags[i].hasDynamicAttributes()));
  551. }
  552. } else {
  553. for (int i = 0; i < tags.length; i++) {
  554. items.add(tags[i]);
  555. }
  556. }
  557. }
  558. return items;
  559. }
  560. /** Should be overriden ny subclasses to support JSP 1.1.
  561. * Returns a list of strings - attribute names available for a particular prefix and tag name.
  562. */
  563. protected List getAllTagAttributes(String prefix, String tag) {
  564. List items = new ArrayList();
  565. // attributes for standard JSP tags (jsp:)
  566. initCompletionData();
  567. if (STANDARD_JSP_PREFIX.equals(prefix)) {
  568. TagInfo[] stanTagDatas = getTagInfos();
  569. for (int i=0; i<stanTagDatas.length; i++) {
  570. if (stanTagDatas[i].getTagName().equals(tag)) {
  571. TagAttributeInfo[] attrs = stanTagDatas[i].getAttributes();
  572. for (int j=0; j<attrs.length; j++)
  573. items.add(attrs[j]);
  574. break;
  575. }
  576. }
  577. }
  578. TagLibraryInfo info = getTagLibrary(prefix, true);
  579. if (info != null) {
  580. TagInfo tagInfo = info.getTag(tag);
  581. if (tagInfo == null) {
  582. TagFileInfo tagFile = info.getTagFile(tag);
  583. if (tagFile != null) {
  584. tagInfo = tagFile.getTagInfo();
  585. }
  586. }
  587. if (tagInfo != null) {
  588. TagAttributeInfo[] attributes = tagInfo.getAttributes();
  589. String url = (String)helpMap.get(tagInfo.getTagLibrary().getURI());
  590. if (url != null && !url.equals("")){
  591. for (int i = 0; i < attributes.length; i++) {
  592. items.add(new TagAttributeInfo(attributes[i].getName(),
  593. attributes[i].isRequired(),
  594. url + tagInfo.getTagName() + ".html#attribute-start-" + attributes[i].getName()
  595. + "#attribute-end-" + attributes[i].getName(),
  596. attributes[i].canBeRequestTime(),
  597. attributes[i].isFragment()));
  598. }
  599. } else {
  600. for (int i = 0; i < attributes.length; i++)
  601. items.add(attributes[i]);
  602. }
  603. }
  604. }
  605. return items;
  606. }
  607. /** Should be overriden ny subclasses to support JSP 1.1. */
  608. protected List<TagInfo> getAllDirectives() {
  609. initCompletionData();
  610. List<TagInfo> items = new ArrayList<TagInfo>();
  611. //Is xml syntax? => return nothing.
  612. if (isXmlSyntax()) return items;
  613. TagInfo[] directiveData;
  614. if(NbEditorUtilities.getMimeType(getDocument()).equals(JspUtils.TAG_MIME_TYPE))
  615. directiveData = directiveTagFileData;
  616. else {
  617. directiveData = directiveJspData;
  618. }
  619. for (int i = 0; i < directiveData.length; i++){
  620. items.add(directiveData[i]);
  621. }
  622. return items;
  623. }
  624. /** Should be overriden ny subclasses to support JSP 1.1. */
  625. protected List getAllDirectiveAttributes(String directive) {
  626. initCompletionData();
  627. List items = new ArrayList();
  628. //Is xml syntax? => return nothing.
  629. if (isXmlSyntax()) return items;
  630. TagInfo[] directiveData;
  631. if(NbEditorUtilities.getMimeType(getDocument()).equals(JspUtils.TAG_MIME_TYPE))
  632. directiveData = directiveTagFileData;
  633. else
  634. directiveData = directiveJspData;
  635. for (int i=0; i<directiveData.length; i++) {
  636. if (directiveData[i].getTagName().equals(directive)) {
  637. TagAttributeInfo[] attrs = directiveData[i].getAttributes();
  638. for (int j=0; j<attrs.length; j++)
  639. items.add(attrs[j]);
  640. break;
  641. }
  642. }
  643. return items;
  644. }
  645. public PageInfo.BeanData[] getBeanData() {
  646. JspParserAPI.ParseResult result = getParseResult();
  647. if (result != null) {
  648. PageInfo pageInfo = result.getPageInfo();
  649. //pageInfo can be null in some cases when the parser cannot parse
  650. //the webmodule or the page itself
  651. if(pageInfo != null) {
  652. return pageInfo.getBeans();
  653. }
  654. }
  655. /*TagLibParseSupport support = (dobj == null) ?
  656. null : (TagLibParseSupport)dobj.getCookie(TagLibParseSupport.class);
  657. return support.getTagLibEditorData().getBeanData();*/
  658. return null;
  659. }
  660. public boolean isErrorPage() {
  661. JspParserAPI.ParseResult result = getParseResult();
  662. if (result != null) {
  663. if (result.getPageInfo() != null)
  664. return result.getPageInfo().isErrorPage();
  665. }
  666. /*TagLibParseSupport support = (dobj == null) ?
  667. null : (TagLibParseSupport)dobj.getCookie(TagLibParseSupport.class);
  668. return support.getTagLibEditorData().isErrorPage ();*/
  669. return false;
  670. }
  671. /**
  672. * The mapping of the 'global' tag library URI to the location
  673. * (resource path) of the TLD associated with that tag library.
  674. * The location is returned as a String array:
  675. * [0] The location
  676. * [1] If the location is a jar file, this is the location
  677. * of the tld.
  678. */
  679. public Map getTagLibraryMappings() {
  680. if (fobj == null) {
  681. return null;
  682. }
  683. return JspUtils.getTaglibMap(fobj);
  684. }
  685. private static void initHelp(){
  686. if (helpMap == null){
  687. String url="";
  688. File f = InstalledFileLocator.getDefault().locate("docs/jstl11-doc.zip", "org.netbeans.modules.web.core.syntax", false); //NoI18N
  689. if (f != null){
  690. try {
  691. URL urll = f.toURL();
  692. urll = FileUtil.getArchiveRoot(urll);
  693. url = urll.toString();
  694. } catch (java.net.MalformedURLException e){
  695. err.log(Level.WARNING, null, e);
  696. // nothing to do
  697. }
  698. }
  699. helpMap = new HashMap();
  700. // The URI from the tld file URL, where are the files for the library
  701. helpMap.put("http://java.sun.com/jsp/jstl/core", url + "c/");
  702. helpMap.put("http://java.sun.com/jstl/core", url + "c/");
  703. helpMap.put("http://java.sun.com/jstl/core_rt", url + "c_rt/");
  704. helpMap.put("http://java.sun.com/jsp/jstl/fmt", url + "fmt/");
  705. helpMap.put("http://java.sun.com/jstl/fmt", url + "fmt/");
  706. helpMap.put("http://java.sun.com/jstl/fmt_rt", url + "fmt_rt/");
  707. helpMap.put("http://java.sun.com/jsp/jstl/functions", url + "fn/");
  708. helpMap.put("http://java.sun.com/jstl/functions", url + "fn/");
  709. helpMap.put("http://jakarta.apache.org/taglibs/standard/permittedTaglibs", url+"permittedTaglibs/");
  710. helpMap.put("http://jakarta.apache.org/taglibs/standard/scriptfree", url+ "scriptfree/");
  711. helpMap.put("http://java.sun.com/jsp/jstl/sql", url + "sql/");
  712. helpMap.put("http://java.sun.com/jstl/sql", url + "sql/");
  713. helpMap.put("http://java.sun.com/jstl/sql_rt", url + "sql_rt/");
  714. helpMap.put("http://java.sun.com/jsp/jstl/xml", url + "x/");
  715. helpMap.put("http://java.sun.com/jstl/xml", url + "x/");
  716. helpMap.put("http://java.sun.com/jstl/xml_rt", url + "x_rt/");
  717. f = InstalledFileLocator.getDefault().locate("docs/jsf12-tlddoc.zip", "org.netbeans.modules.web.core.syntax", false); //NoI18N
  718. if (f != null){
  719. try {
  720. URL urll = f.toURL();
  721. urll = FileUtil.getArchiveRoot(urll);
  722. url = urll.toString();
  723. helpMap.put("http://java.sun.com/jsf/html", url + "h/");
  724. helpMap.put("http://java.sun.com/jsf/core", url + "f/");
  725. } catch (java.net.MalformedURLException e){
  726. err.log(Level.WARNING, null, e);
  727. // nothing to do
  728. }
  729. }
  730. f = InstalledFileLocator.getDefault().locate("docs/struts-tags.zip", "org.netbeans.modules.web.core.syntax", false);
  731. if (f != null){
  732. try {
  733. URL urll = f.toURL();
  734. urll = FileUtil.getArchiveRoot(urll);
  735. url = urll.toString();
  736. helpMap.put("http://jakarta.apache.org/struts/tags-bean", url + "bean/");
  737. helpMap.put("http://struts.apache.org/tags-bean", url + "bean/");
  738. helpMap.put("/WEB-INF/struts-bean.tld", url + "bean/");
  739. helpMap.put("http://jakarta.apache.org/struts/tags-html", url + "html/");
  740. helpMap.put("http://struts.apache.org/tags-html", url + "html/");
  741. helpMap.put("/WEB-INF/struts-html.tld", url + "html/");
  742. helpMap.put("http://jakarta.apache.org/struts/tags-logic", url + "logic/");
  743. helpMap.put("http://struts.apache.org/tags-logic", url + "logic/");
  744. helpMap.put("/WEB-INF/struts-logic.tld", url + "logic/");
  745. helpMap.put("http://jakarta.apache.org/struts/tags-nested", url + "nested/");
  746. helpMap.put("http://struts.apache.org/tags-nested", url + "nested/");
  747. helpMap.put("/WEB-INF/struts-nested.tld", url + "nested/");
  748. helpMap.put("http://jakarta.apache.org/struts/tags-tiles", url + "tiles/");
  749. helpMap.put("http://struts.apache.org/tags-tiles", url + "tiles/");
  750. helpMap.put("/WEB-INF/struts-tiles.tld", url + "tiles/");
  751. } catch (java.net.MalformedURLException e){
  752. err.log(Level.WARNING, null, e);
  753. // nothing to do
  754. }
  755. }
  756. }
  757. }
  758. private static void initCompletionData() {
  759. if (helpMap == null)
  760. initHelp();
  761. String url = ""; // NOI18N
  762. if (directiveJspData == null){
  763. directiveJspData = new TagInfo[] {
  764. new TagInfo("include", null, TagInfo.BODY_CONTENT_EMPTY, url+"syntaxref209.html#1003408#8975", null, null, // NOI18N
  765. new TagAttributeInfo[] { new TagAttributeInfo("file", true, url + "syntaxref209.html#16836#10636", false)}), // NOI18N
  766. new TagInfo("page", null, TagInfo.BODY_CONTENT_EMPTY, url+"syntaxref2010.html", null, null, // NOI18N
  767. new TagAttributeInfo[] { new TagAttributeInfo("autoFlush", false, url+"syntaxref2010.html#15673#15675", false), // NOI18N
  768. new TagAttributeInfo("buffer", false, url+"syntaxref2010.html#15671#15673", false), // NOI18N
  769. new TagAttributeInfo("contentType", false, url+"syntaxref2010.html#15683#1001361", false), // NOI18N
  770. new TagAttributeInfo("errorPage", false, url+"syntaxref2010.html#15679#15681", false), // NOI18N
  771. new TagAttributeInfo("extends", false, url+"syntaxref2010.html#15665#16862", false), // NOI18N
  772. new TagAttributeInfo("import", false, url+"syntaxref2010.html#16862#15669", false), // NOI18N
  773. new TagAttributeInfo("info", false, url+"syntaxref2010.html#15677#15679", false), // NOI18N
  774. new TagAttributeInfo("isELIgnored", false, url+"syntaxref2010.html#1011216#18865", false), // NOI18N
  775. new TagAttributeInfo("isErrorPage", false, url+"syntaxref2010.html#15681#15683", false), // NOI18N
  776. new TagAttributeInfo("isThreadSafe", false, url+"syntaxref2010.html#15675#15677", false), // NOI18N
  777. new TagAttributeInfo("language", false, url+"syntaxref2010.html#15663#15665", false), // NOI18N
  778. new TagAttributeInfo("pageEncoding", false, url+"syntaxref2010.html#1001361#1011216", false), // NOI18N
  779. new TagAttributeInfo("session", false, url+"syntaxref2010.html#15669#15671", false)}), // NOI18N
  780. new TagInfo("taglib", null, TagInfo.BODY_CONTENT_EMPTY, url+"syntaxref2012.html#1003416#1002041", null, null, // NOI18N
  781. new TagAttributeInfo[] { new TagAttributeInfo("prefix", true, url+"syntaxref2012.html#1011290#1002041", false), // NOI18N
  782. new TagAttributeInfo("uri", false, url+"syntaxref2012.html#10721#1011294", false), // NOI18N
  783. new TagAttributeInfo("tagdir", false, url + "syntaxref2012.html#1011294#1011290", false)}) // NOI18N
  784. };
  785. }
  786. if (directiveTagFileData == null){
  787. directiveTagFileData = new TagInfo[]{
  788. new TagInfo("attribute", null, TagInfo.BODY_CONTENT_EMPTY, url + "syntaxref208.html", null, null, // NOI18N
  789. new TagAttributeInfo[] { new TagAttributeInfo("description", false, url + "syntaxref208.html#1004672", false), // NOI18N
  790. new TagAttributeInfo("fragment", false, url + "syntaxref208.html#1004657#1004666", false), // NOI18N
  791. new TagAttributeInfo("name", true, url + "syntaxref208.html#1004648#1004655", false), // NOI18N
  792. new TagAttributeInfo("required", false, url + "syntaxref208.html#1004655#1004657", false), // NOI18N
  793. new TagAttributeInfo("rtexprvalue", false, url + "syntaxref208.html#1004666#1004669", false), // NOI18N
  794. new TagAttributeInfo("type", false, url + "syntaxref208.html#1004669#1004672", false)}), // NOI18N
  795. directiveJspData[0],
  796. new TagInfo("tag", null, TagInfo.BODY_CONTENT_EMPTY, url + "syntaxref2011.html", null, null, // NOI18N
  797. new TagAttributeInfo[] { new TagAttributeInfo("body-content", false, url + "syntaxref2011.html#1005164#005172", false), // NOI18N
  798. new TagAttributeInfo("description", false, url + "syntaxref2011.html#1005196#1005198", false), // NOI18N
  799. new TagAttributeInfo("display-name", false, url + "syntaxref2011.html#1005161#1005164", false), // NOI18N
  800. new TagAttributeInfo("dynamic-attributes", false, url + "syntaxref2011.html#005172#1005190", false), // NOI18N
  801. new TagAttributeInfo("example", false, url + "syntaxref2011.html#1005198#1005201", false), // NOI18N
  802. new TagAttributeInfo("import", false, url + "syntaxref2011.html#1005203#1005209", false), // NOI18N
  803. new TagAttributeInfo("isELIgnored", false, url + "syntaxref2011.html#1005214#1005291#1005291", false), // NOI18N
  804. //new TagAttributeInfo("isScriptingEnabled", false, url + "syntaxref2011.html#", false), // NOI18N
  805. new TagAttributeInfo("large-icon", false, url + "syntaxref2011.html#1005193#1005196", false), // NOI18N
  806. new TagAttributeInfo("language", false, url + "syntaxref2011.html#1005201#1005203", false), // NOI18N
  807. new TagAttributeInfo("pageEncoding", false, url + "syntaxref2011.html#1005209#1005214", false), // NOI18N
  808. new TagAttributeInfo("small-icon", false, url + "syntaxref2011.html#1005190#1005193", false)}), // NOI18N
  809. directiveJspData[2],
  810. new TagInfo("variable", null, TagInfo.BODY_CONTENT_EMPTY, url + "syntaxref2013.html#15694#1003563", null, null, // NOI18N
  811. new TagAttributeInfo[] { new TagAttributeInfo("alias", false, url + "syntaxref2013.html#1005914#1005956", false), // NOI18N
  812. new TagAttributeInfo("declare", false, url + "syntaxref2013.html#1006001#1006019", false), // NOI18N
  813. new TagAttributeInfo("description", false, url + "syntaxref2013.html#1005991#1003563", false), // NOI18N
  814. new TagAttributeInfo("name-given", false, url + "syntaxref2013.html#1003561#1005914", false), // NOI18N
  815. new TagAttributeInfo("scope", false, url + "syntaxref2013.html#1006019#1005991", false), // NOI18N
  816. new TagAttributeInfo("variable-class", false, url + "syntaxref2013.html#1005956#1006001", false)}) // NOI18N
  817. };
  818. }
  819. if (standardJspTagDatas == null) {
  820. final String helpFiles = "docs/syntaxref20.zip"; //NoI18N
  821. File f = InstalledFileLocator.getDefault().locate(helpFiles, "org.netbeans.modules.web.core.syntax", true); //NoI18N
  822. if (f != null){
  823. try {
  824. URL urll = f.toURL();
  825. urll = FileUtil.getArchiveRoot(urll);
  826. url = urll.toString();
  827. } catch (java.net.MalformedURLException e){
  828. err.log(Level.WARNING, null, e);
  829. // nothing to do
  830. }
  831. }
  832. standardJspTagDatas = new TagInfo[] {
  833. new TagInfo("attribute", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2014.html", // NOI18N
  834. null, null, new TagAttributeInfo[] { new TagAttributeInfo("name", true, url + "syntaxref2014.html#1003581#1006483", false), // NOI18N
  835. new TagAttributeInfo("trim", false, url + "syntaxref2014.html#1006483#1003583", false)}), // NOI18N
  836. new TagInfo("body", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2015.html#1006731#1003768", // NOI18N
  837. null, null, new TagAttributeInfo[]{}),
  838. new TagInfo("element", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2016.html#1003696#1003708", // NOI18N
  839. null, null, new TagAttributeInfo[] { new TagAttributeInfo("name", true, url + "syntaxref2016.html#1003706#1003708", false)}), // NOI18N
  840. new TagInfo("expression", null, TagInfo.BODY_CONTENT_JSP, url+"syntaxref205.html#1004353#11268", // NOI18N
  841. null, null, new TagAttributeInfo[] {}),
  842. new TagInfo("fallback", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2023.html#11583#19029", // NOI18N
  843. null, null, new TagAttributeInfo[] {}),
  844. new TagInfo("forward", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2018.html#1003349#15708", // NOI18N
  845. null, null, new TagAttributeInfo[] { new TagAttributeInfo("page", true, url + "syntaxref2018.html#15704#15708", true)}), // NOI18N
  846. new TagInfo("getProperty", null, TagInfo.BODY_CONTENT_EMPTY, url + "syntaxref2019.html#8820#9201", // NOI18N
  847. null, null, new TagAttributeInfo[] { new TagAttributeInfo("name", true, url + "syntaxref2019.html#15748#10919", false), // NOI18N
  848. new TagAttributeInfo("property", true, url + "syntaxref2019.html#10919#19482", false)}), // NOI18N
  849. new TagInfo("include", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2020.html#8828#9228", // NOI18N
  850. null, null, new TagAttributeInfo[] { new TagAttributeInfo("flush", true, url + "syntaxref2020.html#17145#18376", false), // NOI18N
  851. new TagAttributeInfo("page", true, url + "syntaxref2020.html#10930#17145", true)}), // NOI18N
  852. new TagInfo("param", null, TagInfo.BODY_CONTENT_EMPTY, url + "syntaxref2023.html#11538#11583", // NOI18N
  853. null, null, new TagAttributeInfo[] { new TagAttributeInfo("name", true, url + "syntaxref2023.html#11538#11583", false), // NOI18N
  854. new TagAttributeInfo("value", true, url + "syntaxref2023.html#11538#11583", true)}), // NOI18N
  855. new TagInfo("params", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2023.html#11538#11583", // NOI18N
  856. null, null, new TagAttributeInfo[] {}),
  857. new TagInfo("plugin", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2023.html#1004158#19029", // NOI18N
  858. null, null, new TagAttributeInfo[] { new TagAttributeInfo("align", false, url + "syntaxref2023.html#11516#11518", false), // NOI18N
  859. new TagAttributeInfo("archive", false, url + "syntaxref2023.html#11553#11516", false), // NOI18N
  860. new TagAttributeInfo("code", true, url + "syntaxref2023.html#11514#11515", false), // NOI18N
  861. new TagAttributeInfo("codebase", true, url + "syntaxref2023.html#11515#11547", false), // NOI18N
  862. new TagAttributeInfo("height", false, url + "syntaxref2023.html#11518#11568", false), // NOI18N
  863. new TagAttributeInfo("hspace", false, url + "syntaxref2023.html#11568#11520", false), // NOI18N
  864. new TagAttributeInfo("iepluginurl", false, url + "syntaxref2023.html#11526#11538", false),// NOI18N
  865. new TagAttributeInfo("jreversion", false, url + "syntaxref2023.html#11520#11525", false), // NOI18N
  866. new TagAttributeInfo("name", false, url + "syntaxref2023.html#11547#11553", false), // NOI18N
  867. new TagAttributeInfo("nspluginurl", false,url + "syntaxref2023.html#11525#11526", false),// NOI18N
  868. new TagAttributeInfo("type", true, url + "syntaxref2023.html#10935#11514", false), // NOI18N
  869. new TagAttributeInfo("vspace", false, url + "syntaxref2023.html#11568#11520", false), // NOI18N
  870. new TagAttributeInfo("width", false, url + "syntaxref2023.html#11518#11568", false)}), // NOI18N
  871. new TagInfo("setProperty", null, TagInfo.BODY_CONTENT_EMPTY, url + "syntaxref2025.html#8856#9329", // NOI18N
  872. null, null, new TagAttributeInfo[] { new TagAttributeInfo("name", true, url + "syntaxref2025.html#17612#1001786", true), // NOI18N
  873. new TagAttributeInfo("param", false, url + "syntaxref2025.html#9919#20483", false), // NOI18N
  874. new TagAttributeInfo("property", false, url + "syntaxref2025.html#1001786#9329", false), // NOI18N
  875. new TagAttributeInfo("value", false, url + "syntaxref2025.html#20483#9329", true)}), // NOI18N
  876. new TagInfo("text", null, TagInfo.BODY_CONTENT_JSP, url + "syntaxref2026.html",
  877. null, n