Skip to content

Commit c5bb03a

Browse files
committed
Add @j2sXHTML and @j2sCSS, supporting writing HTML and CSS inside Java
and binding to Java object
1 parent bfe76f2 commit c5bb03a

File tree

6 files changed

+319
-3
lines changed

6 files changed

+319
-3
lines changed

sources/net.sf.j2s.core/src/net/sf/j2s/core/astvisitors/ASTJ2SDocVisitor.java

Lines changed: 287 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
package net.sf.j2s.core.astvisitors;
1313

1414
import java.util.ArrayList;
15+
import java.util.HashSet;
1516
import java.util.Iterator;
1617
import java.util.List;
18+
import java.util.Set;
1719
import java.util.regex.Pattern;
1820

1921
import org.eclipse.jdt.core.dom.ASTNode;
@@ -173,6 +175,14 @@ boolean visitNativeJavadoc(Javadoc javadoc, Block node, boolean superVisit) {
173175
return false;
174176
}
175177
}
178+
for (Iterator iter = tags.iterator(); iter.hasNext();) {
179+
TagElement tagEl = (TagElement) iter.next();
180+
if ("@j2sXHTML".equals(tagEl.getTagName()) || "@j2sXCSS".equals(tagEl.getTagName())) {
181+
if (superVisit) super.visit(node);
182+
visitJavadocXStringSource(tagEl, tagEl.getTagName());
183+
return false;
184+
}
185+
}
176186
}
177187
}
178188
return true;
@@ -196,6 +206,267 @@ private void visitJavadocJ2SSource(TagElement tagEl) {
196206
}
197207
buffer.append(fixCommentBlock(buf.toString()));
198208
}
209+
210+
private void visitJavadocXStringSource(TagElement tagEl, String tagName) {
211+
List fragments = tagEl.fragments();
212+
boolean isFirstLine = true;
213+
StringBuffer buf = new StringBuffer();
214+
String firstLine = null;
215+
for (Iterator iterator = fragments.iterator(); iterator
216+
.hasNext();) {
217+
TextElement commentEl = (TextElement) iterator.next();
218+
String text = commentEl.getText().trim();
219+
if (isFirstLine) {
220+
if (text.length() == 0) {
221+
continue;
222+
}
223+
firstLine = text.trim();
224+
isFirstLine = false;
225+
continue;
226+
}
227+
buf.append(text);
228+
buf.append("\r\n");
229+
}
230+
String sources = buf.toString().trim();
231+
sources = buildXSource(tagName, firstLine, sources);
232+
buffer.append(sources);
233+
}
234+
235+
private Set<String> parseXTag(String sources) {
236+
Set<String> vars = new HashSet<String>();
237+
String key = "{$";
238+
int index = sources.indexOf(key, 0);
239+
while (index != -1) {
240+
int idx = sources.indexOf("}", index + key.length());
241+
if (idx == -1) {
242+
break;
243+
}
244+
String var = sources.substring(index + key.length() - 1, idx); // with prefix $
245+
if (var.indexOf(' ') == -1) {
246+
vars.add(var);
247+
}
248+
index = sources.indexOf(key, idx + 1);
249+
}
250+
key = "<!--";
251+
index = sources.indexOf(key, 0);
252+
while (index != -1) {
253+
int idx = sources.indexOf("-->", index + key.length());
254+
if (idx == -1) {
255+
break;
256+
}
257+
String comment = sources.substring(index + key.length(), idx).trim();
258+
if (comment.startsWith("$") && comment.indexOf(' ') == -1) {
259+
vars.add(comment);
260+
}
261+
index = sources.indexOf(key, idx + 3); // 3: "-->".length()
262+
}
263+
key = "id";
264+
index = sources.indexOf(key, 0);
265+
while (index > 0) {
266+
char last = sources.charAt(index - 1);
267+
if (!(last == ' ' || last == '\t' || last == '\n' || last == '\r')) {
268+
index = sources.indexOf(key, index + key.length());
269+
continue;
270+
}
271+
int idxEqual = index + key.length();
272+
do {
273+
char c = sources.charAt(idxEqual);
274+
if (c == '=') {
275+
break;
276+
} else if (c == ' ' || c == '\t') {
277+
idxEqual++;
278+
if (idxEqual == sources.length() - 1) {
279+
idxEqual = -1;
280+
break;
281+
}
282+
} else {
283+
idxEqual = -1;
284+
break;
285+
}
286+
} while (true);
287+
if (idxEqual == -1 || idxEqual == sources.length() - 1) {
288+
break;
289+
}
290+
char quote = 0;
291+
int idxQuoteStart = idxEqual + 1;
292+
do {
293+
char c = sources.charAt(idxQuoteStart);
294+
if (c == '\'' || c == '\"') {
295+
quote = c;
296+
break;
297+
} else if (c == ' ' || c == '\t') {
298+
idxQuoteStart++;
299+
if (idxQuoteStart == sources.length() - 1) {
300+
idxQuoteStart = -1;
301+
break;
302+
}
303+
} else {
304+
idxQuoteStart = -1;
305+
break;
306+
}
307+
} while (true);
308+
if (idxQuoteStart == -1 || idxQuoteStart == sources.length() - 1) {
309+
break;
310+
}
311+
int idxQuoteEnd = sources.indexOf(quote, idxQuoteStart + 1);
312+
if (idxQuoteEnd == -1 || idxQuoteEnd == sources.length() - 1) {
313+
break;
314+
}
315+
String idStr = sources.substring(idxQuoteStart + 1, idxQuoteEnd).trim();
316+
if (idStr.startsWith("$") && idStr.indexOf(' ') == -1) {
317+
vars.add(idStr);
318+
}
319+
index = sources.indexOf(key, idxQuoteEnd + 1);
320+
}
321+
return vars;
322+
}
323+
324+
private boolean containsBeginning(Set<String> set, String beginning) {
325+
for (String s : set) {
326+
if (s.startsWith(beginning)) {
327+
return true;
328+
}
329+
}
330+
return false;
331+
}
332+
333+
private String buildXSource(String tagName, String firstLine, String sources) {
334+
if (firstLine != null && sources.length() > 0) {
335+
Set<String> xTags = null;
336+
StringBuilder builder = new StringBuilder();
337+
if ("@j2sXHTML".equals(tagName)) {
338+
boolean shouldMergeFirstLine = false;
339+
if (firstLine.startsWith("{$") || firstLine.contains("<") || firstLine.contains(">")) {
340+
shouldMergeFirstLine = true;
341+
}
342+
if (shouldMergeFirstLine) {
343+
sources = firstLine + "\r\n" + sources;
344+
firstLine = "";
345+
}
346+
xTags = parseXTag(sources);
347+
sources = "\"" + sources.replaceAll("\t", "\\\\t").replaceAll("\"", "\\\\\"").replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") + "\"";
348+
String[] parts = firstLine.split("(,| |\t)+");
349+
if (firstLine.length() == 0) {
350+
builder.append("Clazz.parseHTML(");
351+
} else if (parts == null || parts.length == 1) {
352+
if ("return".equals(firstLine)) {
353+
builder.append("return Clazz.parseHTML(");
354+
} else {
355+
builder.append("Clazz.parseHTML(").append(firstLine).append(", ");
356+
}
357+
} else {
358+
String firstVar = parts[0];
359+
String leftStr = firstLine.substring(firstVar.length() + 1).replaceAll("^(,| |\t)+", "");
360+
if (leftStr.endsWith(",")) {
361+
leftStr = leftStr.substring(0, leftStr.length() - 1);
362+
}
363+
if ("return".equals(firstVar)) {
364+
builder.append("return Clazz.parseHTML(").append(leftStr).append(", ");
365+
} else {
366+
builder.append(firstVar).append(" = Clazz.parseHTML(").append(leftStr).append(", ");
367+
}
368+
}
369+
} else { // @j2sXCSS
370+
boolean shouldMergeFirstLine = false;
371+
if (firstLine.startsWith(".") || firstLine.contains("#") || firstLine.contains(">") || firstLine.contains("{")) {
372+
shouldMergeFirstLine = true;
373+
} else if (sources.startsWith("{")) {
374+
shouldMergeFirstLine = true;
375+
}
376+
if (shouldMergeFirstLine) {
377+
sources = firstLine + "\r\n" + sources;
378+
xTags = parseXTag(sources);
379+
builder.append("Clazz.parseCSS(");
380+
} else {
381+
xTags = parseXTag(sources);
382+
if (firstLine.endsWith(",")) {
383+
firstLine = firstLine.substring(0, firstLine.length() - 1);
384+
}
385+
builder.append("Clazz.parseCSS(").append(firstLine).append(", ");
386+
}
387+
sources = "\"" + sources.replaceAll("\t", "\\\\t").replaceAll("\"", "\\\\\"").replaceAll("\r\n", "\\\\r\\\\n\" +\r\n\"") + "\"";
388+
}
389+
boolean containsThis = containsBeginning(xTags, "$:") || containsBeginning(xTags, "$.");
390+
boolean containsClass = containsBeginning(xTags, "$/");
391+
if (containsThis) {
392+
builder.append("this, ");
393+
} else if (containsClass) {
394+
String fullClassName = null;
395+
String packageName = ((ASTPackageVisitor) getAdaptable(ASTPackageVisitor.class)).getPackageName();
396+
String className = ((ASTTypeVisitor) getAdaptable(ASTTypeVisitor.class)).getClassName();
397+
if (packageName != null && packageName.length() != 0) {
398+
fullClassName = packageName + '.' + className;
399+
} else {
400+
fullClassName = className;
401+
}
402+
builder.append(fullClassName).append(", ");
403+
}
404+
boolean localStarted = false;
405+
for (String s : xTags) {
406+
if (s.startsWith("$~")) {
407+
if (!localStarted) {
408+
builder.append("{");
409+
localStarted = true;
410+
} else {
411+
builder.append(", ");
412+
}
413+
String varName = s.substring(2);
414+
builder.append(varName).append(": ").append(varName);
415+
}
416+
}
417+
if (localStarted) {
418+
builder.append("}, ");
419+
}
420+
builder.append(sources).append(");\r\n");
421+
return builder.toString();
422+
}
423+
return sources;
424+
}
425+
426+
/*
427+
* Read HTML/CSS sources from @j2sXHTML, @J2SXCSS or others
428+
*/
429+
boolean readStringSources(BodyDeclaration node, String tagName, String prefix, String suffix, boolean both) {
430+
boolean existed = false;
431+
Javadoc javadoc = node.getJavadoc();
432+
if (javadoc != null) {
433+
List tags = javadoc.tags();
434+
if (tags.size() != 0) {
435+
for (Iterator iter = tags.iterator(); iter.hasNext();) {
436+
TagElement tagEl = (TagElement) iter.next();
437+
if (tagName.equals(tagEl.getTagName())) {
438+
if (tagEl != null) {
439+
List fragments = tagEl.fragments();
440+
StringBuffer buf = new StringBuffer();
441+
boolean isFirstLine = true;
442+
String firstLine = null;
443+
for (Iterator iterator = fragments.iterator(); iterator
444+
.hasNext();) {
445+
TextElement commentEl = (TextElement) iterator.next();
446+
String text = commentEl.getText().trim();
447+
if (isFirstLine) {
448+
if (text.length() == 0) {
449+
continue;
450+
}
451+
firstLine = text.trim();
452+
isFirstLine = false;
453+
continue;
454+
}
455+
buf.append(text);
456+
buf.append("\r\n");
457+
}
458+
String sources = buf.toString().trim();
459+
sources = buildXSource(tagName, firstLine, sources);
460+
buffer.append(prefix + sources + suffix);
461+
existed = true;
462+
}
463+
}
464+
}
465+
}
466+
}
467+
return existed;
468+
}
469+
199470
/*
200471
* Read JavaScript sources from @j2sNative, @J2SPrefix or others
201472
*/
@@ -217,6 +488,7 @@ boolean readSources(BodyDeclaration node, String tagName, String prefix, String
217488
TextElement commentEl = (TextElement) iterator.next();
218489
String text = commentEl.getText().trim();
219490
if (isFirstLine) {
491+
isFirstLine = false;
220492
if (text.length() == 0) {
221493
continue;
222494
}
@@ -225,6 +497,7 @@ boolean readSources(BodyDeclaration node, String tagName, String prefix, String
225497
buf.append("\r\n");
226498
}
227499
String sources = buf.toString().trim();
500+
// embed block comments and Javadoc @
228501
sources = sources.replaceAll("(\\/)-\\*|\\*-(\\/)", "$1*$2").replaceAll("<@>", "@");
229502
buffer.append(prefix + sources + suffix);
230503
existed = true;
@@ -309,7 +582,11 @@ private void checkJavadocs(ASTNode root) {
309582
String tagName = tagEl.getTagName();
310583
if ("@j2sIgnore".equals(tagName)
311584
|| "@j2sDebug".equals(tagName)
312-
|| "@j2sNative".equals(tagName)) {
585+
|| "@j2sNative".equals(tagName)
586+
|| "@j2sNativeSrc".equals(tagName)
587+
|| "@j2sXHTML".equals(tagName)
588+
|| "@j2sXCSS".equals(tagName)
589+
) {
313590
list.add(comment);
314591
}
315592
}
@@ -413,6 +690,15 @@ protected boolean isMethodNativeIgnored(MethodDeclaration node) {
413690
if (getJ2STag(node, "@j2sNative") != null) {
414691
return false;
415692
}
693+
if (getJ2STag(node, "@j2sNativeSrc") != null) {
694+
return false;
695+
}
696+
if (getJ2STag(node, "@j2sXHTML") != null) {
697+
return false;
698+
}
699+
if (getJ2STag(node, "@j2sXCSS") != null) {
700+
return false;
701+
}
416702
return true;
417703
}
418704
return true; // interface!

sources/net.sf.j2s.core/src/net/sf/j2s/core/astvisitors/ASTScriptVisitor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,12 @@ private boolean checkJ2STags(MethodDeclaration node, boolean needScope) {
20442044
if (!read) {
20452045
read = readSources(node, "@j2sNative", prefix, suffix, false);
20462046
}
2047+
if (!read) {
2048+
read = readStringSources(node, "@j2sXHTML", prefix, suffix, false);
2049+
}
2050+
if (!read) {
2051+
read = readStringSources(node, "@j2sXCSS", prefix, suffix, false);
2052+
}
20472053
return read;
20482054
}
20492055

sources/net.sf.j2s.core/src/net/sf/j2s/core/astvisitors/DependencyASTVisitor.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,12 @@ public boolean visit(MethodDeclaration node) {
10711071
if (getJ2STag(node, "@j2sNativeSrc") != null) {
10721072
return false;
10731073
}
1074+
if (getJ2STag(node, "@j2sXHTML") != null) {
1075+
return false;
1076+
}
1077+
if (getJ2STag(node, "@j2sXCSS") != null) {
1078+
return false;
1079+
}
10741080

10751081
if (getJ2STag(node, "@j2sIgnore") != null) {
10761082
return false;
@@ -1205,7 +1211,9 @@ boolean visitNativeJavadoc(Javadoc javadoc, Block node, boolean superVisit) {
12051211
}
12061212
for (Iterator iter = tags.iterator(); iter.hasNext();) {
12071213
TagElement tagEl = (TagElement) iter.next();
1208-
if ("@j2sNative".equals(tagEl.getTagName())) {
1214+
if ("@j2sNative".equals(tagEl.getTagName())
1215+
|| "@j2sXHTML".equals(tagEl.getTagName())
1216+
|| "@j2sXCSS".equals(tagEl.getTagName())) {
12091217
if (superVisit) super.visit(node);
12101218
return false;
12111219
}
@@ -1237,7 +1245,11 @@ private void checkJavadocs(ASTNode root) {
12371245
String tagName = tagEl.getTagName();
12381246
if ("@j2sIgnore".equals(tagName)
12391247
|| "@j2sDebug".equals(tagName)
1240-
|| "@j2sNative".equals(tagName)) {
1248+
|| "@j2sNative".equals(tagName)
1249+
|| "@j2sNativeSrc".equals(tagName)
1250+
|| "@j2sXHTML".equals(tagName)
1251+
|| "@j2sXCSS".equals(tagName)
1252+
) {
12411253
list.add(comment);
12421254
}
12431255
}

0 commit comments

Comments
 (0)