Mercurial > wiki
changeset 4:01313b55ed09
We're now loading from wikicreole markup contained in wiki.txt, though editing fields still edits their HTML, not their wiki markup.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Sun, 01 Feb 2009 13:15:55 -0800 |
parents | ac7e15dcee69 |
children | 06e8c49e9dec |
files | wiki.html wiki.js wiki.txt wikicreole.js |
diffstat | 4 files changed, 394 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/wiki.html Sun Feb 01 12:53:25 2009 -0800 +++ b/wiki.html Sun Feb 01 13:15:55 2009 -0800 @@ -8,12 +8,9 @@ <title>Wiki.</title> </head> <body> -<div id="content"> -<div class="wiki"><h1>Yo.</h1> -Hi there <i>dude</i>.</div> -<div class="wiki">I am gud.</div> -</div> +<div id="content"></div> </body> <script src="jquery.js"></script> +<script src="wikicreole.js"></script> <script src="wiki.js"></script> </html>
--- a/wiki.js Sun Feb 01 12:53:25 2009 -0800 +++ b/wiki.js Sun Feb 01 13:15:55 2009 -0800 @@ -1,4 +1,8 @@ -function makeEditable(aEvt) { +var App = { + eventHandlers: {} +}; + +App.eventHandlers.makeEditable = function makeEditable(aEvt) { if (!aEvt.shiftKey) return; @@ -17,7 +21,7 @@ function() { var html = $(newItem).attr("value"); $(item).html(html); - $(item).mousedown(makeEditable); + $(item).mousedown(App.eventHandlers.makeEditable); $(newItem).replaceWith(item); }); @@ -26,10 +30,37 @@ setScrollHeight(); $(newItem).focus(); -} +}; + +App.processMarkup = function processMarkup(text) { + var parts = text.split("\n\n"); + jQuery.each( + parts, + function(i) { + var part = this; + var partDiv = $('<div class="wiki"></div>'); + App.creole.parse(partDiv.get(0), part); + partDiv.mousedown(App.eventHandlers.makeEditable); + $("#content").append(partDiv); + } + ); +}; -function onLoad() { - $(".wiki").mousedown(makeEditable); -} +App.eventHandlers.onLoad = function onLoad() { + var creole = new Parse.Simple.Creole( + {interwiki: { + WikiCreole: 'http://www.wikicreole.org/wiki/', + Wikipedia: 'http://en.wikipedia.org/wiki/' + }, + linkFormat: '' + }); -$(window).ready(onLoad); + App.creole = creole; + + jQuery.get("wiki.txt", + {}, + App.processMarkup, + "text"); +}; + +$(window).ready(App.eventHandlers.onLoad);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wiki.txt Sun Feb 01 13:15:55 2009 -0800 @@ -0,0 +1,6 @@ +Hello there dood. + +# Item one. +# Item two. + +How are you.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wikicreole.js Sun Feb 01 13:15:55 2009 -0800 @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2008 Ivan Fomichev + * + * Portions Copyright (c) 2007 Chris Purcell + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +if (!Parse) { var Parse = {}; } +if (!Parse.Simple) { Parse.Simple = {}; } + +Parse.Simple.Base = function(root, options) { + if (!arguments.length) { return; } + + this.root = new this.ruleConstructor(root); + this.options = options; +}; + +Parse.Simple.Base.prototype = { + ruleConstructor: null, + root: null, + options: null, + + parse: function(node, data, options) { + if (options) { + for (i in this.options) { + if (typeof options[i] == 'undefined') { options[i] = this.options[i]; } + } + } + else { + options = this.options; + } + this.root.apply(node, data, options); + } +}; + +Parse.Simple.Base.prototype.constructor = Parse.Simple.Base; + +Parse.Simple.Base.Rule = function(params) { + if (!arguments.length) { return; } + + for (var p in params) { this[p] = params[p]; } + if (!this.children) { this.children = []; } +}; + +Parse.Simple.Base.prototype.ruleConstructor = Parse.Simple.Base.Rule; + +Parse.Simple.Base.Rule.prototype = { + regex: null, + capture: null, + replaceRegex: null, + replaceString: null, + tag: null, + attrs: null, + children: null, + + match: function(data, options) { + return data.match(this.regex); + }, + + build: function(node, r, options) { + var data; + if (this.capture !== null) { + data = r[this.capture]; + } + + var target; + if (this.tag) { + target = document.createElement(this.tag); + node.appendChild(target); + } + else { target = node; } + + if (data) { + if (this.replaceRegex) { + data = data.replace(this.replaceRegex, this.replaceString); + } + this.apply(target, data, options); + } + + if (this.attrs) { + for (var i in this.attrs) { + target.setAttribute(i, this.attrs[i]); + if (i == 'class') { target.className = this.attrs[i]; } // for IE + } + } + return this; + }, + + apply: function(node, data, options) { + var tail = '' + data; + var matches = []; + + if (!this.fallback.apply) { + this.fallback = new this.constructor(this.fallback); + } + + while (true) { + var best = false; + var rule = false; + for (var i = 0; i < this.children.length; i++) { + if (typeof matches[i] == 'undefined') { + if (!this.children[i].match) { + this.children[i] = new this.constructor(this.children[i]); + } + matches[i] = this.children[i].match(tail, options); + } + if (matches[i] && (!best || best.index > matches[i].index)) { + best = matches[i]; + rule = this.children[i]; + if (best.index == 0) { break; } + } + } + + var pos = best ? best.index : tail.length; + if (pos > 0) { + this.fallback.apply(node, tail.substring(0, pos), options); + } + + if (!best) { break; } + + if (!rule.build) { rule = new this.constructor(rule); } + rule.build(node, best, options); + + var chopped = best.index + best[0].length; + tail = tail.substring(chopped); + for (var i = 0; i < this.children.length; i++) { + if (matches[i]) { + if (matches[i].index >= chopped) { + matches[i].index -= chopped; + } + else { + matches[i] = void 0; + } + } + } + } + + return this; + }, + + fallback: { + apply: function(node, data, options) { + node.appendChild(document.createTextNode(data)); + } + } +}; + +Parse.Simple.Base.Rule.prototype.constructor = Parse.Simple.Base.Rule; + +Parse.Simple.Creole = function(options) { + var rx = {}; + rx.link = '[^\\]|~\\n]*(?:(?:\\](?!\\])|~.)[^\\]|~\\n]*)*'; + rx.linkText = '[^\\]~\\n]*(?:(?:\\](?!\\])|~.)[^\\]~\\n]*)*'; + rx.uriPrefix = '\\b(?:(?:https?|ftp)://|mailto:)'; + rx.uri = rx.uriPrefix + rx.link; + rx.rawUri = rx.uriPrefix + '\\S*[^\\s!"\',.:;?]'; + rx.interwikiPrefix = '[\\w.]+:'; + rx.interwikiLink = rx.interwikiPrefix + rx.link; + + var formatLink = function(link, format) { + format = format instanceof Array ? format : [ format ]; + if (typeof format[1] == 'undefined') { format[1] = ''; } + return format[0] + link + format[1]; + }; + + var g = { + hr: { tag: 'hr', regex: /(^|\n)\s*----\s*(\n|$)/ }, + + br: { tag: 'br', regex: /\\\\/ }, + + preBlock: { tag: 'pre', capture: 2, + regex: /(^|\n)\{\{\{\n((.*\n)*?)\}\}\}(\n|$)/, + replaceRegex: /^ ([ \t]*\}\}\})/gm, + replaceString: '$1' }, + tt: { tag: 'tt', + regex: /\{\{\{(.*?\}\}\}+)/, capture: 1, + replaceRegex: /\}\}\}$/, replaceString: '' }, + + ulist: { tag: 'ul', capture: 0, + regex: /(^|\n)([ \t]*\*[^*#].*(\n|$)([ \t]*[^\s*#].*(\n|$))*([ \t]*[*#]{2}.*(\n|$))*)+/ }, + olist: { tag: 'ol', capture: 0, + regex: /(^|\n)([ \t]*#[^*#].*(\n|$)([ \t]*[^\s*#].*(\n|$))*([ \t]*[*#]{2}.*(\n|$))*)+/ }, + li: { tag: 'li', capture: 0, + regex: /[ \t]*([*#]).+(\n[ \t]*[^*#\s].*)*(\n[ \t]*\1[*#].+)*/, + replaceRegex: /(^|\n)[ \t]*[*#]/g, replaceString: '$1' }, + + table: { tag: 'table', capture: 0, + regex: /(^|\n)(\|.*?[ \t]*(\n|$))+/ }, + tr: { tag: 'tr', capture: 2, regex: /(^|\n)(\|.*?)\|?[ \t]*(\n|$)/ }, + th: { tag: 'th', regex: /\|+=([^|]*)/, capture: 1 }, + td: { tag: 'td', capture: 1, + regex: /\|+([^|~]*(~(.|(?=\n)|$)[^|~]*)*)/ }, + + singleLine: { regex: /.+/, capture: 0 }, + paragraph: { tag: 'p', capture: 0, + regex: /(^|\n)([ \t]*\S.*(\n|$))+/ }, + text: { capture: 0, regex: /(^|\n)([ \t]*[^\s].*(\n|$))+/ }, + + strong: { tag: 'strong', capture: 1, + regex: /\*\*([^*~]*((\*(?!\*)|~(.|(?=\n)|$))[^*~]*)*)(\*\*|\n|$)/ }, + em: { tag: 'em', capture: 1, + regex: '\\/\\/(((?!' + rx.uriPrefix + ')[^\\/~])*' + + '((' + rx.rawUri + '|\\/(?!\\/)|~(.|(?=\\n)|$))' + + '((?!' + rx.uriPrefix + ')[^\\/~])*)*)(\\/\\/|\\n|$)' }, + + img: { regex: '\\{\\{((?!\\{)[^|}\\n]*(?:}(?!})[^|}\\n]*)*)\\|' + + '([^}~\\n]*((}(?!})|~.)[^}~\\n]*)*)}}', + build: function(node, r, options) { + var img = document.createElement('img'); + img.src = r[1]; + img.alt = r[2].replace(/~(.)/g, '$1'); + node.appendChild(img); + } }, + + namedUri: { regex: '\\[\\[(' + rx.uri + ')\\|(' + rx.linkText + ')\\]\\]', + build: function(node, r, options) { + var link = document.createElement('a'); + link.href = r[1]; + if (options && options.isPlainUri) { + link.appendChild(document.createTextNode(r[2])); + } + else { + this.apply(link, r[2], options); + } + node.appendChild(link); + } }, + + namedLink: { regex: '\\[\\[(' + rx.link + ')\\|(' + rx.linkText + ')\\]\\]', + build: function(node, r, options) { + var link = document.createElement('a'); + + link.href = options && options.linkFormat + ? formatLink(r[1].replace(/~(.)/g, '$1'), options.linkFormat) + : r[1].replace(/~(.)/g, '$1'); + this.apply(link, r[2], options); + + node.appendChild(link); + } }, + + unnamedUri: { regex: '\\[\\[(' + rx.uri + ')\\]\\]', + build: 'dummy' }, + unnamedLink: { regex: '\\[\\[(' + rx.link + ')\\]\\]', + build: 'dummy' }, + unnamedInterwikiLink: { regex: '\\[\\[(' + rx.interwikiLink + ')\\]\\]', + build: 'dummy' }, + + rawUri: { regex: '(' + rx.rawUri + ')', + build: 'dummy' }, + + escapedSequence: { regex: '~(' + rx.rawUri + '|.)', capture: 1, + tag: 'span', attrs: { 'class': 'escaped' } }, + escapedSymbol: { regex: /~(.)/, capture: 1, + tag: 'span', attrs: { 'class': 'escaped' } } + }; + g.unnamedUri.build = g.rawUri.build = function(node, r, options) { + if (!options) { options = {}; } + options.isPlainUri = true; + g.namedUri.build.call(this, node, Array(r[0], r[1], r[1]), options); + }; + g.unnamedLink.build = function(node, r, options) { + g.namedLink.build.call(this, node, Array(r[0], r[1], r[1]), options); + }; + g.namedInterwikiLink = { regex: '\\[\\[(' + rx.interwikiLink + ')\\|(' + rx.linkText + ')\\]\\]', + build: function(node, r, options) { + var link = document.createElement('a'); + + var m, f; + if (options && options.interwiki) { + m = r[1].match(/(.*?):(.*)/); + f = options.interwiki[m[1]]; + } + + if (typeof f == 'undefined') { + if (!g.namedLink.apply) { + g.namedLink = new this.constructor(g.namedLink); + } + return g.namedLink.build.call(g.namedLink, node, r, options); + } + + link.href = formatLink(m[2].replace(/~(.)/g, '$1'), f); + + this.apply(link, r[2], options); + + node.appendChild(link); + } + }; + g.unnamedInterwikiLink.build = function(node, r, options) { + g.namedInterwikiLink.build.call(this, node, Array(r[0], r[1], r[1]), options); + }; + g.namedUri.children = g.unnamedUri.children = g.rawUri.children = + g.namedLink.children = g.unnamedLink.children = + g.namedInterwikiLink.children = g.unnamedInterwikiLink.children = + [ g.escapedSymbol, g.img ]; + + for (var i = 1; i <= 6; i++) { + g['h' + i] = { tag: 'h' + i, capture: 2, + regex: '(^|\\n)[ \\t]*={' + i + '}[ \\t]' + + '([^~]*?(~(.|(?=\\n)|$))*)[ \\t]*=*\\s*(\\n|$)' + }; + } + + g.ulist.children = g.olist.children = [ g.li ]; + g.li.children = [ g.ulist, g.olist ]; + g.li.fallback = g.text; + + g.table.children = [ g.tr ]; + g.tr.children = [ g.th, g.td ]; + g.td.children = [ g.singleLine ]; + g.th.children = [ g.singleLine ]; + + g.h1.children = g.h2.children = g.h3.children = + g.h4.children = g.h5.children = g.h6.children = + g.singleLine.children = g.paragraph.children = + g.text.children = g.strong.children = g.em.children = + [ g.escapedSequence, g.strong, g.em, g.br, g.rawUri, + g.namedUri, g.namedInterwikiLink, g.namedLink, + g.unnamedUri, g.unnamedInterwikiLink, g.unnamedLink, + g.tt, g.img ]; + + g.root = { + children: [ g.h1, g.h2, g.h3, g.h4, g.h5, g.h6, + g.hr, g.ulist, g.olist, g.preBlock, g.table ], + fallback: { children: [ g.paragraph ] } + }; + + Parse.Simple.Base.call(this, g.root, options); +}; + +Parse.Simple.Creole.prototype = new Parse.Simple.Base(); + +Parse.Simple.Creole.prototype.constructor = Parse.Simple.Creole;