diff --git a/htroot/Wiki.html b/htroot/Wiki.html index 34293f4a1..49ca3dba2 100644 --- a/htroot/Wiki.html +++ b/htroot/Wiki.html @@ -19,7 +19,12 @@ last edited by #[author]# | change date #[date]# | Edit #(access)#(only granted to admin)::#(/access)#

- + ::
@@ -106,6 +111,39 @@ + :: + + #(error)# + +
Select versions of page '#[page]# + +
+
:
+
+ +
+
:
+
+ +
+
+
+
+
+ :: +

IO Error reading wiki database: #[message]#

+ :: + #(/error)# + #[diff]# + #(/mode)#

Changes will be published as announcement on YaCyNews

diff --git a/htroot/Wiki.java b/htroot/Wiki.java index 889f11c9a..106d3472a 100644 --- a/htroot/Wiki.java +++ b/htroot/Wiki.java @@ -53,6 +53,7 @@ import java.util.Date; import java.util.HashMap; import java.util.Iterator; +import de.anomic.data.Diff; import de.anomic.data.wikiBoard; import de.anomic.http.httpHeader; import de.anomic.plasma.plasmaSwitchboard; @@ -155,7 +156,7 @@ public class Wiki { prop.put("mode_author", author); prop.put("mode_date", dateString(new Date())); prop.putWiki("mode_page", post.get("content", "")); - prop.put("mode_page-code", post.get("content", "").replaceAll("<","<").replaceAll(">",">")); + prop.put("mode_page-code", post.get("content", "")); } //end contrib of [MN] @@ -183,6 +184,68 @@ public class Wiki { } prop.put("mode_pagename", pagename); } + + else if (post.containsKey("diff")) { + prop.put("mode", 4); + prop.put("mode_page", pagename); + prop.put("mode_error_page", pagename); + + try { + Iterator it = switchboard.wikiDB.keysBkp(true); + wikiBoard.entry entry; + wikiBoard.entry oentry = null; + wikiBoard.entry nentry = null; + int count = 0; + boolean oldselected = false, newselected = false; + while (it.hasNext()) { + entry = switchboard.wikiDB.readBkp((String)it.next()); + prop.put("mode_error_versions_" + count + "_date", wikiBoard.dateString(entry.date())); + prop.put("mode_error_versions_" + count + "_fdate", dateString(entry.date())); + if (wikiBoard.dateString(entry.date()).equals(post.get("old", null))) { + prop.put("mode_error_versions_" + count + "_oldselected", 1); + oentry = entry; + oldselected = true; + } else if (wikiBoard.dateString(entry.date()).equals(post.get("new", null))) { + prop.put("mode_error_versions_" + count + "_newselected", 1); + nentry = entry; + newselected = true; + } + count++; + } + count--; // don't show current version + + if (!oldselected) // select latest old entry + prop.put("mode_error_versions_" + (count - 1) + "_oldselected", 1); + if (!newselected) // select latest new entry (== current) + prop.put("mode_error_curselected", 1); + + if (count == 0) { + prop.put("mode_error", 2); // no entries found + } else { + prop.put("mode_error_versions", count); + } + + entry = switchboard.wikiDB.read(pagename); + if (entry != null) { + prop.put("mode_error_curdate", wikiBoard.dateString(entry.date())); + prop.put("mode_error_curfdate", dateString(entry.date())); + } + + if (nentry == null) nentry = entry; + if (post.get("diff", "").length() > 0 && oentry != null && nentry != null) { + // TODO: split into paragraphs and compare them with the same diff-algo + Diff diff = new Diff( + new String(oentry.page(), "UTF-8"), + new String(nentry.page(), "UTF-8"), 5); + prop.putASIS("mode_diff", Diff.toHTML(new Diff[] { diff })); + } else { + prop.put("mode_diff", ""); + } + } catch (IOException e) { + prop.put("mode_error", 1); //IO Error reading Wiki + prop.put("mode_error_message", e.getMessage()); + } + } else { // show page diff --git a/htroot/env/base.css b/htroot/env/base.css index 3a3f2181b..dad197af7 100644 --- a/htroot/env/base.css +++ b/htroot/env/base.css @@ -34,7 +34,7 @@ /* --------------- global elements -------------------------- */ * { - font-family:Helvetica, Arial, sans-serif; + font-family:/*Helvetica, Arial, */sans-serif; } body { @@ -165,6 +165,17 @@ legend { padding: 8px; } +.diff { + margin: 10px 5px; + border: 1px dashed #722; + padding: .5em; + font-family: monospace; +} + +.diff .unchanged { font-family: monospace; } +.diff .added { font-family: monospace; } +.diff .deleted { font-family: monospace; text-decoration: line-through; } + .imgtable { margin: 1px; padding: 1px; diff --git a/skins/dark.css b/skins/dark.css index 787702c19..5bb00e594 100644 --- a/skins/dark.css +++ b/skins/dark.css @@ -45,15 +45,20 @@ a.extern { color: #635; } .bookmark { border-bottom: 1px #000 dashed; } .Tags { border-left: 2px solid black; } -a.bookmarkTitle { color: #4070a0; } +a.bookmarkTitle { color: #4070a0; } a:hover.bookmarkTitle { color: #4070a0; } -a.bookmarkTags { color: #007050; } +a.bookmarkTags { color: #007050; } a:hover.bookmarkTags { color: #4070a0; } -a.bookmarkAction { color: #999999; } +a.bookmarkAction { color: #999999; } .Navigation a { color: #555; } .Navigation a:hover { color: #777; } +.diff { background-color: #171717; } +.diff .unchanged { color: #666; } +.diff .added { color: #0A0; background-color: #053005; } +.diff .deleted { color: #B00; background-color: #390505; } + /* in Status.html */ .ProgressBar { border: 1px solid #777; } .ProgressBarFill { background-color: #944; } diff --git a/skins/default.css b/skins/default.css index 27498054a..35b5e369e 100644 --- a/skins/default.css +++ b/skins/default.css @@ -132,6 +132,10 @@ a.bookmarkAction { border-left: 2px solid black; } +.diff { background-color: #E8E8EE; } +.diff .unchanged { color: #333; } +.diff .added { color: #090; background-color: #B5F0B5; } +.diff .deleted { color: #B00; background-color: #F9B5B5; } /* in Status.html */ diff --git a/skins/grey.css b/skins/grey.css index ec10f345f..fc3120b5a 100644 --- a/skins/grey.css +++ b/skins/grey.css @@ -136,6 +136,10 @@ a.bookmarkAction { border-left: 2px solid black; } +.diff { background-color: #E8E8E8; } +.diff .unchanged { color: #333; } +.diff .added { color: #090; background-color: #B5F0B5; } +.diff .deleted { color: #B00; background-color: #F9B5B5; } /* in Status.html */ diff --git a/skins/mint-green.css b/skins/mint-green.css index 237c081fb..1b356075b 100644 --- a/skins/mint-green.css +++ b/skins/mint-green.css @@ -133,6 +133,10 @@ a.bookmarkAction { border-left: 2px solid black; } +.diff { background-color: #E5FFC5; } +.diff .unchanged { color: #333; } +.diff .added { color: #090; background-color: #B5F0B5; } +.diff .deleted { color: #B00; background-color: #F9B5B5; } /* in Status.html */ diff --git a/skins/phosphor.css b/skins/phosphor.css index de5bc676f..c96987c67 100644 --- a/skins/phosphor.css +++ b/skins/phosphor.css @@ -144,6 +144,10 @@ a.bookmarkAction { border-left: 2px solid black; } +.diff { background-color: #171717; } +.diff .unchanged { color: #666; } +.diff .added { color: #0A0; background-color: #053005; } +.diff .deleted { color: #B00; background-color: #390505; } /* in Status.html */ diff --git a/source/de/anomic/data/Diff.java b/source/de/anomic/data/Diff.java index d2619d4e0..27812a57e 100644 --- a/source/de/anomic/data/Diff.java +++ b/source/de/anomic/data/Diff.java @@ -143,7 +143,7 @@ public class Diff { if (!matrix[yy + i][xx + i]) break; if (i <= minLength && yy + i < matrix.length && xx + i < matrix[yy].length) { // vorzeitig abgebrochen => zuwenige chars in Diagonale => weitersuchen - break; + continue; } else { return new int[] { rx, ry, i }; } @@ -170,6 +170,13 @@ public class Diff { */ public Part[] getParts() { return (Part[])this.parts.toArray(new Part[this.parts.size()]); } + public String toString() { + StringBuffer sb = new StringBuffer(this.parts.size() * 20); + for (int j=0; j\n"); + ps = diffs[i].getParts(); + for (int j=0; j").append(wikiCode.replaceXMLEntities(ps[j].getString()).replaceAll("\n", "
")); + sb.append(""); + } + sb.append("

