Fossil SCM

Automatically clean up the HTML that is generated by webbrowsers and by the Fossil wiki-to-html translator so that the HTML is easier to read in the wysiwyg editor.

drh 2012-08-10 23:12 UTC wysiwyg
Commit fb6f1b7b719f9f62322b6eb950ccf72cb86de4c6
2 files changed +14 -3 +111
+14 -3
--- src/wiki.c
+++ src/wiki.c
@@ -262,13 +262,21 @@
262262
const char *zPageName;
263263
char *zHtmlPageName;
264264
int n;
265265
const char *z;
266266
char *zBody = (char*)P("w");
267
+ int isWysiwyg = P("wysiwyg")!=0;
267268
268269
if( zBody ){
269
- zBody = mprintf("%s", zBody);
270
+ if( isWysiwyg ){
271
+ Blob body;
272
+ blob_zero(&body);
273
+ htmlTidy(zBody, &body);
274
+ zBody = blob_str(&body);
275
+ }else{
276
+ zBody = mprintf("%s", zBody);
277
+ }
270278
}
271279
login_check_credentials();
272280
zPageName = PD("name","");
273281
if( check_name(zPageName) ) return;
274282
isSandbox = is_sandbox(zPageName);
@@ -360,16 +368,19 @@
360368
@ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
361369
@ <br />
362370
@ <input type="submit" name="preview" value="Preview Your Changes" />
363371
}else{
364372
/* Wysiwyg editing */
365
- Blob html;
373
+ Blob html, temp;
366374
@ <form method="post" action="%s(g.zTop)/wikiedit"
367375
@ onsubmit="wysiwygSubmit()"><div>
368376
@ <input type="hidden" name="wysiwyg" value="1" />
377
+ blob_zero(&temp);
378
+ wiki_convert(&wiki, &temp, 0);
369379
blob_zero(&html);
370
- wiki_convert(&wiki, &html, 0);
380
+ htmlTidy(blob_str(&temp), &html);
381
+ blob_reset(&temp);
371382
wysiwygEditor("w", blob_str(&html), 60, n);
372383
blob_reset(&html);
373384
@ <br />
374385
}
375386
@ <input type="submit" name="submit" value="Apply These Changes" />
376387
--- src/wiki.c
+++ src/wiki.c
@@ -262,13 +262,21 @@
262 const char *zPageName;
263 char *zHtmlPageName;
264 int n;
265 const char *z;
266 char *zBody = (char*)P("w");
 
