diff options
author | Wade Brainerd <wadetb@gmail.com> | 2008-05-08 11:00:00 (GMT) |
---|---|---|
committer | Wade Brainerd <wadetb@gmail.com> | 2008-05-08 11:00:00 (GMT) |
commit | e4ba8a2e24b5496a53042d7dd8f6c75e869d4292 (patch) | |
tree | 5eb8b511c8fcb6c3d9dfadb75ae3756cf186bec8 | |
parent | 2b6d6694259e024dc05112d25e1b9160f5d013cb (diff) |
Support for choosing JavaScript parsers using /wiki/Title?parser={0,1,2}. This should be helpful in identifying the differences between parsers.
Added instaview-0.6.4 (and fixed one bug in it already).
Changed query format to /search?q=Text to allow for future Search box.
-rw-r--r-- | AUTHORS | 6 | ||||
-rw-r--r-- | MANIFEST | 50 | ||||
-rwxr-xr-x | NEWS | 3 | ||||
-rw-r--r-- | activity/activity-web.svg | 15 | ||||
-rw-r--r-- | js/instaview-0.6.1.js (renamed from js/instaview.js) | 340 | ||||
-rw-r--r-- | js/instaview-0.6.4.js | 1379 | ||||
-rw-r--r-- | js/wiki2html.js | 27 | ||||
-rw-r--r-- | py/server.py | 79 | ||||
-rwxr-xr-x | sh/pyserver | 3 |
9 files changed, 1643 insertions, 259 deletions
@@ -1,3 +1,7 @@ Patrick Collison <patrick@collison.ie> -Some code from bzip2 and the FreeBSD implementation of locate has been used; more details are provided in README
\ No newline at end of file +Some code from bzip2 and the FreeBSD implementation of locate has been used; more details are provided in README + +OLPC adaptation by: +* Chris Ball <cjb@pullcord.laptop.org> +* Wade Brainerd <wadetb@gmail.com> diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..b8b4e81 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,50 @@ +MANIFEST +NEWS +COPYING +AUTHORS +40ormore.xml.bz2.processed +40ormore.xml.bz2.blocks.db +40ormore.xml.bz2.locate.db +40ormore.xml.bz2.locate.prefixdb +cert8.db +setup.py +activity.py +activity/activity-wikipedia.svg +activity/activity.info +py/wp.py +py/_wp.so +py/wp/wp.i +py/wp/setup.py +py/server.py +js/instaview.js +c/README +c/AUTHORS +c/NEWS +c/COPYING +c/INSTALL +c/ChangeLog +c/lsearcher.h +c/Makefile.in +c/lsearcher.c +c/wp.h +c/wp.c +c/indexer.s +c/bzipreader.h +c/safe.h +c/bootstrap.sh +c/Makefile.am +c/search.h +c/searcher.c +c/configure.ac +c/indexer.i +c/aclocal.m4 +c/safe.o +c/ternary.h +c/debug.h +c/indexer.c +c/bzipreader.c +c/search.c +c/safe.c +c/livesearch.c +c/configure +c/blocks.c @@ -0,0 +1,3 @@ +1
+
+* Preview release of activity wrapper for wikiserver.
diff --git a/activity/activity-web.svg b/activity/activity-web.svg deleted file mode 100644 index c8f466a..0000000 --- a/activity/activity-web.svg +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd' [ - <!ENTITY stroke_color "#010101"> - <!ENTITY fill_color "#FFFFFF"> -]><svg enable-background="new 0 0 55 55" height="55px" version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" y="0px"><g display="block" id="activity-browse"> - <circle cx="27.375" cy="27.5" display="inline" fill="&fill_color;" r="19.903" stroke="&stroke_color;" stroke-width="3.5"/> - <g display="inline"> - <path d="M27.376,7.598c0,0-11.205,8.394-11.205,19.976 c0,11.583,11.205,19.829,11.205,19.829" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/> - <path d="M27.376,7.598c0,0,11.066,9.141,11.066,19.976 c0,10.839-11.066,19.829-11.066,19.829" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5"/> - <line fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" x1="27.376" x2="27.376" y1="7.598" y2="47.402"/> - <line fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" x1="27.376" x2="27.376" y1="7.598" y2="47.402"/> - <line fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" x1="27.376" x2="27.376" y1="7.598" y2="47.402"/> - <line fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" x1="7.472" x2="47.278" y1="27.5" y2="27.5"/> - </g> -</g></svg> - diff --git a/js/instaview.js b/js/instaview-0.6.1.js index f7d8638..e8ec28b 100644 --- a/js/instaview.js +++ b/js/instaview-0.6.1.js @@ -1,39 +1,7 @@ -/* <pre><nowiki> -This is a copy of InstaView for use in other applications like [[User:Cacycle/wikEd|wikEd]]. - -Changes made: - Fixed code duplication, fixed "doubled article name" bug in links. Cacycle 00:56, 9 September 2007 (UTC) - The "Script to embed InstaView in MediaWiki's edit page" has been commented out - added: // get values from MediaWiki global variables (Cacycle) - -Installation: - if (typeof(InstaView) != 'object')) { - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = 'http://en.wikipedia.org/w/index.php?title=User:Pilaf/dev/instaview.js&action=raw&ctype=text/javascript&dontcountme=s'; - document.getElementsByTagName('head')[0].appendChild(script); - } - -*/ - -// Last update: Cacycle 00:56, 9 September 2007 (UTC) - -/* -// Script to embed InstaView in MediaWiki's edit page -addOnloadHook(function(){ - if (document.getElementById('editpage-copywarn')) { - var oldPreview = document.getElementById('wpPreview'); - var newPreview = document.createElement('input'); - newPreview.setAttribute('type', 'button'); - newPreview.setAttribute('style', 'font-style: italic'); - newPreview.setAttribute('value', 'InstaView'); - newPreview.setAttribute('onclick', "InstaView.dump('wpTextbox1', 'InstaViewDump')"); - oldPreview.parentNode.insertBefore(newPreview, oldPreview); - oldPreview.parentNode.innerHTML += '<div style="margin: 5px 0 5px 0; padding: 5px; border: 2px solid orange;" id="InstaViewDump"></div>'; - oldPreview.value = 'Classic Preview'; - } -}); -*/ +function convert_wiki_to_html(wiki) +{ + return InstaView.convert(wiki); +} /* * InstaView - a Mediawiki to HTML converter in JavaScript @@ -66,21 +34,21 @@ addOnloadHook(function(){ * - Support for templates (through AJAX) * - Support for coloured links (AJAX) */ - - + + var InstaView = {} - + // options InstaView.conf = { user: {}, - + wiki: { lang: 'en', interwiki: 'ab|aa|af|ak|sq|als|am|ang|ar|an|arc|hy|roa-rup|as|ast|av|ay|az|bm|ba|eu|be|bn|bh|bi|bs|br|bg|my|ca|ch|ce|chr|chy|ny|zh|zh-tw|zh-cn|cho|cv|kw|co|cr|hr|cs|da|dv|nl|dz|en|eo|et|ee|fo|fj|fi|fr|fy|ff|gl|ka|de|got|el|kl|gn|gu|ht|ha|haw|he|hz|hi|ho|hu|is|io|ig|id|ia|ie|iu|ik|ga|it|ja|jv|kn|kr|csb|ks|kk|km|ki|rw|rn|tlh|kv|kg|ko|kj|ku|ky|lo|la|lv|li|ln|lt|jbo|nds|lg|lb|mk|mg|ms|ml|mt|gv|mi|minnan|mr|mh|zh-min-nan|mo|mn|mus|nah|na|nv|ne|se|no|nn|oc|or|om|pi|fa|pl|pt|pa|ps|qu|ro|rm|ru|sm|sg|sa|sc|gd|sr|sh|st|tn|sn|scn|simple|sd|si|sk|sl|so|st|es|su|sw|ss|sv|tl|ty|tg|ta|tt|te|th|bo|ti|tpi|to|tokipona|ts|tum|tr|tk|tw|uk|ur|ug|uz|ve|vi|vo|wa|cy|wo|xh|ii|yi|yo|za|zu', default_thumb_width: 180 }, - + paths: { articles: '/wiki/', math: '/math/', @@ -88,7 +56,7 @@ InstaView.conf = images_fallback: 'http://upload.wikimedia.org/wikipedia/commons/', magnify_icon: 'skins/common/images/magnify-clip.png' }, - + locale: { user: 'User', image: 'Image', @@ -96,41 +64,41 @@ InstaView.conf = months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] } } - - + + // get values from MediaWiki global variables (Cacycle) if (typeof(wgArticlePath) != 'undefined') { InstaView.conf.paths.articles = wgArticlePath.replace(/\$1/, ''); } if (typeof(wgContentLanguage) != 'undefined') { InstaView.conf.wiki.lang = wgContentLanguage; } - + // options with default values or backreferences with (InstaView.conf) { user.name = user.name || 'Wikipedian' user.signature = '[['+locale.user+':'+user.name+'|'+user.name+']]' paths.images = 'http://upload.wikimedia.org/wikipedia/' + wiki.lang + '/' } - + // define constants InstaView.BLOCK_IMAGE = new RegExp('^\\[\\['+InstaView.conf.locale.image+':.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i'); - + InstaView.dump = function(from, to) { if (typeof from == 'string') from = document.getElementById(from) if (typeof to == 'string') to = document.getElementById(to) to.innerHTML = this.convert(from.value) } - + InstaView.convert = function(wiki) { var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode o='', // output p=0, // para flag $r // result of passing a regexp to $() - + // some shorthands function remain() { return ll.length } function sh() { return ll.shift() } // shift function ps(s) { o+=s } // push - + function f() // similar to C's printf, uses ? as placeholders, ?? to escape question marks { var i=1,a=arguments,f=a[0],o='',c,p @@ -142,99 +110,99 @@ InstaView.convert = function(wiki) } else break; return o+f } - + function html_entities(s) { return s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">") } - + function max(a,b) { return (a>b)?a:b } function min(a,b) { return (a<b)?a:b } - + // return the first non matching character position between two strings function str_imatch(a, b) { for (var i=0, l=min(a.length, b.length); i<l; i++) if (a.charAt(i)!=b.charAt(i)) break return i } - + // compare current line against a string or regexp // if passed a string it will compare only the first string.length characters // if passed a regexp the result is stored in $r function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)) } - + function $$(c) { return ll[0]==c } // compare current line against a string function _(p) { return ll[0].charAt(p) } // return char at pos p - + function endl(s) { ps(s); sh() } - + function parse_list() { var prev=''; - + while (remain() && $(/^([*#:;]+)(.*)$/)) { - + var l_match = $r - + sh() - + var ipos = str_imatch(prev, l_match[1]) - + // close uncontinued lists for (var i=prev.length-1; i >= ipos; i--) { - + var pi = prev.charAt(i) - + if (pi=='*') ps('</ul>') else if (pi=='#') ps('</ol>') // close a dl only if the new item is not a dl item (:, ; or empty) else switch (l_match[1].charAt(i)) { case'':case'*':case'#': ps('</dl>') } } - + // open new lists for (var i=ipos; i<l_match[1].length; i++) { - + var li = l_match[1].charAt(i) - + if (li=='*') ps('<ul>') else if (li=='#') ps('<ol>') // open a new dl only if the prev item is not a dl item (:, ; or empty) else switch(prev.charAt(i)) { case'':case'*':case'#': ps('<dl>') } } - + switch (l_match[1].charAt(l_match[1].length-1)) { - + case '*': case '#': ps('<li>' + parse_inline_nowiki(l_match[2])); break - + case ';': ps('<dt>') - + var dt_match - + // handle ;dt :dd format if (dt_match = l_match[2].match(/(.*?) (:.*?)$/)) { - + ps(parse_inline_nowiki(dt_match[1])) ll.unshift(dt_match[2]) - + } else ps(parse_inline_nowiki(l_match[2])) - + break - + case ':': ps('<dd>' + parse_inline_nowiki(l_match[2])) } - + prev=l_match[1] } - + // close remaining lists for (var i=prev.length-1; i>=0; i--) ps(f('</?>', (prev.charAt(i)=='*')? 'ul': ((prev.charAt(i)=='#')? 'ol': 'dl'))) } - + function parse_table() { endl(f('<table?>', $(/^\{\|( .*)$/)? $r[1]: '')) - + for (;remain();) if ($('|')) switch (_(1)) { case '}': endl('</table>'); return case '-': endl(f('<tr ?>', $(/\|-*(.*)/)[1])); break @@ -243,43 +211,43 @@ InstaView.convert = function(wiki) else if ($('!')) parse_table_data() else sh() } - + function parse_table_data() { var td_line, match_i - + // 1: "|+", '|' or '+' // 2: ?? // 3: attributes ?? // TODO: finish commenting this regexp var td_match = sh().match(/^(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/) - + if (td_match[1] == '|+') ps('<caption'); else ps('<t' + ((td_match[1]=='|')?'d':'h')) - + if (typeof td_match[3] != 'undefined') { - + ps(' ' + td_match[3]) match_i = 4 - + } else match_i = 2 - + ps('>') - + if (td_match[1] != '|+') { - + // use || or !! as a cell separator depending on context // NOTE: when split() is passed a regexp make sure to use non-capturing brackets td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/) - + ps(parse_inline_nowiki(td_line.shift())) - + while (td_line.length) ll.unshift(td_match[1] + td_line.pop()) - + } else ps(td_match[match_i]) - + var tc = 0, td = [] - + for (;remain(); td.push(sh())) if ($('|')) { if (!tc) break // we're at the outer-most level (no nested tables), skip to td parse @@ -287,32 +255,32 @@ InstaView.convert = function(wiki) } else if (!tc && $('!')) break else if ($('{|')) tc++ - + if (td.length) ps(InstaView.convert(td)) } - + function parse_pre() { ps('<pre>') do endl(parse_inline_nowiki(ll[0].substring(1)) + "\n"); while (remain() && $(' ')) ps('</pre>') } - + function parse_block_image() { ps(parse_image(sh())) } - + function parse_image(str) { // get what's in between "[[Image:" and "]]" var tag = str.substring(InstaView.conf.locale.image.length + 3, str.length - 2); - + var width; var attr = [], filename, caption = ''; var thumb=0, frame=0, center=0; var align=''; - + if (tag.match(/\|/)) { // manage nested links var nesting = 0; @@ -332,13 +300,13 @@ InstaView.convert = function(wiki) i--; } } - + attr = tag.split(/\s*\|\s*/); attr.push(last_attr); filename = attr.shift(); - + var w_match; - + for (;attr.length; attr.shift()) if (w_match = attr[0].match(/^(\d*)px$/)) width = w_match[1] else switch(attr[0]) { @@ -361,21 +329,21 @@ InstaView.convert = function(wiki) default: if (attr.length == 1) caption = attr[0]; } - + } else filename = tag; - - + + var o=''; - + if (frame) { - + if (align=='') align = 'right'; - + o += f("<div class='thumb t?'>", align); - + if (thumb) { if (!width) width = InstaView.conf.wiki.default_thumb_width; - + o += f("<div style='width:?px;'>?", 2+width*1, make_image(filename, caption, width)) + f("<div class='thumbcaption'><div class='magnify' style='float:right'><a href='?' class='internal' title='Enlarge'><img src='?'></a></div>?</div>", InstaView.conf.paths.articles + InstaView.conf.locale.image + ':' + filename, @@ -385,24 +353,24 @@ InstaView.convert = function(wiki) } else { o += '<div>' + make_image(filename, caption) + f("<div class='thumbcaption'>?</div>", parse_inline_nowiki(caption)) } - + o += '</div></div>'; - + } else if (align != '') { o += f("<div class='float?'><span>?</span></div>", align, make_image(filename, caption, width)); } else { return make_image(filename, caption, width); } - + return center? f("<div class='center'>?</div>", o): o; } - + function parse_inline_nowiki(str) { var start, lastend=0 var substart=0, nestlev=0, open, close, subloop; var html=''; - + while (-1 != (start = str.indexOf('<nowiki>', substart))) { html += parse_inline_wiki(str.substring(lastend, start)); start += 8; @@ -429,35 +397,35 @@ InstaView.convert = function(wiki) } } while (subloop) } - + return html + parse_inline_wiki(str.substr(lastend)); } - + function make_image(filename, caption, width) { // uppercase first letter in file name filename = filename.charAt(0).toUpperCase() + filename.substr(1); // replace spaces with underscores filename = filename.replace(/ /g, '_'); - + caption = strip_inline_wiki(caption); - + var md5 = hex_md5(filename); - + var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename; - + if (width) width = "width='" + width + "px'"; - + var img = f("<img onerror=\"this.onerror=null;this.src='?'\" src='?' ? ?>", InstaView.conf.paths.images_fallback + source, InstaView.conf.paths.images + source, (caption!='')? "alt='" + caption + "'" : '', width); - + return f("<a class='image' ? href='?'>?</a>", (caption!='')? "title='" + caption + "'" : '', InstaView.conf.paths.articles + InstaView.conf.locale.image + ':' + filename, img); } - + function parse_inline_images(str) { var start, substart=0, nestlev=0; var loop, close, open, wiki, html; - + while (-1 != (start=str.indexOf('[[', substart))) { if(str.substr(start+2).match(RegExp('^' + InstaView.conf.locale.image + ':','i'))) { loop=true; @@ -483,13 +451,13 @@ InstaView.convert = function(wiki) nestlev++; } } while (loop) - + } else break; } - + return str; } - + // the output of this function doesn't respect the FILO structure of HTML // but since most browsers can handle it I'll save myself the hassle function parse_inline_formatting(str) @@ -509,62 +477,62 @@ InstaView.convert = function(wiki) } return o+str.substr(li); } - + function parse_inline_wiki(str) { var aux_match; - + str = parse_inline_images(str); str = parse_inline_formatting(str); - + // math while (aux_match = str.match(/<(?:)math>(.*?)<\/math>/i)) { var math_md5 = hex_md5(aux_match[1]); str = str.replace(aux_match[0], f("<img src='?.png'>", InstaView.conf.paths.math+math_md5)); } - + // Build a Mediawiki-formatted date string var date = new Date; var minutes = date.getUTCMinutes(); if (minutes < 10) minutes = '0' + minutes; var date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), InstaView.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear()); - + // text formatting return str. // signatures replace(/~{5}(?!~)/g, date). replace(/~{4}(?!~)/g, InstaView.conf.user.name+' '+date). replace(/~{3}(?!~)/g, InstaView.conf.user.name). - + // [[:Category:...]], [[:Image:...]], etc... replace(RegExp('\\[\\[:((?:'+InstaView.conf.locale.category+'|'+InstaView.conf.locale.image+'|'+InstaView.conf.wiki.interwiki+'):.*?)\\]\\]','gi'), "<a href='"+InstaView.conf.paths.articles+"$1'>$1</a>"). replace(RegExp('\\[\\[(?:'+InstaView.conf.locale.category+'|'+InstaView.conf.wiki.interwiki+'):.*?\\]\\]','gi'),''). - + // [[/Relative links]] replace(/\[\[(\/[^|]*?)\]\]/g, f("<a href='?$1'>$1</a>", location)). - + // [[/Replaced|Relative links]] replace(/\[\[(\/.*?)\|(.+?)\]\]/g, f("<a href='?$1'>$2</a>", location)). - + // [[Common links]] replace(/\[\[([^|]*?)\]\](\w*)/g, f("<a href='?$1'>$1$2</a>", InstaView.conf.paths.articles)). - + // [[Replaced|Links]] replace(/\[\[(.*?)\|([^\]]+?)\]\](\w*)/g, f("<a href='?$1'>$2$3</a>", InstaView.conf.paths.articles)). - + // [[Stripped:Namespace|Namespace]] replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, f("<a href='?$1$2$3'>$2</a>", InstaView.conf.paths.articles)). - + // External links replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, "<a href='$1:$2$3'>$4</a>"). replace(/\[http:\/\/(.*?)\]/g, "<a href='http://$1'>[#]</a>"). replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, "<a href='$1:$2$3'>$1:$2$3</a>"). replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*)/g, "$1<a href='$2:$3$4'>$2:$3$4</a>"). - + replace('__NOTOC__',''). replace('__NOEDITSECTION__',''); } - + function strip_inline_wiki(str) { return str @@ -572,34 +540,34 @@ InstaView.convert = function(wiki) .replace(/\[\[(.*?)\]\]/g,'$1') .replace(/''(.*?)''/g,'$1'); } - + // begin parsing for (;remain();) if ($(/^(={1,6})(.*)\1(.*)$/)) { p=0 endl(f('<h?>?</h?>?', $r[1].length, parse_inline_nowiki($r[2]), $r[1].length, $r[3])) - + } else if ($(/^[*#:;]/)) { p=0 parse_list() - + } else if ($(' ')) { p=0 parse_pre() - + } else if ($('{|')) { p=0 parse_table() - + } else if ($(/^----+$/)) { p=0 endl('<hr>') - + } else if ($(InstaView.BLOCK_IMAGE)) { p=0 parse_block_image() - + } else { - + // handle paragraphs if ($$('')) { if (p = (remain()>1 && ll[1]==(''))) endl('<p><br>') @@ -610,14 +578,14 @@ InstaView.convert = function(wiki) } ps(parse_inline_nowiki(ll[0]) + ' ') } - + sh(); } - + return o } - - + + /* * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algorithm, as defined in RFC 1321. @@ -626,14 +594,14 @@ InstaView.convert = function(wiki) * Distributed under the BSD License * See http://pajhome.org.uk/crypt/md5 for more info. */ - + /* * Configurable variables. You may need to tweak these to be compatible with * the server-side, but the defaults work in most cases. */ var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ - + /* * These are the functions you'll usually want to call * They take string arguments and return either hex or base-64 encoded strings @@ -647,7 +615,7 @@ function b64_hmac_md5(k, d) { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } function any_hmac_md5(k, d, e) { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } - + /* * Calculate the MD5 of a raw string */ @@ -655,7 +623,7 @@ function rstr_md5(s) { return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); } - + /* * Calculate the HMAC-MD5, of a key and some data (raw strings) */ @@ -663,18 +631,18 @@ function rstr_hmac_md5(key, data) { var bkey = rstr2binl(key); if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); - + var ipad = Array(16), opad = Array(16); for(var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } - + var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); } - + /* * Convert a raw string to a hex string */ @@ -691,7 +659,7 @@ function rstr2hex(input) } return output; } - + /* * Convert a raw string to a base-64 string */ @@ -713,7 +681,7 @@ function rstr2b64(input) } return output; } - + /* * Convert a raw string to an arbitrary string encoding */ @@ -722,14 +690,14 @@ function rstr2any(input, encoding) var divisor = encoding.length; var remainders = Array(); var i, q, x, quotient; - + /* Convert to an array of 16-bit big-endian values, forming the dividend */ var dividend = Array(input.length / 2); for(i = 0; i < dividend.length; i++) { dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); } - + /* * Repeatedly perform a long division. The binary array forms the dividend, * the length of the encoding is the divisor. Once computed, the quotient @@ -751,15 +719,15 @@ function rstr2any(input, encoding) remainders[remainders.length] = x; dividend = quotient; } - + /* Convert the remainders to the output string */ var output = ""; for(i = remainders.length - 1; i >= 0; i--) output += encoding.charAt(remainders[i]); - + return output; } - + /* * Encode a string as utf-8. * For efficiency, this assumes the input is valid utf-16. @@ -769,7 +737,7 @@ function str2rstr_utf8(input) var output = ""; var i = -1; var x, y; - + while(++i < input.length) { /* Decode utf-16 surrogate pairs */ @@ -780,7 +748,7 @@ function str2rstr_utf8(input) x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); i++; } - + /* Encode output as utf-8 */ if(x <= 0x7F) output += String.fromCharCode(x); @@ -799,7 +767,7 @@ function str2rstr_utf8(input) } return output; } - + /* * Encode a string as utf-16 */ @@ -811,7 +779,7 @@ function str2rstr_utf16le(input) (input.charCodeAt(i) >>> 8) & 0xFF); return output; } - + function str2rstr_utf16be(input) { var output = ""; @@ -820,7 +788,7 @@ function str2rstr_utf16be(input) input.charCodeAt(i) & 0xFF); return output; } - + /* * Convert a raw string to an array of little-endian words * Characters >255 have their high-byte silently ignored. @@ -834,7 +802,7 @@ function rstr2binl(input) output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); return output; } - + /* * Convert an array of little-endian words to a string */ @@ -845,7 +813,7 @@ function binl2rstr(input) output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); return output; } - + /* * Calculate the MD5 of an array of little-endian words, and a bit length. */ @@ -854,19 +822,19 @@ function binl_md5(x, len) /* append padding */ x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; - + var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; - + for(var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; - + a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); @@ -883,7 +851,7 @@ function binl_md5(x, len) d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); - + a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); @@ -900,7 +868,7 @@ function binl_md5(x, len) d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); - + a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); @@ -917,7 +885,7 @@ function binl_md5(x, len) d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); - + a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); @@ -934,7 +902,7 @@ function binl_md5(x, len) d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); - + a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); @@ -942,7 +910,7 @@ function binl_md5(x, len) } return Array(a, b, c, d); } - + /* * These functions implement the four basic operations the algorithm uses. */ @@ -966,7 +934,7 @@ function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); } - + /* * Add integers, wrapping at 2^32. This uses 16-bit operations internally * to work around bugs in some JS interpreters. @@ -977,7 +945,7 @@ function safe_add(x, y) var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } - + /* * Bitwise rotate a 32-bit number to the left. */ diff --git a/js/instaview-0.6.4.js b/js/instaview-0.6.4.js new file mode 100644 index 0000000..dec30f0 --- /dev/null +++ b/js/instaview-0.6.4.js @@ -0,0 +1,1379 @@ +function convert_wiki_to_html(wiki) +{ + return InstaView.convert(wiki); +} + +var InstaView = {} + +// options +InstaView.conf = +{ + user: {}, + + wiki: { + lang: 'en', + interwiki: 'ab|aa|af|ak|sq|als|am|ang|ar|an|arc|hy|roa-rup|as|ast|av|ay|az|bm|ba|eu|be|bn|bh|bi|bs|br|bg|my|ca|ch|ce|chr|chy|ny|zh|zh-tw|zh-cn|cho|cv|kw|co|cr|hr|cs|da|dv|nl|dz|en|eo|et|ee|fo|fj|fi|fr|fy|ff|gl|ka|de|got|el|kl|gn|gu|ht|ha|haw|he|hz|hi|ho|hu|is|io|ig|id|ia|ie|iu|ik|ga|it|ja|jv|kn|kr|csb|ks|kk|km|ki|rw|rn|tlh|kv|kg|ko|kj|ku|ky|lo|la|lv|li|ln|lt|jbo|nds|lg|lb|mk|mg|ms|ml|mt|gv|mi|minnan|mr|mh|zh-min-nan|mo|mn|mus|nah|na|nv|ne|se|no|nn|oc|or|om|pi|fa|pl|pt|pa|ps|qu|ro|rm|ru|sm|sg|sa|sc|gd|sr|sh|st|tn|sn|scn|simple|sd|si|sk|sl|so|st|es|su|sw|ss|sv|tl|ty|tg|ta|tt|te|th|bo|ti|tpi|to|tokipona|ts|tum|tr|tk|tw|uk|ur|ug|uz|ve|vi|vo|wa|cy|wo|xh|ii|yi|yo|za|zu', + default_thumb_width: 180 + }, + + paths: { + articles: '/wiki/', + math: '/math/', + images: '', + images_fallback: 'http://upload.wikimedia.org/wikipedia/commons/', + magnify_icon: 'skins/common/images/magnify-clip.png' + }, + + locale: { + user: 'User', + image: 'Image', + category: 'Category', + months: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'] + } +} + +// options with default values or backreferences +with (InstaView.conf) { + user.name = user.name || 'Wikipedian' + user.signature = '[['+locale.user+':'+user.name+'|'+user.name+']]' + paths.images = 'http://upload.wikimedia.org/wikipedia/' + wiki.lang + '/' +} +//reset internal counters + +// pregormated text token +InstaView.inPre = false; + +// the level of nowiki nesting +InstaView.nestlev = 0; + +// define constants +// Maximum number of includes +/**///InstaView.IncNum = 0; + + +// new line token +// One of the folowing strings (or combinaton): +// '\n' | '<br style="display:none;"/>' | '<br class="hidden"/>' | '' +InstaView.br = '\n'; + +//Regular Expression for wiki images processing +InstaView.BLOCK_IMAGE = new RegExp('^\\[\\['+InstaView.conf.locale.image+':.*?\\|.*?(?:frame|thumbnail|thumb|none|right|left|center)', 'i'); + +InstaView.el = function(aID) +{ + return (typeof(aID) != 'string') ? aID : (document.getElementById) ? document.getElementById(aID) + : (document.layers) ? document.layers[aID] : document.all[aID]; +} + + +InstaView.dump = function(from, to) +{ + this.el(to).innerHTML = this.convert( this.el(from).value ) +} + +InstaView.convert = function(wiki) +{ + var ll = (typeof wiki == 'string')? wiki.replace(/\r/g,'').split(/\n/): wiki, // lines of wikicode + o='', // output + p=0, // para flag + $r // result of passing a regexp to $() + + // some shorthands + function remain() { return ll.length } + function sh() { return ll.shift() } // shift + function ps(s) { o+=s } // push + + function f() // similar to C's printf, uses ? as placeholders, ?? to escape question marks + { + var i=1,a=arguments,f=a[0],o='',c,p + for (;i<a.length; i++) if ((p=f.indexOf('?'))+1) { + // allow character escaping + i -= c=f.charAt(p+1)=='?'?1:0 + o += f.substring(0,p)+(c?'?':a[i]) + f=f.substr(p+1+c) + } else break; + return o+f + } + + function html_entities(s) { + // alert("html: "+s+" "+ s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")); + return s.replace(/&/g,"&").replace(/</g,"<").replace(/\"/g,""").replace(/>/g,">") + } + + function max(a,b) { return (a>b)?a:b } + function min(a,b) { return (a<b)?a:b } + + // return the first non matching character position between two strings + function str_imatch(a, b) + { + for (var i=0, l=min(a.length, b.length); i<l; i++) if (a.charAt(i)!=b.charAt(i)) break + return i + } + + // compare current line against a string or regexp + // if passed a string it will compare only the first string.length characters + // if passed a regexp the result is stored in $r + function $(c) { return (typeof c == 'string') ? (ll[0].substr(0,c.length)==c) : ($r = ll[0].match(c)) } + + function $$(c) { return ll[0]==c } // compare current line against a string + function _(p) { return ll[0].charAt(p) } // return char at pos p + + //function endl(s) { ps(s); sh() } + /**/function endl(s) { ps(s+InstaView.br); sh() } + /**/function endP() { /*alert(o);*/ if (p) { p=0; ps('</p>') } return !p; } + /**/function trim(s) { return s.replace(/^\s*(.*)\s*$/, '$1') ; } + /**/function ltrim() { + if (!remain()) return; + var str = ll[0]; + //alert('str = "' + str + '"'); + ll[0] = str.replace(/^\s*(.*)$/, '$1') ; + //alert('ll[0] = "' + ll[0] + '"'); + str = str.replace(/^(\s*)(.*)$/, '$1') ; + ps (str); + //alert('str = "' + str + '"'); + } + + // Delete 1-st empty line. (like MW does - propose to delete ALL empty lines - while not if) + /**/ while ($$('')) sh(); + + function parse_nowiki () + { + var start=0, open=0, close=0; + + while ( InstaView.nestlev || ( remain() && /<nowiki>/i . test( ll[0].substring( start ) ) ) ) { + + open = ll[0] . toLowerCase(). indexOf( '<nowiki>' , start); + close = ll[0]. toLowerCase(). indexOf( '</'+'nowiki>', start); + + // if < nowiki > tag is opened and < / nowiki > closing tag stands before the next < nowiki > (if it exists...) + if (InstaView.nestlev && (close < open || ( open == -1 && close >= 0 ) ) ) { + + // extract the substring from the current line + // (the text between the starting point and closing tag), + // replace '<', '>' and '&' with their html entities + // and push the result to output + ps( html_entities( ll[0] . substring(start, close) ) ); + + // close opened span indicating the borders of each nowiki container + ps( '</span class="nowiki_' + InstaView.nestlev-- + '">' ); + + // and shift the starting point to 9 simbols after closing tag position + start = close + 9; + + // if < nowiki > was found on the line + } else if (open >= 0) { + + // select text before the opening nowiki tag + var before = ll[0] . substring( start, open ); + + // if inside the multiline nowiki replace special html symbols (<, >, &) + // before the opening tag with their html entities otherwise paste the text as it is + // and push the result to output + ps( (InstaView.nestlev) ? html_entities(before) : before ); + + // anyway - create new span indicating the borders of each nowiki container + ps( '<span class="nowiki_' + ++InstaView.nestlev + '">' ); + + // if there are no closing < / nowiki > tags... + if (close == -1) { + + // extract the substring from the current line (the text after the opening tag), + // replace special html symbols after the opening tag with their html entities + // and push the result to output + endl( html_entities( ll[0] . substring(open + 8) ) ); + + // reset the starting point + start=0; + + + // if closing tag stands after the opening ( .. < nowiki > .. < / nowiki > .. ) + } else if ( close > open) { + + // replace special html symbols between the nowiki tags with their html entities + ps( html_entities( ll[0] . substring(open + 8, close) ) ); + + // close opened span indicating the borders of each nowiki container + ps( '</span class="nowiki_' + InstaView.nestlev-- + '">' ); + + + // and shift the starting point to 9 simbols after closing tag position + start = close + 9; + + } + } + + //alert('Current line:\n' + ll[0] + + // '\n InstaView.nestlev = ' + InstaView.nestlev + '\n open = ' + open + '\n close = ' + close ); + + var after = ll[0] . substring( start ); + + // if the line doesn't contain's nowiki tags... + if ( !/<\/?nowiki>/i . test( after ) ) { + + + // if inside the multiline nowiki replace special html symbols (<, >, &) + // before the opening tag with their html entities otherwise paste the text as it is; + // then push the result to output and shift the array of lines + + endl( (InstaView.nestlev) ? html_entities(after) : after ); + } + } + //alert('nowiki ended:\n' + o); + } + + function parse_pre () + { + + function doInPre( $0, $1, $2, $3) + { + //alert(o); + //alert($0+" : "+$1+" : "+$2+" : "+$3); + + if ($2 == '<pre>') { + //var closeindex = $3. toLowerCase(). indexOf( '</'+'pre>', 0); + //var preclose = $3.substring(0,closeindex); + // var close = $3.substring(closeindex); + return $1 + $2 + html_entities($3); + } + return html_entities($1) + $2 + $3; + } + + if ( !remain() ) return; + + if ( ll[0].match('<pre>') && !InstaView.inPre ) { + // alert("one:"+ll[0]); + InstaView.inPre = true; + endl( ll[0].replace(/(.*?)(<pre>)[*</pre>]+/i, doInPre) ); + + } + + while ( InstaView.inPre ) { + + parse_nowiki(); + if ( !remain() ) return; + // alert(o); + if ( !ll[0].match('</'+'pre>') ) endl( html_entities(ll[0]) ); + + else { + // alert("two:"+ll[0]); + InstaView.inPre = false; + endl( ll[0].replace(/(.*?)(<\/pre>)[*<pre>]+/i, doInPre) ); + + } + } + //alert('preformatted line passed:\n' + o); + + } + /* + function dont_parse() + { + + var openmatch = '(<html|<table|<blockquote|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<p|<ul|<ol|<li' + + //.'|<\\/center|<tr|<\\/tr|<\\/td|<\\/th'+ + ')'; + var closematch = '(<\\/html|<\\/table|<\\/blockquote|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|' + + //.'<td|<th|<div|<\\/div|<hr|<\\/pre|<center|' + + '<\\/p|<\\/li|<\\/ul|<\\/ol); + var patterns = [openmatch, closematch] + + if (!remain()) return true; + + //alert(' Open Match: ' + openmatch.test(ll[0]) + '\n Close Match: ' + closematch.test(ll[0]) ) + + op_part = RegExp( '^\\s*' + openmatch + '.*$', 'i' ); + cl_pat = RegExp( '^.*' + closematch + '\\s*$', 'i' ); + + if ( $(op_pat) ) { + + //if (InstaView.BlockEl) ps('</'+'pre>'); + ps('<pre>'); + InstaView.BlockEl = true; + + ltrim(); + //alert('Trimed line with html tag(s):\n' + ll[0]) + + endl(ll[0]); + + return true; + } + + if ( $(cl_pat) ) { + + if (InstaView.BlockEl) ps('</'+'pre>'); + InstaView.BlockEl = false; + + ltrim(); + //alert('Trimed line with html tag(s):\n' + ll[0]) + + endl(ll[0]); + + return true; + } + + + if ( $(/^\s*\{\|/) ) { + + if (this.inPre) ps('</'+'pre>'); + InstaView.BlockEl = false; + + parse_table(); + + return true; + } + return false; + + } + */ + function parse_list() + { + + var prev=''; + var DtOpen = false; + + function next(char) + { + + switch (char) { + + case '*': case '#': + ps('</li><li>'); + //alert('Countinue "ol" or "ul"') + break; + + case ';': + ps( (DtOpen)?'</dt>':'</dd>' + '<dt>' ); + //alert('Countinue "dl" - dt') + break + + case ':': + ps( (DtOpen)?'</dt>':'</dd>' + '<dd>' ); + //alert('Countinue "dl" - dd') + DtOpen = false; + } + } + + function close(pi) + { + //alert("pi is: "+pi); + if (pi=='*') { + ps('</li></ul>'); + //alert('Close "ul"') + } + + else if (pi=='#') { + ps('</li></ol>'); + //alert('Close "ol"') + } + + // close a dl only if the new item is not a dl item (:, ; or empty) + else switch (l_match[1].charAt(i)) { + + case'':case'*':case'#': + + ps( (DtOpen)?'</dt>':'</dd>' + '</dl>' ); + //alert('Close "dl"'); + DtOpen = false; + + } //switch + + // print the line-break after each list's closing tag (if the line isn't last) + //if (remain()>1) + //alert('Close list at: '+ll[0]); + ps(InstaView.br); + + // return t; + + } + + function open(li) + { + + if (li=='*') { + ps('<ul><li>'); + //alert('Start "ul"') + } + + else if (li=='#') { + ps('<ol><li>'); + //alert('Start "ol"') + } + + // do wee need the coparison at all? it don't work... (imho) + else switch(prev.charAt(i)) { + + case'':case'*':case'#': + + // open a new dl only if it is needed for nesting: + // don't add <dl> if the previous and the current + // char are equal to ';' at the same time + + if ( (l_match[1].charAt(i-1) != ';') || (l_match[1].charAt(i) != ';') ) { + ps('<dl>'); + //alert('Start "dl"') + if (li==':') ps('<dd>'); + else { + ps('<dt>'); + DtOpen = true; + } //else + + } // if + + } //else + } + + while (remain() && $(/^([*#:;]+)(.*)$/)) { + + var l_match = $r + + sh() + + var ipos = str_imatch(prev, l_match[1]) + + // continue opened lists + //if ( prev == l_match[1] ) next(l_match[1].charAt(l_match[1].length-1)) + + //else if ( l_match[1].length || prev.length ) { + // alert("we are: " + prev.length+prev+ipos+prev.charAt(0)+ o); + // close uncontinued lists + for (var i=prev.length-1; i >= ipos && prev.length != 0 ; i--) { + // alert("closing: " + prev.charAt(i-1)); + close(prev.charAt(i)); + } + // open new lists + for (var i=ipos; i<l_match[1].length; i++) open(l_match[1].charAt(i)); + + // continue unclosed lists %) + if ( l_match[1].length <= ipos && ipos > 0 ) { + // alert('Continue list: '+ l_match[1][ipos-1] + + // ',\n cause the current prefix is shorter then previous') + // alert("matching: "+ipos+l_match[1]); + next( l_match[1].charAt(ipos-1) ); + } + + // process the remaining wikitext + prev=l_match[1] + //alert("prev is: " + prev+ipos); + // Nested DL's solution - see bug #6569 [http://bugzilla.wikimedia.org/show_bug.cgi?id=6569] + // ps( l_match[1].replace(/^.*?[;:]([;:]*)$/g, '$1') ) + + var dt_match + + var pr_char = prev.charAt(prev.length-1) + + // handle ;dt :dd format + if ( (pr_char == ';') && (dt_match = l_match[2].match(/(.*?) (:.*?)$/) ) ) { + + ps(parse_inline_wiki(dt_match[1])) + //alert(dt_match[1]) + ll.unshift(dt_match[2]) + + } else { + + ps(parse_inline_wiki(l_match[2])); + //alert(l_match[2]) + } + + // print the line-break + ps(InstaView.br); + + + //} // else if + + } // while + + // alert(prev+', '+ipos+o) + for (var i=prev.length-1; i >= ipos-1 && prev.length != 0 && i >= 0; i--) { + // alert("i is: "+i); + // alert('lists processed:\n' + o) ; + close(prev.charAt(i)) ; + // alert('lists processed:\n' + o) + // alert('open:\n' + close(prev.charAt(i))); + } +// alert('lists processed:\n'+prev+ipos + o) + } //function + + function parse_table() + { + ltrim(); + //alert('ll[0] = "' + ll[0] + '"'); + /**/endl(f('<table?>', $(/^\s*\{\|( .*)$/)? $r[1] : '' )); + //ps(f('<table?>', $(/^\{\|( .*)$/)? $r[1]: '')); + //sh(); + + while (remain()) { + + ltrim(); + //alert('ll[0] = "' + ll[0] + '"'); + + if ($('|')) switch (_(1)) { + + // close table and parse inline wiki after it + case '}': endl('</table>' + parse_inline_wiki(ll[0].substr(ll[0].indexOf('}')+1))); return + case '-': endl(f('<tr ?>', $(/\|-*(.*)/)[1])); break + default: parse_table_data() + } else if ($('!')) parse_table_data() + //else sh(); + // add new line token and shift the array of lines + /**/else endl('') + } + + } + + function parse_table_data() + { + var td_line, match_i + + // 1: "|+", '|' or '!' + // 2: Full string: + // all the chars before the "|" and "[" but not "||" if such pattern exists in the string ; and any way - the rest of the line + + // (?: .. ) and (?! .. ) doesn't save the matches. So they aren't counted. + // The first matches for pattern agter the colon but not saves it. + // The second matches ig the pattern given after ! doesn't match the string. + // So: + // (?: .. )?(.*)$ - if the line before the '|' exists (see #3) return "substring"+"the_rest_of_the_line" ; otherwise return "the rest of the line" only + // (?!\|) - not a "|" + + // 3: attribute - any minimal (maybe even 0-length) number of occurances of neither "[" nor "|" characters + // 4: The rest of the line - can be less that #2 - any chars till the end of the line + + var td_match = sh().match(/^\s*(\|\+|\||!)((?:([^[|]*?)\|(?!\|))?(.*))$/) + ltrim(); + //alert('td_match =\n' + td_match); + if (td_match[1] == '|+') ps('<caption'); + else ps('<t' + ((td_match[1]=='|')?'d':'h')) + + // the was some attribute + if (typeof td_match[3] != 'undefined') { + + ps(' ' + td_match[3]) + match_i = 4 + + } else match_i = 2 + + /**/ps('>') + //ps('>' + InstaView.br) + + if (td_match[1] != '|+') { + + // use || or !! as a cell separator depending on context + // NOTE: when split() is passed a regexp make sure to use non-capturing brackets + td_line = td_match[match_i].split((td_match[1] == '|')? '||': /(?:\|\||!!)/) + + ps(parse_inline_wiki(td_line.shift())) + + while (td_line.length) ll.unshift(td_match[1] + td_line.pop()) + + } else ps(td_match[match_i]) + + var tc = 0, td = [] + + while (remain()) { + if ($('|')) { + if (!tc) break // we're at the outer-most level (no nested tables), skip to td parse + else if (_(1)=='}') tc-- + } + else if (!tc && $('!')) break + else if ($('{|')) tc++ + + td.push(sh()); + ltrim(); + } + + if (td.length) ps(InstaView.convert(td)) + //add closing <td> or <th> and new line token + /**/ps('</t' + ((td_match[1]=='|')?'d':'h')+'>' + InstaView.br); + } + + function parse_sp_lines() + { + + //close paragraph if it was opened + /**/endP();//p=0 + ps('<pre>'); + + while (_(0)==' ' && remain()) { + + /*if ( !remain() || dont_parse() ) break; + + this.inPre = true; + */ + endl(parse_inline_wiki(ll[0].substring(1))); + + } + if (this.inPre) ps('</'+'pre>'); + + } + + function parse_block_image() + { + //ps(parse_image(sh())) + //add new line token + /**/ps(parse_image(sh()) + InstaView.br) + } + + function parse_image(str) + { + // get what's in between "[[Image:" and "]]" + var tag = str.substring(InstaView.conf.locale.image.length + 3, str.length - 2); + + var width; + var attr = [], filename, caption = ''; + var thumb=0, frame=0, center=0; + var align=''; + + if (tag.match(/\|/)) { + // manage nested links + var nesting = 0; + var last_attr; + for (var i = tag.length-1; i > 0; i--) { + if (tag.charAt(i) == '|' && !nesting) { + last_attr = tag.substr(i+1); + tag = tag.substring(0, i); + break; + } else switch (tag.substr(i-1, 2)) { + case ']]': + nesting++; + i--; + break; + case '[[': + nesting--; + i--; + } + } + + attr = tag.split(/\s*\|\s*/); + attr.push(last_attr); + filename = attr.shift(); + + var w_match; + + for (;attr.length; attr.shift()) + if (w_match = attr[0].match(/^(\d*)px$/)) width = w_match[1] + else switch(attr[0]) { + case 'thumb': + case 'thumbnail': + thumb=true; + case 'frame': + frame=true; + break; + case 'none': + case 'right': + case 'left': + center=false; + align=attr[0]; + break; + case 'center': + center=true; + align='none'; + break; + default: + if (attr.length == 1) caption = attr[0]; + } + + } else filename = tag; + + + var o=''; + + if (frame) { + + if (align=='') align = 'right'; + + o += f('<div class="thumb t?">', align); + + if (thumb) { + if (!width) width = InstaView.conf.wiki.default_thumb_width; + + o += f('<div style="width:?px;">?', 2+width*1, make_image(filename, caption, width)) + + f('<div class="thumbcaption"><div class="magnify" style="float:right"><a href="?" class="internal" title="Enlarge"><img src="?"></a></div>?</div>', + InstaView.conf.paths.articles + InstaView.conf.locale.image + ':' + filename, + InstaView.conf.paths.magnify_icon, + parse_inline_wiki(caption) + ) + } else { + o += '<div>' + make_image(filename, caption) + f('<div class="thumbcaption">?</div>', parse_inline_wiki(caption)) + } + + o += '</div></div>'; + + } else if (align != '') { + o += f('<div class="float?"><span>?</span></div>', align, make_image(filename, caption, width)); + } else { + return make_image(filename, caption, width); + } + //alert(width); + return center? f('<div class="center">?</div>', o): o; + } + + function make_image(filename, caption, width) + { + // uppercase first letter in file name + filename = filename.charAt(0).toUpperCase() + filename.substr(1); + // replace spaces with underscores + filename = filename.replace(/ /g, '_'); + + caption = strip_inline_wiki(caption); + + var md5 = hex_md5(filename); + + var source = md5.charAt(0) + '/' + md5.substr(0,2) + '/' + filename; + + width = (width) ? 'width="' + width + '"' : ''; + + var img = f('<img src="?" ? longdesc="?" ? onerror="this.onerror=null;this.src=\'?\'">', InstaView.conf.paths.images + source, (caption!='')? 'alt="' + caption + '"' : '', InstaView.conf.paths.articles + InstaView.conf.locale.image + ':' + filename, width, InstaView.conf.paths.images_fallback + source); + + return f('<a href="?" class="image" ?>?</a>', InstaView.conf.paths.articles + InstaView.conf.locale.image + ':' + filename, (caption!='')? 'title="' + caption + '"' : '', img); + } + + function parse_inline_images(str) + { + var start, substart=0, nestlev=0; + var loop, close, open, wiki, html; + + while (-1 != (start=str.indexOf('[[', substart))) { + if(str.substr(start+2).match(RegExp('^' + InstaView.conf.locale.image + ':','i'))) { + loop=true; + substart=start; + do { + substart+=2; + close=str.indexOf(']]',substart); + open=str.indexOf('[[',substart); + if (close<=open||open==-1) { + if (close==-1) return str; + substart=close; + if (nestlev) { + nestlev--; + } else { + wiki=str.substring(start,close+2); + html=parse_image(wiki); + str=str.replace(wiki,html); + substart=start+html.length; + loop=false; + } + } else { + substart=open; + nestlev++; + } + } while (loop) + + } else break; + } + + return str; + } + + // the output of this function doesn't respect the FILO structure of HTML + // but since most browsers can handle it I'll save myself the hassle + function parse_inline_formatting(str) + { + var em,st,i,li,o=''; + while ((i=str.indexOf("''",li))+1) { + o += str.substring(li,i); + li=i+2; + if (str.charAt(i+2)=="'") { + li++; + st=!st; + //o+=st?'<strong>':'</strong>'; + //MW uses <b> and <i> + /**/o+=st?'<b>':'</b>'; + + } else { + em=!em; + //o+=em?'<em>':'</em>'; + /**/o+=em?'<i>':'</i>'; + } + } + return o+str.substr(li); + } + + function parse_inline_wiki(str) + { + var aux_match; + + str = parse_inline_images(str); + str = parse_inline_formatting(str); + + // math + while (aux_match = str.match(/<(?:)math>(.*?)<\/math>/i)) { + var math_md5 = hex_md5(aux_match[1]); + str = str.replace(aux_match[0], f('<img src="?.png">', InstaView.conf.paths.math+math_md5)); + } + + // Build a Mediawiki-formatted date string + var date = new Date; + var minutes = date.getUTCMinutes(); + if (minutes < 10) minutes = '0' + minutes; + var date = f("?:?, ? ? ? (UTC)", date.getUTCHours(), minutes, date.getUTCDate(), InstaView.conf.locale.months[date.getUTCMonth()], date.getUTCFullYear()); + + //alert('??????' + urlencode('??????') ); + + // text formatting + return str. + // signatures + replace(/~{5}(?!~)/g, date). + replace(/~{4}(?!~)/g, InstaView.conf.user.name+' '+date). + replace(/~{3}(?!~)/g, InstaView.conf.user.name). +/* +//********************************** + + // {{{ Variables }}} and {{{ Replaced | Variables }}} + replace(/\{\{\{(.*?)(?:\|(.*?))?\}\}\}/g, this.replaceArguments). + // {{ (Striped:)? Templates (| with_args )? }} + replace(/\{\{([^\]]*?:)?(.*?)(?:\|(.*?))?\}\}/g, this.replaceTemplates). + +//********************************** +*/ + // 2Do: Urlencode the article name in ''href'' attribute + // [[:Category:...]], [[:Image:...]], etc... + replace(RegExp('\\[\\[:((?:'+InstaView.conf.locale.category+'|'+InstaView.conf.locale.image+'|'+InstaView.conf.wiki.interwiki+'):.*?)\\]\\]','gi'), '<a href="'+InstaView.conf.paths.articles+'$1" title="$1">$1</a>'). + replace(RegExp('\\[\\[('+InstaView.conf.locale.category+'|'+InstaView.conf.wiki.interwiki+'):(.*?)\\]\\]','gi'), '<span dir="ltr" style="display:none"><a href="'+InstaView.conf.paths.articles+'$1:$2" title="$1:$2">$2</a></span>'). + + // [[/Relative links]] + replace(/\[\[(\/[^|]*?)\]\]/g, f('<a href="?$1" title="$1">$1</a>', location)). + + // [[/Replaced|Relative links]] + replace(/\[\[(\/.*?)\|(.+?)\]\]/g, f('<a href="?$1" title="$1">$2</a>', location)). + + // Bug: Non-english words are ignored due to \w + // Solved for cyrilic: \w -> [\w?-??] + // Bug: Upcase chars should be ignored, they dont + // Solved: \w - > [a-z] + + // [[Common links]]with_trail + replace(/\[\[([^|]*?)\]\]([a-z?-??]*)/g, f('<a href="?$1" title="$1">$1$2</a>', InstaView.conf.paths.articles)). + + // [[Replaced|Links]]with_trail + replace(/\[\[(.*?)\|([^\]]+?)\]\]([a-z?-??]*)/g, f('<a href="?$1" title="$1">$2$3</a>', InstaView.conf.paths.articles)). + + // [[Stripped:Namespace|]] + replace(/\[\[([^\]]*?:)?(.*?)( *\(.*?\))?\|\]\]/g, f('<a href="?$1$2$3" title="$1$2$3">$2</a>', InstaView.conf.paths.articles)). + + // External links + replace(/\[(https?|news|ftp|mailto|gopher|irc):(\/*)([^\]]*?) (.*?)\]/g, '<a href="$1:$2$3">$4</a>'). + replace(/\[http:\/\/(.*?)\]/g, '<a href="http://$1">[#]</a>'). + replace(/\[(news|ftp|mailto|gopher|irc):(\/*)(.*?)\]/g, '<a href="$1:$2$3">$1:$2$3</a>'). + replace(/(^| )(https?|news|ftp|mailto|gopher|irc):(\/*)([^ $]*)/g, '$1<a href="$2:$3$4">$2:$3$4</a>'). + + replace('__NOTOC__',''). + replace('__NOEDITSECTION__',''); + } + + function strip_inline_wiki(str) + { + return str + .replace(/\[\[[^\]]*\|(.*?)\]\]/g,'$1') + .replace(/\[\[(.*?)\]\]/g,'$1') + .replace(/''(.*?)''/g,'$1'); + } + + // begin parsing + do { + + parse_nowiki(); + parse_pre(); + //dont_parse(); + + if (!remain()) break; + + //parse headings + if ($(/^(={1,6})(.*)\1(.*)$/)) { + //close paragraph if it was opened + /**/endP();//p=0 + endl(f('<h?>?</h?>?', $r[1].length, parse_inline_wiki($r[2]), $r[1].length, $r[3])) + + //alert('headings processed:\n' + o) + + //parse lists + } else if ($(/^[*#:;]/)) { + //close paragraph if it was opened + /**/endP();//p=0 + /**/ps(InstaView.br); + + parse_list() + + //alert('lists processed:\n' + o) + + //parse tables + } else if ($(/^(?:\s*)\{\|/)) { + //alert('ll[0] = "' + ll[0] + '"') + //close paragraph if it was opened + /**/endP();//p=0 + parse_table() + //alert('tables processed:\n' + o) + + //parse lines that start with space + } else if ( _(0) == ' ') { + parse_sp_lines() + //alert('spaced lines processed:\n' + o) + + //do the <hr> + } else if ($(/^----+$/)) { + //close paragraph if it was opened + /**/endP();//p=0 + endl('<hr>') + //alert('horizontal lines processed:\n' + o) + + //parse images + } else if ($(InstaView.BLOCK_IMAGE)) { + //close paragraph if it was opened + /**/endP();//p=0 + parse_block_image() + //alert('images processed:\n' + o) + + } else { + + //escape < /pre > tag cause there's no opening tag and it should be treaten as text + ll[0] = ll[0].replace( '</'+'pre>', '</pre>') + + + // handle paragraphs + if (trim(ll[0]) == '') { //blank line + //if (p = (remain()>1 && ll[1]==(''))) endl('<p><br>') + + //if para was opened - close it + //if 2 empty strings - add hard line break + + if ( endP() ) + if ( remain()>1 ){ + ps('<p>'); + p=1; + + /**/ if (trim(ll[1])==('') ) + /**/ {sh(); ps('<br>'); p=1} + } else break; + } else { + if(!p) { + ps('<p>') + p=1 + } + + if (remain()<2) { + //alert('The last line:' + ll[0]); + ps(parse_inline_wiki(ll[0])); + endP(); + break; + } else ps(parse_inline_wiki(ll[0])); + + //add new line token + //ps(parse_inline_wiki(ll[0]) + InstaView.br) + + //alert('Add inblockElem - in order to disable the creation of new paragraph' + + //'for such elements as:\n tables, headings, lists and so on.' ); + + } + + //alert('paragraphs processed:\n' + o) + + //sh(); + //add new line token and shift the array of lines + /**/endl(''); + } + } while (remain()) + //add closing </tr> + /**/o = o.replace(/(<\/t[dh]>\s*)(<tr (.*)>|<\/table>)/gim, '$1</tr>'+ InstaView.br +'$2') + /**/.replace(/<tr >/gim, '<tr>') + + //escape closing < / nowiki > tags + /**/.replace(/<\/nowiki>/i, '</nowiki>'); + + CatLinks = o.match(/<span dir="ltr" style="display:none">(.*?)<\/span>/gim); + + if (CatLinks) + { + o += '<div id="catlinks"><p class="catlinks">'; + for (i in CatLinks) + { + alert(CatLinks[i]); + o += CatLinks[i].replace(' style="display:none"', ''); + if ( i != CatLinks.length-1 ) { alert(i); alert(CatLinks.length-1); o += ' | ';} + } + o += '</p></div>'; + } + + + /*// - maybe faster, but don't work :(((. + ShortExtLinks = o.match('[#]'); + + for (i in ShortExtLinks) + { + alert(ShortExtLinks[i] + ' ' + i); + o.replace(/\[#\]/m, '[' + i + ']'); + } + */ + i=0; + while ( /\[#\]/m.test(o) ) o=o.replace(/\[#\]/m, '[' + ++i + ']'); + + + //alert('"'+o+'"'); + return o +} + +// +/* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.2-alpha Copyright (C) Paul Johnston 1999 - 2005 + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); } +function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); } +function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); } +function hex_hmac_md5(k, d) + { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } +function b64_hmac_md5(k, d) + { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); } +function any_hmac_md5(k, d, e) + { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); } + +/* + * Calculate the MD5 of a raw string + */ +function rstr_md5(s) +{ + return binl2rstr(binl_md5(rstr2binl(s), s.length * 8)); +} + +/* + * Calculate the HMAC-MD5, of a key and some data (raw strings) + */ +function rstr_hmac_md5(key, data) +{ + var bkey = rstr2binl(key); + if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8); + return binl2rstr(binl_md5(opad.concat(hash), 512 + 128)); +} + +/* + * Convert a raw string to a hex string + */ +function rstr2hex(input) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var output = ""; + var x; + for(var i = 0; i < input.length; i++) + { + x = input.charCodeAt(i); + output += hex_tab.charAt((x >>> 4) & 0x0F) + + hex_tab.charAt( x & 0x0F); + } + return output; +} + +/* + * Convert a raw string to a base-64 string + */ +function rstr2b64(input) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var output = ""; + var len = input.length; + for(var i = 0; i < len; i += 3) + { + var triplet = (input.charCodeAt(i) << 16) + | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0) + | (i + 2 < len ? input.charCodeAt(i+2) : 0); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > input.length * 8) output += b64pad; + else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F); + } + } + return output; +} + +/* + * Convert a raw string to an arbitrary string encoding + */ +function rstr2any(input, encoding) +{ + var divisor = encoding.length; + var remainders = Array(); + var i, q, x, quotient; + + /* Convert to an array of 16-bit big-endian values, forming the dividend */ + var dividend = Array(input.length / 2); + for(i = 0; i < dividend.length; i++) + { + dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1); + } + + /* + * Repeatedly perform a long division. The binary array forms the dividend, + * the length of the encoding is the divisor. Once computed, the quotient + * forms the dividend for the next step. We stop when the dividend is zero. + * All remainders are stored for later use. + */ + while(dividend.length > 0) + { + quotient = Array(); + x = 0; + for(i = 0; i < dividend.length; i++) + { + x = (x << 16) + dividend[i]; + q = Math.floor(x / divisor); + x -= q * divisor; + if(quotient.length > 0 || q > 0) + quotient[quotient.length] = q; + } + remainders[remainders.length] = x; + dividend = quotient; + } + + /* Convert the remainders to the output string */ + var output = ""; + for(i = remainders.length - 1; i >= 0; i--) + output += encoding.charAt(remainders[i]); + + return output; +} + +/* + * Encode a string as utf-8. + * For efficiency, this assumes the input is valid utf-16. + */ +function str2rstr_utf8(input) +{ + var output = ""; + var i = -1; + var x, y; + + while(++i < input.length) + { + /* Decode utf-16 surrogate pairs */ + x = input.charCodeAt(i); + y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0; + if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) + { + x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF); + i++; + } + + /* Encode output as utf-8 */ + if(x <= 0x7F) + output += String.fromCharCode(x); + else if(x <= 0x7FF) + output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F), + 0x80 | ( x & 0x3F)); + else if(x <= 0xFFFF) + output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + else if(x <= 0x1FFFFF) + output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07), + 0x80 | ((x >>> 12) & 0x3F), + 0x80 | ((x >>> 6 ) & 0x3F), + 0x80 | ( x & 0x3F)); + } + return output; +} + +/* + * Encode a string as utf-16 + */ +function str2rstr_utf16le(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode( input.charCodeAt(i) & 0xFF, + (input.charCodeAt(i) >>> 8) & 0xFF); + return output; +} + +function str2rstr_utf16be(input) +{ + var output = ""; + for(var i = 0; i < input.length; i++) + output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF, + input.charCodeAt(i) & 0xFF); + return output; +} + +/* + * Convert a raw string to an array of little-endian words + * Characters >255 have their high-byte silently ignored. + */ +function rstr2binl(input) +{ + var output = Array(input.length >> 2); + for(var i = 0; i < output.length; i++) + output[i] = 0; + for(var i = 0; i < input.length * 8; i += 8) + output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32); + return output; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2rstr(input) +{ + var output = ""; + for(var i = 0; i < input.length * 32; i += 8) + output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF); + return output; +} + +/* + * Calculate the MD5 of an array of little-endian words, and a bit length. + */ +function binl_md5(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + + a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); + c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); + d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return Array(a, b, c, d); +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) +{ + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); +} +function md5_ff(a, b, c, d, x, s, t) +{ + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function md5_gg(a, b, c, d, x, s, t) +{ + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function md5_hh(a, b, c, d, x, s, t) +{ + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii(a, b, c, d, x, s, t) +{ + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} diff --git a/js/wiki2html.js b/js/wiki2html.js index 63ccf52..bbc3043 100644 --- a/js/wiki2html.js +++ b/js/wiki2html.js @@ -1,3 +1,8 @@ +function convert_wiki_to_html(wiki) +{ + return wiki2html(wiki); +} + /* @author: remy sharp / http://remysharp.com @url: http://remysharp.com/2008/04/01/wiki-to-html-using-javascript/ @@ -7,33 +12,13 @@ Can extend String or be used stand alone - just change the flag at the top of the script. */ -(function () { - -var extendString = true; - -if (extendString) { - String.prototype.wiki2html = wiki2html; - String.prototype.iswiki = iswiki; -} else { - window.wiki2html = wiki2html; - window.iswiki = iswiki; -} - // utility function to check whether it's worth running through the wiki2html function iswiki(s) { - if (extendString) { - s = this; - } - return !!(s.match(/^[\s{2} `#\*='{2}]/m)); } // the regex beast... function wiki2html(s) { - if (extendString) { - s = this; - } - // lists need to be done using a function to allow for recusive calls function list(str) { return str.replace(/(?:(?:(?:^|\n)[\*#].*)+)/g, function (m) { // (?=[\*#]) @@ -99,5 +84,3 @@ function wiki2html(s) { }) ); } - -})();
\ No newline at end of file diff --git a/py/server.py b/py/server.py index 4fc575d..148c4df 100644 --- a/py/server.py +++ b/py/server.py @@ -19,70 +19,85 @@ import sys import os import BaseHTTPServer import urllib +import cgi import re import wp +parsers = [ + 'js/wiki2html.js', + 'js/instaview-0.6.1.js', + 'js/instaview-0.6.4.js', +] + +default_parser = 2 + class WikiRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): - @staticmethod - def send_article(s, title): - s.send_response(200) - s.send_header("Content-type", "text/html; charset=utf-8") - s.end_headers() - - s.wfile.write("<html><head><title>%s</title></head>" % title) - s.wfile.write("<body>") + def send_article(self, title): + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.end_headers() + + self.wfile.write("<html><head><title>%s</title></head>" % title) + self.wfile.write("<body>") - instaview_src = open('js/instaview.js').read() - s.wfile.write("<script type='text/javascript'>%s</script>" % instaview_src) + parser_index = int(self.params.get('parser', default_parser)) + instaview_src = open(parsers[parser_index]).read() + self.wfile.write("<script type='text/javascript'>%s</script>" % instaview_src) article_text = unicode(wp.wp_load_article(title), 'utf8') + # Embed article text and call parser. jstext = '' for l in article_text.split('\n'): jstext += re.escape(l) + '\\n\\\n' - s.wfile.write("<script type='text/javascript'>"); - s.wfile.write("var wikitext = \"%s\";" % jstext.encode('utf8')); - s.wfile.write("document.write(InstaView.convert(unescape(wikitext)));"); - s.wfile.write("</script>") + self.wfile.write("<script type='text/javascript'>"); + self.wfile.write("var wikitext = \"%s\";" % jstext.encode('utf8')); + self.wfile.write("document.write(convert_wiki_to_html(unescape(wikitext)));"); + self.wfile.write("</script>") - s.wfile.write("</body></html>") + self.wfile.write("</body></html>") - @staticmethod - def send_searchresult(s, title): - s.send_response(200) - s.send_header("Content-type", "text/html; charset=utf-8") - s.end_headers() + def send_searchresult(self, title): + self.send_response(200) + self.send_header("Content-Type", "text/html; charset=utf-8") + self.end_headers() - s.wfile.write("<html><head><title>Search Results for '%s'</title></head>" % title) - s.wfile.write("<body>") + self.wfile.write("<html><head><title>Search Results for '%s'</title></head>" % title) + self.wfile.write("<body>") - s.wfile.write("<p>You asked for search term %s.</p>" % title) + self.wfile.write("<p>You asked for search term %s.</p>" % title) num_results = wp.wp_search(title) for i in xrange(0, num_results): result = unicode(wp.wp_result(i), 'utf8') - s.wfile.write('<a href="/wiki/%s">%s</a><br>' % + self.wfile.write('<a href="/wiki/%s">%s</a><br>' % (result.encode('utf8'), result.encode('utf8'))) - s.wfile.write("</body></html>") + self.wfile.write("</body></html>") - def do_GET(s): - real_path = s.path + def do_GET(self): + real_path = self.path real_path = urllib.url2pathname(real_path) + (real_path, sep, param_text) = real_path.partition('?') + self.params = {} + for p in param_text.split('&'): + (key, sep, value) = p.partition('=') + self.params[key] = value + m = re.match(r'^/(wiki|raw)/(.+)$', real_path) if m: - WikiRequestHandler.send_article(s, m.group(2)) + self.send_article(m.group(2)) return - - m = re.match(r'^/search/(.+)$', real_path) + + m = re.match(r'^/search$', real_path) if m: - WikiRequestHandler.send_searchresult(s, m.group(1)) + self.send_searchresult(self.params.get('q', '')) return - s.send_response(404) + self.send_response(404) def load_db(dbname): wp.wp_load_dump( diff --git a/sh/pyserver b/sh/pyserver deleted file mode 100755 index 615fedb..0000000 --- a/sh/pyserver +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -python ../py/server.py $1 |