"); + } + return sb.toString(); + } } diff --git a/source/de/anomic/data/wikiBoard.java b/source/de/anomic/data/wikiBoard.java index 29b17c0f0..cf5fc7040 100644 --- a/source/de/anomic/data/wikiBoard.java +++ b/source/de/anomic/data/wikiBoard.java @@ -1,42 +1,42 @@ -// wikiBoard.java -// ------------------------------------- -// (C) by Michael Peter Christen; mc@anomic.de -// first published on http://www.anomic.de -// Frankfurt, Germany, 2004 -// last major change: 20.07.2004 -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Using this software in any meaning (reading, learning, copying, compiling, -// running) means that you agree that the Author(s) is (are) not responsible -// for cost, loss of data or any harm that may be caused directly or indirectly -// by usage of this softare or this documentation. The usage of this software -// is on your own risk. The installation and usage (starting/running) of this -// software may allow other people or application to access your computer and -// any attached devices and is highly dependent on the configuration of the -// software which must be done by the user of the software; the author(s) is -// (are) also not responsible for proper configuration and usage of the -// software, even if provoked by documentation provided together with -// the software. -// -// Any changes to this file according to the GPL as documented in the file -// gpl.txt aside this file in the shipment you received can be done to the -// lines that follows this copyright notice here, but changes must not be -// done inside the copyright notive above. A re-distribution must contain -// the intact and unchanged copyright notice. -// Contributions and changes to the program code must be marked as such. +//wikiBoard.java +//------------------------------------- +//(C) by Michael Peter Christen; mc@anomic.de +//first published on http://www.anomic.de +//Frankfurt, Germany, 2004 +//last major change: 20.07.2004 + +//This program is free software; you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation; either version 2 of the License, or +//(at your option) any later version. + +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. + +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +//Using this software in any meaning (reading, learning, copying, compiling, +//running) means that you agree that the Author(s) is (are) not responsible +//for cost, loss of data or any harm that may be caused directly or indirectly +//by usage of this softare or this documentation. The usage of this software +//is on your own risk. The installation and usage (starting/running) of this +//software may allow other people or application to access your computer and +//any attached devices and is highly dependent on the configuration of the +//software which must be done by the user of the software; the author(s) is +//(are) also not responsible for proper configuration and usage of the +//software, even if provoked by documentation provided together with +//the software. + +//Any changes to this file according to the GPL as documented in the file +//gpl.txt aside this file in the shipment you received can be done to the +//lines that follows this copyright notice here, but changes must not be +//done inside the copyright notive above. A re-distribution must contain +//the intact and unchanged copyright notice. +//Contributions and changes to the program code must be marked as such. package de.anomic.data; @@ -57,7 +57,7 @@ import de.anomic.kelondro.kelondroMapObjects; import de.anomic.kelondro.kelondroRecords; public class wikiBoard { - + public static final int keyLength = 64; private static final String dateFormat = "yyyyMMddHHmmss"; private static final int recordSize = 512; @@ -68,9 +68,9 @@ public class wikiBoard { private kelondroMapObjects datbase = null; private kelondroMapObjects bkpbase = null; private static HashMap authors = new HashMap(); - + public wikiBoard(File actpath, File bkppath, int bufferkb, long preloadTime) { - new File(actpath.getParent()).mkdirs(); + new File(actpath.getParent()).mkdirs(); if (datbase == null) { datbase = new kelondroMapObjects(kelondroDyn.open(actpath, bufferkb / 2 * 0x400, preloadTime, keyLength, recordSize, '_', true, false), 500); } @@ -83,44 +83,44 @@ public class wikiBoard { public int sizeOfTwo() { return datbase.size() + bkpbase.size(); } - + public int size() { return datbase.size(); } - + public int cacheNodeChunkSize() { int db = datbase.cacheNodeChunkSize(); int bk = bkpbase.cacheNodeChunkSize(); return (db + bk) / 2; } - + public int cacheObjectChunkSize() { int db = datbase.cacheObjectChunkSize(); int bk = bkpbase.cacheObjectChunkSize(); return (db + bk) / 2; } - + public int[] cacheNodeStatus() { int[] a = datbase.cacheNodeStatus(); int[] b = bkpbase.cacheNodeStatus(); return kelondroRecords.cacheCombinedStatus(new int[][]{a, b}, 2); } - + public long[] cacheObjectStatus() { return datbase.cacheObjectStatus(); } - + public void close() { try {datbase.close();} catch (IOException e) {} try {bkpbase.close();} catch (IOException e) {} } - + private static String dateString() { - return dateString(new GregorianCalendar(GMTTimeZone).getTime()); + return dateString(new GregorianCalendar(GMTTimeZone).getTime()); } - private static String dateString(Date date) { - return SimpleFormatter.format(date); + public static String dateString(Date date) { + return SimpleFormatter.format(date); } private static String normalize(String key) { @@ -136,104 +136,104 @@ public class wikiBoard { key = key.substring(0, p) + "%20" + key.substring(p +1); return key; } - + public static String guessAuthor(String ip) { String author = (String) authors.get(ip); //yacyCore.log.logDebug("DEBUG: guessing author for ip = " + ip + " is '" + author + "', authors = " + authors.toString()); return author; } - + public static void setAuthor(String ip, String author) { authors.put(ip,author); } public entry newEntry(String subject, String author, String ip, String reason, byte[] page) throws IOException { - return new entry(normalize(subject), author, ip, reason, page); + return new entry(normalize(subject), author, ip, reason, page); } public class entry { - - String key; + + String key; Map record; - public entry(String subject, String author, String ip, String reason, byte[] page) throws IOException { - record = new HashMap(); - key = subject; - if (key.length() > keyLength) key = key.substring(0, keyLength); - record.put("date", dateString()); - if ((author == null) || (author.length() == 0)) author = "anonymous"; - record.put("author", kelondroBase64Order.enhancedCoder.encode(author.getBytes("UTF-8"))); - if ((ip == null) || (ip.length() == 0)) ip = ""; - record.put("ip", ip); - if ((reason == null) || (reason.length() == 0)) reason = ""; - record.put("reason", kelondroBase64Order.enhancedCoder.encode(reason.getBytes("UTF-8"))); - if (page == null) - record.put("page", ""); - else - record.put("page", kelondroBase64Order.enhancedCoder.encode(page)); + public entry(String subject, String author, String ip, String reason, byte[] page) throws IOException { + record = new HashMap(); + key = subject; + if (key.length() > keyLength) key = key.substring(0, keyLength); + record.put("date", dateString()); + if ((author == null) || (author.length() == 0)) author = "anonymous"; + record.put("author", kelondroBase64Order.enhancedCoder.encode(author.getBytes("UTF-8"))); + if ((ip == null) || (ip.length() == 0)) ip = ""; + record.put("ip", ip); + if ((reason == null) || (reason.length() == 0)) reason = ""; + record.put("reason", kelondroBase64Order.enhancedCoder.encode(reason.getBytes("UTF-8"))); + if (page == null) + record.put("page", ""); + else + record.put("page", kelondroBase64Order.enhancedCoder.encode(page)); authors.put(ip, author); //System.out.println("DEBUG: setting author " + author + " for ip = " + ip + ", authors = " + authors.toString()); - } + } - private entry(String key, Map record) { - this.key = key; - this.record = record; - } + private entry(String key, Map record) { + this.key = key; + this.record = record; + } - public String subject() { - return key; - } + public String subject() { + return key; + } - public Date date() { - try { - String c = (String) record.get("date"); - if (c == null) { - System.out.println("DEBUG - ERROR: date field missing in wikiBoard"); - return new Date(); + public Date date() { + try { + String c = (String) record.get("date"); + if (c == null) { + System.out.println("DEBUG - ERROR: date field missing in wikiBoard"); + return new Date(); + } + return SimpleFormatter.parse(c); + } catch (ParseException e) { + return new Date(); + } } - return SimpleFormatter.parse(c); - } catch (ParseException e) { - return new Date(); - } - } - public String author() { - String a = (String) record.get("author"); - if (a == null) return "anonymous"; - byte[] b = kelondroBase64Order.enhancedCoder.decode(a); - if (b == null) return "anonymous"; - return new String(b); - } + public String author() { + String a = (String) record.get("author"); + if (a == null) return "anonymous"; + byte[] b = kelondroBase64Order.enhancedCoder.decode(a); + if (b == null) return "anonymous"; + return new String(b); + } - public String reason() { - String r = (String) record.get("reason"); - if (r == null) return ""; - byte[] b = kelondroBase64Order.enhancedCoder.decode(r); - if (b == null) return "unknown"; - return new String(b); - } + public String reason() { + String r = (String) record.get("reason"); + if (r == null) return ""; + byte[] b = kelondroBase64Order.enhancedCoder.decode(r); + if (b == null) return "unknown"; + return new String(b); + } - public byte[] page() { - String m = (String) record.get("page"); - if (m == null) return new byte[0]; - byte[] b = kelondroBase64Order.enhancedCoder.decode(m); - if (b == null) return "".getBytes(); - return b; - } - - private void setAncestorDate(Date date) { - record.put("bkp", dateString(date)); - } + public byte[] page() { + String m = (String) record.get("page"); + if (m == null) return new byte[0]; + byte[] b = kelondroBase64Order.enhancedCoder.decode(m); + if (b == null) return "".getBytes(); + return b; + } - private Date getAncestorDate() { - try { - String c = (String) record.get("date"); - if (c == null) return null; - return SimpleFormatter.parse(c); - } catch (ParseException e) { - return null; - } - } + private void setAncestorDate(Date date) { + record.put("bkp", dateString(date)); + } + + private Date getAncestorDate() { + try { + String c = (String) record.get("date"); + if (c == null) return null; + return SimpleFormatter.parse(c); + } catch (ParseException e) { + return null; + } + } /* public boolean hasAncestor() { @@ -245,76 +245,80 @@ public class wikiBoard { return false; } } - */ - - public entry getAncestor() { - Date ancDate = getAncestorDate(); - if (ancDate == null) return null; - return read(key + dateString(ancDate), bkpbase); - } + */ + + public entry getAncestor() { + Date ancDate = getAncestorDate(); + if (ancDate == null) return null; + return read(key + dateString(ancDate), bkpbase); + } + + private void setChild(String subject) { + record.put("child", kelondroBase64Order.enhancedCoder.encode(subject.getBytes())); + } - private void setChild(String subject) { - record.put("child", kelondroBase64Order.enhancedCoder.encode(subject.getBytes())); - } - private String getChildName() { String c = (String) record.get("child"); - if (c == null) return null; - byte[] subject = kelondroBase64Order.enhancedCoder.decode(c); + if (c == null) return null; + byte[] subject = kelondroBase64Order.enhancedCoder.decode(c); if (subject == null) return null; return new String(subject); - } - + } + public boolean hasChild() { String c = (String) record.get("child"); - if (c == null) return false; - byte[] subject = kelondroBase64Order.enhancedCoder.decode(c); + if (c == null) return false; + byte[] subject = kelondroBase64Order.enhancedCoder.decode(c); return (subject != null); - } + } public entry getChild() { - String childName = getChildName(); - if (childName == null) return null; - return read(childName, datbase); - } + String childName = getChildName(); + if (childName == null) return null; + return read(childName, datbase); + } } public String write(entry page) { - // writes a new page and returns key - try { - // first load the old page - entry oldEntry = read(page.key); - // set the bkp date of the new page to the date of the old page - Date oldDate = oldEntry.date(); - page.setAncestorDate(oldDate); + // writes a new page and returns key + try { + // first load the old page + entry oldEntry = read(page.key); + // set the bkp date of the new page to the date of the old page + Date oldDate = oldEntry.date(); + page.setAncestorDate(oldDate); oldEntry.setChild(page.subject()); - // write the backup + // write the backup //System.out.println("key = " + page.key); //System.out.println("oldDate = " + oldDate); //System.out.println("record = " + oldEntry.record.toString()); - bkpbase.set(page.key + dateString(oldDate), oldEntry.record); - // write the new page - datbase.set(page.key, page.record); - return page.key; - } catch (IOException e) { - return null; - } + bkpbase.set(page.key + dateString(oldDate), oldEntry.record); + // write the new page + datbase.set(page.key, page.record); + return page.key; + } catch (IOException e) { + return null; + } } public entry read(String key) { - return read(key, datbase); + return read(key, datbase); } private entry read(String key, kelondroMapObjects base) { - try { - key = normalize(key); - if (key.length() > keyLength) key = key.substring(0, keyLength); - Map record = base.getMap(key); - if (record == null) return newEntry(key, "anonymous", "127.0.0.1", "New Page", "".getBytes()); - return new entry(key, record); - } catch (IOException e) { - return null; - } + try { + key = normalize(key); + if (key.length() > keyLength) key = key.substring(0, keyLength); + Map record = base.getMap(key); + if (record == null) return newEntry(key, "anonymous", "127.0.0.1", "New Page", "".getBytes()); + return new entry(key, record); + } catch (IOException e) { + return null; + } + } + + public entry readBkp(String key) { + return read(key, bkpbase); } /* @@ -325,10 +329,13 @@ public class wikiBoard { return false; } } - */ - + */ + public Iterator keys(boolean up) throws IOException { - return datbase.keys(up, false); + return datbase.keys(up, false); } + public Iterator keysBkp(boolean up) throws IOException { + return bkpbase.keys(up, false); + } } diff --git a/source/de/anomic/data/wikiCode.java b/source/de/anomic/data/wikiCode.java index b11a14e9c..e520e8b86 100644 --- a/source/de/anomic/data/wikiCode.java +++ b/source/de/anomic/data/wikiCode.java @@ -171,6 +171,32 @@ public class wikiCode { } return text; } + + public static String deReplaceHTML(String text) { + text = deReplaceHTMLEntities(text); + text = deReplaceXMLEntities(text); + return text; + } + + public static String deReplaceHTMLEntities(String text) { + return deReplace(text, htmlentities); + } + + public static String deReplaceXMLEntities(String text) { + return deReplace(text, xmlentities); + } + + public static String deReplace(String text, String[] entities) { + if (text == null) return null; + for (int i=entities.length-1; i>0; i-=2) { + int p = 0; + while ((p = text.indexOf(entities[i])) >= 0) { + text = text.substring(0, p) + entities[i - 1] + text.substring(p + entities[i].length()); + p += entities[i - 1].length(); + } + } + return text; + } //This array contains codes (see http://mindprod.com/jgloss/unicode.html for details) //that will be replaced. To add new codes or patterns, just put them at the end