267
268 if( zBody ){
269 zBody = mprintf("%s", zBody);
 
 
 
 
 
 
 
270 }
271 login_check_credentials();
272 zPageName = PD("name","");
273 if( check_name(zPageName) ) return;
274 isSandbox = is_sandbox(zPageName);
@@ -360,16 +368,19 @@
360 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
361 @ <br />
362 @ <input type="submit" name="preview" value="Preview Your Changes" />
363 }else{
364 /* Wysiwyg editing */
365 Blob html;
366 @ <form method="post" action="%s(g.zTop)/wikiedit"
367 @ onsubmit="wysiwygSubmit()"><div>
368 @ <input type="hidden" name="wysiwyg" value="1" />
 
 
369 blob_zero(&html);
370 wiki_convert(&wiki, &html, 0);
 
371 wysiwygEditor("w", blob_str(&html), 60, n);
372 blob_reset(&html);
373 @ <br />
374 }
375 @ <input type="submit" name="submit" value="Apply These Changes" />
376
--- src/wiki.c
+++ src/wiki.c
@@ -262,13 +262,21 @@
262 const char *zPageName;
263 char *zHtmlPageName;
264 int n;
265 const char *z;
266 char *zBody = (char*)P("w");
267 int isWysiwyg = P("wysiwyg")!=0;
268
269 if( zBody ){
270 if( isWysiwyg ){
271 Blob body;
272 blob_zero(&body);
273 htmlTidy(zBody, &body);
274 zBody = blob_str(&body);
275 }else{
276 zBody = mprintf("%s", zBody);
277 }
278 }
279 login_check_credentials();
280 zPageName = PD("name","");
281 if( check_name(zPageName) ) return;
282 isSandbox = is_sandbox(zPageName);
@@ -360,16 +368,19 @@
368 @ rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
369 @ <br />
370 @ <input type="submit" name="preview" value="Preview Your Changes" />
371 }else{
372 /* Wysiwyg editing */
373 Blob html, temp;
374 @ <form method="post" action="%s(g.zTop)/wikiedit"
375 @ onsubmit="wysiwygSubmit()"><div>
376 @ <input type="hidden" name="wysiwyg" value="1" />
377 blob_zero(&temp);
378 wiki_convert(&wiki, &temp, 0);
379 blob_zero(&html);
380 htmlTidy(blob_str(&temp), &html);
381 blob_reset(&temp);
382 wysiwygEditor("w", blob_str(&html), 60, n);
383 blob_reset(&html);
384 @ <br />
385 }
386 @ <input type="submit" name="submit" value="Apply These Changes" />
387
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1747,5 +1747,116 @@
17471747
}
17481748
z += n;
17491749
}
17501750
free(renderer.aStack);
17511751
}
1752
+
1753
+/*
1754
+** Get the next HTML token.
1755
+**
1756
+** z points to the start of a token. Return the number of
1757
+** characters in that token.
1758
+*/
1759
+static int nextHtmlToken(const char *z){
1760
+ int n;
1761
+ if( z[0]=='<' ){
1762
+ n = markupLength(z);
1763
+ if( n<=0 ) n = 1;
1764
+ }else if( fossil_isspace(z[0]) ){
1765
+ for(n=1; z[n] && fossil_isspace(z[n]); n++){}
1766
+ }else{
1767
+ for(n=1; z[n] && z[n]!='<' && !fossil_isspace(z[n]); n++){}
1768
+ }
1769
+ return n;
1770
+}
1771
+
1772
+/*
1773
+** Return true if z[] is the word zWord in any case.
1774
+*/
1775
+static int isWord(const char *z, const char *zWord, int nWord){
1776
+ return fossil_strnicmp(z, zWord, nWord)==0 && !fossil_isalpha(z[nWord]);
1777
+}
1778
+
1779
+/*
1780
+** Attempt to reformat messy HTML to be easily readable by humans.
1781
+**
1782
+** * Try to keep lines less than 80 characters in length
1783
+** * Collapse white space into a single space
1784
+** * Put a blank line before:
1785
+** <blockquote><center><code><hN><p><pre><table>
1786
+** * Put a newline after <br> and <hr>
1787
+** * Start each of the following elements on a new line:
1788
+** <address><cite><dd><div><dl><dt><li><ol><samp>
1789
+** <tbody><td><tfoot><th><thead><tr><ul>
1790
+**
1791
+** Except, do not do any reformatting inside of <pre>...</pre>
1792
+*/
1793
+void htmlTidy(const char *zIn, Blob *pOut){
1794
+ int n;
1795
+ int nPre = 0;
1796
+ int iCur = 0;
1797
+ while( zIn[0] ){
1798
+ n = nextHtmlToken(zIn);
1799
+ if( zIn[0]=='<' && n>1 ){
1800
+ if( isWord(zIn, "<pre", 4) ){
1801
+ if( iCur && nPre==0 ){ blob_append(pOut, "\n", 1); iCur = 0; }
1802
+ nPre++;
1803
+ }else if( isWord(zIn, "</pre", 5) ){
1804
+ nPre--;
1805
+ if( nPre==0 ){ blob_append(pOut, "\n", 1); iCur = 0; }
1806
+ }else if( isWord(zIn, "<blockquote", 11)
1807
+ || isWord(zIn, "<center", 7)
1808
+ || (isWord(zIn, "<h", 2) && fossil_isdigit(zIn[2]))
1809
+ || isWord(zIn, "<p", 2)
1810
+ || isWord(zIn, "<table", 6) ){
1811
+ blob_append(pOut, "\n\n", 1 + (iCur>0));
1812
+ iCur = 0;
1813
+ }else if( isWord(zIn, "<dd", 3)
1814
+ || isWord(zIn, "<div", 4)
1815
+ || isWord(zIn, "<dl", 3)
1816
+ || isWord(zIn, "<dt", 3)
1817
+ || isWord(zIn, "<li", 3)
1818
+ || isWord(zIn, "<ol", 3)
1819
+ || isWord(zIn, "<td", 3)
1820
+ || isWord(zIn, "<th", 3)
1821
+ || isWord(zIn, "<tr", 3)
1822
+ || isWord(zIn, "<ul", 3) ){
1823
+ if( iCur>0 ) blob_append(pOut, "\n", 1);
1824
+ iCur = 0;
1825
+ }
1826
+ blob_append(pOut, zIn, n);
1827
+ iCur += n;
1828
+ }else if( fossil_isspace(zIn[0]) ){
1829
+ if( nPre ){
1830
+ blob_append(pOut, zIn, n);
1831
+ }else if( iCur>=70 ){
1832
+ blob_append(pOut, "\n", 1);
1833
+ iCur = 0;
1834
+ }else{
1835
+ blob_append(pOut, " ", 1);
1836
+ iCur++;
1837
+ }
1838
+ }else{
1839
+ blob_append(pOut, zIn, n);
1840
+ iCur += n;
1841
+ }
1842
+ zIn += n;
1843
+ }
1844
+ if( iCur ) blob_append(pOut, "\n", 1);
1845
+}
1846
+
1847
+/*
1848
+** COMMAND: test-html-tidy
1849
+*/
1850
+void test_html_tidy(void){
1851
+ Blob in, out;
1852
+ int i;
1853
+
1854
+ for(i=2; i<g.argc; i++){
1855
+ blob_read_from_file(&in, g.argv[i]);
1856
+ blob_zero(&out);
1857
+ htmlTidy(blob_str(&in), &out);
1858
+ blob_reset(&in);
1859
+ fossil_puts(blob_str(&out), 0);
1860
+ blob_reset(&out);
1861
+ }
1862
+}
17521863
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1747,5 +1747,116 @@
1747 }
1748 z += n;
1749 }
1750 free(renderer.aStack);
1751 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1752
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1747,5 +1747,116 @@
1747 }
1748 z += n;
1749 }
1750 free(renderer.aStack);
1751 }
1752
1753 /*
1754 ** Get the next HTML token.
1755 **
1756 ** z points to the start of a token. Return the number of
1757 ** characters in that token.
1758 */
1759 static int nextHtmlToken(const char *z){
1760 int n;
1761 if( z[0]=='<' ){
1762 n = markupLength(z);
1763 if( n<=0 ) n = 1;
1764 }else if( fossil_isspace(z[0]) ){
1765 for(n=1; z[n] && fossil_isspace(z[n]); n++){}
1766 }else{
1767 for(n=1; z[n] && z[n]!='<' && !fossil_isspace(z[n]); n++){}
1768 }
1769 return n;
1770 }
1771
1772 /*
1773 ** Return true if z[] is the word zWord in any case.
1774 */
1775 static int isWord(const char *z, const char *zWord, int nWord){
1776 return fossil_strnicmp(z, zWord, nWord)==0 && !fossil_isalpha(z[nWord]);
1777 }
1778
1779 /*
1780 ** Attempt to reformat messy HTML to be easily readable by humans.
1781 **
1782 ** * Try to keep lines less than 80 characters in length
1783 ** * Collapse white space into a single space
1784 ** * Put a blank line before:
1785 ** <blockquote><center><code><hN><p><pre><table>
1786 ** * Put a newline after <br> and <hr>
1787 ** * Start each of the following elements on a new line:
1788 ** <address><cite><dd><div><dl><dt><li><ol><samp>
1789 ** <tbody><td><tfoot><th><thead><tr><ul>
1790 **
1791 ** Except, do not do any reformatting inside of <pre>...</pre>
1792 */
1793 void htmlTidy(const char *zIn, Blob *pOut){
1794 int n;
1795 int nPre = 0;
1796 int iCur = 0;
1797 while( zIn[0] ){
1798 n = nextHtmlToken(zIn);
1799 if( zIn[0]=='<' && n>1 ){
1800 if( isWord(zIn, "<pre", 4) ){
1801 if( iCur && nPre==0 ){ blob_append(pOut, "\n", 1); iCur = 0; }
1802 nPre++;
1803 }else if( isWord(zIn, "</pre", 5) ){
1804 nPre--;
1805 if( nPre==0 ){ blob_append(pOut, "\n", 1); iCur = 0; }
1806 }else if( isWord(zIn, "<blockquote", 11)
1807 || isWord(zIn, "<center", 7)
1808 || (isWord(zIn, "<h", 2) && fossil_isdigit(zIn[2]))
1809 || isWord(zIn, "<p", 2)
1810 || isWord(zIn, "<table", 6) ){
1811 blob_append(pOut, "\n\n", 1 + (iCur>0));
1812 iCur = 0;
1813 }else if( isWord(zIn, "<dd", 3)
1814 || isWord(zIn, "<div", 4)
1815 || isWord(zIn, "<dl", 3)
1816 || isWord(zIn, "<dt", 3)
1817 || isWord(zIn, "<li", 3)
1818 || isWord(zIn, "<ol", 3)
1819 || isWord(zIn, "<td", 3)
1820 || isWord(zIn, "<th", 3)
1821 || isWord(zIn, "<tr", 3)
1822 || isWord(zIn, "<ul", 3) ){
1823 if( iCur>0 ) blob_append(pOut, "\n", 1);
1824 iCur = 0;
1825 }
1826 blob_append(pOut, zIn, n);
1827 iCur += n;
1828 }else if( fossil_isspace(zIn[0]) ){
1829 if( nPre ){
1830 blob_append(pOut, zIn, n);
1831 }else if( iCur>=70 ){
1832 blob_append(pOut, "\n", 1);
1833 iCur = 0;
1834 }else{
1835 blob_append(pOut, " ", 1);
1836 iCur++;
1837 }
1838 }else{
1839 blob_append(pOut, zIn, n);
1840 iCur += n;
1841 }
1842 zIn += n;
1843 }
1844 if( iCur ) blob_append(pOut, "\n", 1);
1845 }
1846
1847 /*
1848 ** COMMAND: test-html-tidy
1849 */
1850 void test_html_tidy(void){
1851 Blob in, out;
1852 int i;
1853
1854 for(i=2; i<g.argc; i++){
1855 blob_read_from_file(&in, g.argv[i]);
1856 blob_zero(&out);
1857 htmlTidy(blob_str(&in), &out);
1858 blob_reset(&in);
1859 fossil_puts(blob_str(&out), 0);
1860 blob_reset(&out);
1861 }
1862 }
1863

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button