/*==============================================================================
This Wikiwyg mode supports a textarea editor with toolbar buttons.
COPYRIGHT:
Copyright (c) 2005 Socialtext Corporation
655 High Street
Palo Alto, CA 94301 U.S.A.
All rights reserved.
Wikiwyg is free software.
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.
This library 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 Lesser
General Public License for more details.
http://www.gnu.org/copyleft/lesser.txt
=============================================================================*/
proto = new Subclass('Wikiwyg.Wikitext', 'Wikiwyg.Mode');
klass = Wikiwyg.Wikitext;
proto.classtype = 'wikitext';
proto.modeDescription = 'Wikitext';
proto.config = {
supportCamelCaseLinks: false,
javascriptLocation: null,
clearRegex: null,
editHeightMinimum: 10,
editHeightAdjustment: 1.3,
markupRules: {
link: ['bound_phrase', '[', ']'],
bold: ['bound_phrase', '*', '*'],
code: ['bound_phrase', '`', '`'],
italic: ['bound_phrase', '/index.html', '/index.html'],
underline: ['bound_phrase', '_', '_'],
strike: ['bound_phrase', '-', '-'],
p: ['start_lines', ''],
pre: ['start_lines', ' '],
h1: ['start_line', '= '],
h2: ['start_line', '== '],
h3: ['start_line', '=== '],
h4: ['start_line', '==== '],
h5: ['start_line', '===== '],
h6: ['start_line', '====== '],
ordered: ['start_lines', '#'],
unordered: ['start_lines', '*'],
indent: ['start_lines', '>'],
hr: ['line_alone', '----'],
table: ['line_alone', '| A | B | C |\n| | | |\n| | | |']
}
}
proto.initializeObject = function() { // See IE
this.initialize_object();
}
proto.initialize_object = function() {
this.div = document.createElement('div');
this.textarea = document.createElement('textarea');
this.textarea.setAttribute('id', 'wikiwyg_wikitext_textarea');
this.div.appendChild(this.textarea);
this.area = this.textarea;
this.clear_inner_text();
}
proto.clear_inner_text = function() {
var self = this;
this.area.onclick = function() {
var inner_text = self.area.value;
var clear = self.config.clearRegex;
if (clear && inner_text.match(clear))
self.area.value = '';
}
}
proto.enableThis = function() {
this.superfunc('enableThis').call(this);
this.textarea.style.width = '100%';
this.setHeightOfEditor();
this.enable_keybindings();
}
proto.setHeightOfEditor = function() {
var config = this.config;
var adjust = config.editHeightAdjustment;
var area = this.textarea;
var text = this.textarea.value;
var rows = text.split(/\n/).length;
var height = parseInt(rows * adjust);
if (height < config.editHeightMinimum)
height = config.editHeightMinimum;
area.setAttribute('rows', height);
}
proto.toWikitext = function() {
return this.textarea.value;
}
proto.toHtml = function(func) {
var wikitext = this.textarea.value;
this.convertWikitextToHtml(wikitext, func);
}
proto.fromHtml = function(html) {
this.textarea.value = 'Loading...';
var textarea = this.textarea;
this.convertHtmlToWikitext(
html,
function(value) { textarea.value = value }
);
}
proto.convertWikitextToHtml = function(wikitext, func) {
alert('Wikitext changes cannot be converted to HTML\nWikiwyg.Wikitext.convertWikitextToHtml is not implemented here');
func(this.copyhtml);
}
proto.convertHtmlToWikitext = function(html, func) {
func(this.convert_html_to_wikitext(html));
}
proto.get_keybinding_area = function() {
return this.textarea;
}
/*==============================================================================
Code to markup wikitext
=============================================================================*/
Wikiwyg.Wikitext.phrase_end_re = /[\s\.\:\;\,\!\?\(\)]/;
proto.find_left = function(t, selection_start, matcher) {
var substring = t.substr(selection_start - 1, 1);
var nextstring = t.substr(selection_start - 2, 1);
if (selection_start == 0)
return selection_start;
if (substring.match(matcher)) {
// special case for word.word
if ((substring != '.') || (nextstring.match(/\s/)))
return selection_start;
}
return this.find_left(t, selection_start - 1, matcher);
}
proto.find_right = function(t, selection_end, matcher) {
var substring = t.substr(selection_end, 1);
var nextstring = t.substr(selection_end + 1, 1);
if (selection_end >= t.length)
return selection_end;
if (substring.match(matcher)) {
// special case for word.word
if ((substring != '.') || (nextstring.match(/\s/)))
return selection_end;
}
return this.find_right(t, selection_end + 1, matcher);
}
proto.get_lines = function() {
t = this.area;
var selection_start = t.selectionStart;
var selection_end = t.selectionEnd;
if (selection_start == null || selection_end == null)
return false
var our_text = t.value.replace(/\r/g, '');
selection = our_text.substr(selection_start,
selection_end - selection_start);
selection_start = this.find_right(our_text, selection_start, /[^\r\n]/);
selection_end = this.find_left(our_text, selection_end, /[^\r\n]/);
this.selection_start = this.find_left(our_text, selection_start, /[\r\n]/);
this.selection_end = this.find_right(our_text, selection_end, /[\r\n]/);
t.setSelectionRange(selection_start, selection_end);
t.focus();
this.start = our_text.substr(0,this.selection_start);
this.sel = our_text.substr(this.selection_start, this.selection_end -
this.selection_start);
this.finish = our_text.substr(this.selection_end, our_text.length);
return true;
}
proto.alarm_on = function() {
var area = this.area;
var background = area.style.background;
area.style.background = '#f88';
function alarm_off() {
area.style.background = background;
}
window.setTimeout(alarm_off, 250);
area.focus()
}
proto.get_words = function() {
function is_insane(selection) {
return selection.match(/\r?\n(\r?\n|\*+ |\#+ |\=+ )/);
}
t = this.area;
var selection_start = t.selectionStart;
var selection_end = t.selectionEnd;
if (selection_start == null || selection_end == null)
return false;
var our_text = t.value.replace(/\r/g, '');
selection = our_text.substr(selection_start,
selection_end - selection_start);
selection_start = this.find_right(our_text, selection_start, /(\S|\r?\n)/);
if (selection_start > selection_end)
selection_start = selection_end;
selection_end = this.find_left(our_text, selection_end, /(\S|\r?\n)/);
if (selection_end < selection_start)
selection_end = selection_start;
if (is_insane(selection)) {
this.alarm_on();
return false;
}
this.selection_start =
this.find_left(our_text, selection_start, Wikiwyg.Wikitext.phrase_end_re);
this.selection_end =
this.find_right(our_text, selection_end, Wikiwyg.Wikitext.phrase_end_re);
t.setSelectionRange(this.selection_start, this.selection_end);
t.focus();
this.start = our_text.substr(0,this.selection_start);
this.sel = our_text.substr(this.selection_start, this.selection_end -
this.selection_start);
this.finish = our_text.substr(this.selection_end, our_text.length);
return true;
}
proto.markup_is_on = function(start, finish) {
return (this.sel.match(start) && this.sel.match(finish));
}
proto.clean_selection = function(start, finish) {
this.sel = this.sel.replace(start, '');
this.sel = this.sel.replace(finish, '');
}
proto.toggle_same_format = function(start, finish) {
start = this.clean_regexp(start);
finish = this.clean_regexp(finish);
var start_re = new RegExp('^' + start);
var finish_re = new RegExp(finish + '$');
if (this.markup_is_on(start_re, finish_re)) {
this.clean_selection(start_re, finish_re);
return true;
}
return false;
}
proto.clean_regexp = function(string) {
string = string.replace(/([\^\$\*\+\.\?\[\]\{\}])/g, '\\$1');
return string;
}
proto.set_text_and_selection = function(text, start, end) {
this.area.value = text;
this.area.setSelectionRange(start, end);
}
proto.add_markup_words = function(markup_start, markup_finish, example) {
if (this.toggle_same_format(markup_start, markup_finish)) {
this.selection_end = this.selection_end -
(markup_start.length + markup_finish.length);
markup_start = '';
markup_finish = '';
}
if (this.sel.length == 0) {
if (example)
this.sel = example;
var text = this.start + markup_start +
this.sel + markup_finish + this.finish;
var start = this.selection_start + markup_start.length;
var end = this.selection_end + markup_start.length + this.sel.length;
this.set_text_and_selection(text, start, end);
} else {
var text = this.start + markup_start + this.sel +
markup_finish + this.finish;
var start = this.selection_start;
var end = this.selection_end + markup_start.length +
markup_finish.length;
this.set_text_and_selection(text, start, end);
}
this.area.focus();
}
// XXX - A lot of this is hardcoded.
proto.add_markup_lines = function(markup_start) {
var already_set_re = new RegExp( '^' + this.clean_regexp(markup_start), 'gm');
var other_markup_re = /^(\^+|\=+|\*+|#+|>+| )/gm;
var match;
// if paragraph, reduce everything.
if (! markup_start.length) {
this.sel = this.sel.replace(other_markup_re, '');
this.sel = this.sel.replace(/^\ +/gm, '');
}
// if pre and not all indented, indent
else if ((markup_start == ' ') && this.sel.match(/^\S/m))
this.sel = this.sel.replace(/^/gm, markup_start);
// if not requesting heading and already this style, kill this style
else if (
(! markup_start.match(/[\=\^]/)) &&
this.sel.match(already_set_re)
) {
this.sel = this.sel.replace(already_set_re, '');
if (markup_start != ' ')
this.sel = this.sel.replace(/^ */gm, '');
}
// if some other style, switch to new style
else if (match = this.sel.match(other_markup_re))
// if pre, just indent
if (markup_start == ' ')
this.sel = this.sel.replace(/^/gm, markup_start);
// if heading, just change it
else if (markup_start.match(/[\=\^]/))
this.sel = this.sel.replace(other_markup_re, markup_start);
// else try to change based on level
else
this.sel = this.sel.replace(
other_markup_re,
function(match) {
return markup_start.times(match.length);
}
);
// if something selected, use this style
else if (this.sel.length > 0)
this.sel = this.sel.replace(/^(.*\S+)/gm, markup_start + ' $1');
// just add the markup
else
this.sel = markup_start + ' ';
var text = this.start + this.sel + this.finish;
var start = this.selection_start;
var end = this.selection_start + this.sel.length;
this.set_text_and_selection(text, start, end);
this.area.focus();
}
// XXX - A lot of this is hardcoded.
proto.bound_markup_lines = function(markup_array) {
var markup_start = markup_array[1];
var markup_finish = markup_array[2];
var already_start = new RegExp('^' + this.clean_regexp(markup_start), 'gm');
var already_finish = new RegExp(this.clean_regexp(markup_finish) + '$', 'gm');
var other_start = /^(\^+|\=+|\*+|#+|>+) */gm;
var other_finish = /( +(\^+|\=+))?$/gm;
var match;
if (this.sel.match(already_start)) {
this.sel = this.sel.replace(already_start, '');
this.sel = this.sel.replace(already_finish, '');
}
else if (match = this.sel.match(other_start)) {
this.sel = this.sel.replace(other_start, markup_start);
this.sel = this.sel.replace(other_finish, markup_finish);
}
// if something selected, use this style
else if (this.sel.length > 0) {
this.sel = this.sel.replace(
/^(.*\S+)/gm,
markup_start + '$1' + markup_finish
);
}
// just add the markup
else
this.sel = markup_start + markup_finish;
var text = this.start + this.sel + this.finish;
var start = this.selection_start;
var end = this.selection_start + this.sel.length;
this.set_text_and_selection(text, start, end);
this.area.focus();
}
proto.markup_bound_line = function(markup_array) {
var scroll_top = this.area.scrollTop;
if (this.get_lines())
this.bound_markup_lines(markup_array);
this.area.scrollTop = scroll_top;
}
proto.markup_start_line = function(markup_array) {
var markup_start = markup_array[1];
markup_start = markup_start.replace(/ +/, '');
var scroll_top = this.area.scrollTop;
if (this.get_lines())
this.add_markup_lines(markup_start);
this.area.scrollTop = scroll_top;
}
proto.markup_start_lines = function(markup_array) {
var markup_start = markup_array[1];
var scroll_top = this.area.scrollTop;
if (this.get_lines())
this.add_markup_lines(markup_start);
this.area.scrollTop = scroll_top;
}
proto.markup_bound_phrase = function(markup_array) {
var markup_start = markup_array[1];
var markup_finish = markup_array[2];
var scroll_top = this.area.scrollTop;
if (markup_finish == 'undefined')
markup_finish = markup_start;
if (this.get_words())
this.add_markup_words(markup_start, markup_finish, null);
this.area.scrollTop = scroll_top;
}
klass.make_do = function(style) {
return function() {
var markup = this.config.markupRules[style];
var handler = markup[0];
if (! this['markup_' + handler])
die('No handler for markup: "' + handler + '"');
this['markup_' + handler](markup);
}
}
proto.do_link = klass.make_do('link');
proto.do_bold = klass.make_do('bold');
proto.do_code = klass.make_do('code');
proto.do_italic = klass.make_do('italic');
proto.do_underline = klass.make_do('underline');
proto.do_strike = klass.make_do('strike');
proto.do_p = klass.make_do('p');
proto.do_pre = klass.make_do('pre');
proto.do_h1 = klass.make_do('h1');
proto.do_h2 = klass.make_do('h2');
proto.do_h3 = klass.make_do('h3');
proto.do_h4 = klass.make_do('h4');
proto.do_h5 = klass.make_do('h5');
proto.do_h6 = klass.make_do('h6');
proto.do_ordered = klass.make_do('ordered');
proto.do_unordered = klass.make_do('unordered');
proto.do_hr = klass.make_do('hr');
proto.do_table = klass.make_do('table');
proto.do_dent = function(method) {
var scroll_top = this.area.scrollTop;
if (! this.get_lines()) {
this.area.scrollTop = scroll_top;
return;
}
if (method(this)) {
var text = this.start + this.sel + this.finish;
var start = this.selection_start;
var end = this.selection_start + this.sel.length;
this.set_text_and_selection(text, start, end);
}
this.area.focus();
}
proto.do_indent = function() {
this.do_dent(
function(that) {
if (that.sel == '') return false;
that.sel = that.sel.replace(/^(([\*\-\#])+(?=\s))/gm, '$2$1');
that.sel = that.sel.replace(/^([\>\=])/gm, '$1$1');
that.sel = that.sel.replace(/^([^\>\*\-\#\=\r\n])/gm, '> $1');
that.sel = that.sel.replace(/^\={7,}/gm, '======');
return true;
}
)
}
proto.do_outdent = function() {
this.do_dent(
function(that) {
if (that.sel == '') return false;
that.sel = that.sel.replace(/^([\>\*\-\#\=] ?)/gm, '');
return true;
}
)
}
proto.markup_line_alone = function(markup_array) {
var t = this.area;
var scroll_top = t.scrollTop;
var selection_start = t.selectionStart;
var text = t.value;
this.selection_start = this.find_right(text, selection_start, /\r?\n/);
this.selection_end = this.selection_start;
t.setSelectionRange(this.selection_start, this.selection_start);
t.focus();
var markup = markup_array[1];
this.start = t.value.substr(0, this.selection_start);
this.finish = t.value.substr(this.selection_end, t.value.length);
var text = this.start + '\n' + markup + this.finish;
var start = this.selection_start + markup.length + 1;
var end = this.selection_end + markup.length + 1;
this.set_text_and_selection(text, start, end);
t.scrollTop = scroll_top;
}
/*==============================================================================
Code to convert from html to wikitext.
=============================================================================*/
proto.convert_html_to_wikitext = function(html) {
this.copyhtml = html;
var dom = document.createElement('div');
html = html.replace(/<!-=-/g, '<!--').
replace(/-=->/g, '-->');
dom.innerHTML = html;
this.output = [];
this.list_type = [];
this.indent_level = 0;
this.walk(dom);
// add final whitespace
this.assert_new_line();
return this.join_output(this.output);
}
proto.appendOutput = function(string) {
this.output.push(string);
}
proto.join_output = function(output) {
var list = this.remove_stops(output);
list = this.cleanup_output(list);
return list.join('');
}
// This is a noop, but can be subclassed.
proto.cleanup_output = function(list) {
return list;
}
proto.remove_stops = function(list) {
var clean = [];
for (var i = 0 ; i < list.length ; i++) {
if (typeof(list[i]) != 'string') continue;
clean.push(list[i]);
}
return clean;
}
proto.walk = function(element) {
if (!element) return;
for (var part = element.firstChild; part; part = part.nextSibling) {
if (part.nodeType == 1) {
this.dispatch_formatter(part);
}
else if (part.nodeType == 3) {
if (part.nodeValue.match(/\S/)) {
var string = part.nodeValue;
if (! string.match(/^[\.\,\?\!\)]/)) {
this.assert_space_or_newline();
string = this.trim(string);
}
this.appendOutput(this.collapse(string));
}
}
}
}
proto.dispatch_formatter = function(element) {
var dispatch = 'format_' + element.nodeName.toLowerCase();
if (! this[dispatch])
dispatch = 'handle_undefined';
this[dispatch](element);
}
proto.skip = function() { }
proto.pass = function(element) {
this.walk(element);
}
proto.handle_undefined = function(element) {
this.appendOutput('<' + element.nodeName + '>');
this.walk(element);
this.appendOutput('/doc/i/in/ingy/Wikiwyg/012/lib/Wikiwyg/lt/index.html' + element.nodeName + '>');
}
proto.handle_undefined = proto.skip;
proto.format_abbr = proto.pass;
proto.format_acronym = proto.pass;
proto.format_address = proto.pass;
proto.format_applet = proto.skip;
proto.format_area = proto.skip;
proto.format_basefont = proto.skip;
proto.format_base = proto.skip;
proto.format_bgsound = proto.skip;
proto.format_big = proto.pass;
proto.format_blink = proto.pass;
proto.format_body = proto.pass;
proto.format_br = proto.skip;
proto.format_button = proto.skip;
proto.format_caption = proto.pass;
proto.format_center = proto.pass;
proto.format_cite = proto.pass;
proto.format_col = proto.pass;
proto.format_colgroup = proto.pass;
proto.format_dd = proto.pass;
proto.format_dfn = proto.pass;
proto.format_dl = proto.pass;
proto.format_dt = proto.pass;
proto.format_embed = proto.skip;
proto.format_field = proto.skip;
proto.format_fieldset = proto.skip;
proto.format_font = proto.pass;
proto.format_form = proto.skip;
proto.format_frame = proto.skip;
proto.format_frameset = proto.skip;
proto.format_head = proto.skip;
proto.format_html = proto.pass;
proto.format_iframe = proto.pass;
proto.format_input = proto.skip;
proto.format_ins = proto.pass;
proto.format_isindex = proto.skip;
proto.format_label = proto.skip;
proto.format_legend = proto.skip;
proto.format_link = proto.skip;
proto.format_map = proto.skip;
proto.format_marquee = proto.skip;
proto.format_meta = proto.skip;
proto.format_multicol = proto.pass;
proto.format_nobr = proto.skip;
proto.format_noembed = proto.skip;
proto.format_noframes = proto.skip;
proto.format_nolayer = proto.skip;
proto.format_noscript = proto.skip;
proto.format_nowrap = proto.skip;
proto.format_object = proto.skip;
proto.format_optgroup = proto.skip;
proto.format_option = proto.skip;
proto.format_param = proto.skip;
proto.format_select = proto.skip;
proto.format_small = proto.pass;
proto.format_spacer = proto.skip;
proto.format_style = proto.skip;
proto.format_sub = proto.pass;
proto.format_submit = proto.skip;
proto.format_sup = proto.pass;
proto.format_tbody = proto.pass;
proto.format_textarea = proto.skip;
proto.format_tfoot = proto.pass;
proto.format_thead = proto.pass;
proto.format_wiki = proto.pass;
proto.format_img = function(element) {
var uri = element.getAttribute('src');
if (uri) {
this.assert_space_or_newline();
this.appendOutput(uri);
}
}
// XXX This little dance relies on knowning lots of little details about where
// indentation fangs are added and deleted by the various insert/assert calls.
proto.format_blockquote = function(element) {
if (! this.indent_level) {
this.assert_new_line();
this.indent_level++;
this.insert_new_line();
}
else {
this.indent_level++;
this.assert_new_line();
}
this.walk(element);
this.indent_level--;
if (! this.indent_level)
this.assert_blank_line();
else
this.assert_new_line();
}
proto.format_div = function(element) {
if (this.is_opaque(element)) {
this.handle_opaque_block(element);
return;
}
this.walk(element);
}
proto.format_span = function(element) {
if (this.is_opaque(element)) {
this.handle_opaque_phrase(element);
return;
}
var style = element.getAttribute('style');
if (!style) {
this.pass(element);
return;
}
this.assert_space_or_newline();
if (style.match(/\bbold\b/))
this.appendOutput(this.config.markupRules.bold[1]);
if (style.match(/\bitalic\b/))
this.appendOutput(this.config.markupRules.italic[1]);
if (style.match(/\bunderline\b/))
this.appendOutput(this.config.markupRules.underline[1]);
if (style.match(/\bline-through\b/))
this.appendOutput(this.config.markupRules.strike[1]);
this.no_following_whitespace();
this.walk(element);
if (style.match(/\bline-through\b/))
this.appendOutput(this.config.markupRules.strike[2]);
if (style.match(/\bunderline\b/))
this.appendOutput(this.config.markupRules.underline[2]);
if (style.match(/\bitalic\b/))
this.appendOutput(this.config.markupRules.italic[2]);
if (style.match(/\bbold\b/))
this.appendOutput(this.config.markupRules.bold[2]);
}
klass.make_format = function(style) {
return function(element) {
var markup = this.config.markupRules[style];
var handler = markup[0];
this['handle_' + handler](element, markup);
}
}
proto.format_b = klass.make_format('bold');
proto.format_strong = proto.format_b;
proto.format_code = klass.make_format('code');
proto.format_kbd = proto.format_code;
proto.format_samp = proto.format_code;
proto.format_tt = proto.format_code;
proto.format_var = proto.format_code;
proto.format_i = klass.make_format('italic');
proto.format_em = proto.format_i;
proto.format_u = klass.make_format('underline');
proto.format_strike = klass.make_format('strike');
proto.format_del = proto.format_strike;
proto.format_s = proto.format_strike;
proto.format_hr = klass.make_format('hr');
proto.format_h1 = klass.make_format('h1');
proto.format_h2 = klass.make_format('h2');
proto.format_h3 = klass.make_format('h3');
proto.format_h4 = klass.make_format('h4');
proto.format_h5 = klass.make_format('h5');
proto.format_h6 = klass.make_format('h6');
proto.format_pre = klass.make_format('pre');
proto.format_p = function(element) {
this.assert_blank_line();
this.walk(element);
this.assert_blank_line();
}
proto.format_a = function(element) {
var label = Wikiwyg.htmlUnescape(element.innerHTML);
label = label.replace(/<[^>]*?>/g, ' ');
label = label.replace(/\s+/g, ' ');
label = label.replace(/^\s+/, '');
label = label.replace(/\s+$/, '');
this.make_wikitext_link(label, element.getAttribute('/doc/i/in/ingy/Wikiwyg/012/lib/Wikiwyg/href/index.html'), element);
}
proto.format_table = function(element) {
this.assert_blank_line();
this.walk(element);
this.assert_blank_line();
}
proto.format_tr = function(element) {
this.walk(element);
this.appendOutput('|');
this.insert_new_line();
}
proto.format_td = function(element) {
this.appendOutput('| ');
this.walk(element);
this.appendOutput(' ');
}
proto.format_th = proto.format_td;
proto.format_ol = function(element) {
if (!this.list_type.length)
this.assert_blank_line();
else
this.assert_new_line();
this.list_type.push('ordered');
this.walk(element);
this.list_type.pop();
if (!this.list_type.length)
this.assert_blank_line();
}
// XXX - Maybe a refactoring for the duplication above
proto.format_ul = function(element) {
if (!this.list_type.length)
this.assert_blank_line();
else
this.assert_new_line();
this.list_type.push('unordered');
this.walk(element);
this.list_type.pop();
if (!this.list_type.length)
this.assert_blank_line();
}
proto.format_li = function(element) {
var level = this.list_type.length;
if (!level) die("List error");
var type = this.list_type[level - 1];
var markup = this.config.markupRules[type];
this.appendOutput(markup[1].times(level) + ' ');
this.walk(element);
this.chomp();
this.insert_new_line();
}
proto.chomp = function() {
var string;
while (this.output.length) {
string = this.output.pop();
if (typeof(string) != 'string') {
this.appendOutput(string);
return;
}
if (! string.match(/^\n>+ $/) && string.match(/\S/))
break;
}
if (string) {
string = string.replace(/[\r\n\s]+$/, '');
this.appendOutput(string);
}
}
proto.collapse = function(string) {
return string.replace(/[ \r\n]+/g, ' ');
}
proto.trim = function(string) {
return string.replace(/^\s+/, '');
}
proto.insert_new_line = function() {
var fang = '';
if (this.indent_level > 0)
fang = '>'.times(this.indent_level) + ' ';
// XXX - ('\n' + fang) MUST be in the same element in this.output so that
// it can be properly matched by chomp above.
if (this.output.length)
this.appendOutput('\n' + fang);
else if (fang.length)
this.appendOutput(fang);
}
proto.assert_new_line = function() {
this.chomp();
this.insert_new_line();
}
proto.assert_blank_line = function() {
this.chomp();
this.insert_new_line();
this.insert_new_line();
}
proto.assert_space_or_newline = function() {
var string;
if (! this.output.length) return;
string = this.output[this.output.length - 1];
if (! string.whitespace && ! string.match(/\s+$/))
this.appendOutput(' ');
}
proto.no_following_whitespace = function() {
this.appendOutput({whitespace: 'stop'});
}
proto.handle_bound_phrase = function(element, markup) {
this.assert_space_or_newline();
this.appendOutput(markup[1]);
this.no_following_whitespace();
this.walk(element);
// assume that walk leaves no trailing whitespace.
this.appendOutput(markup[2]);
}
// XXX - A very promising refactoring is that we don't need the trailing
// assert_blank_line in block formatters.
proto.handle_bound_line = function(element,markup) {
this.assert_blank_line();
this.appendOutput(markup[1]);
this.walk(element);
this.appendOutput(markup[2]);
this.assert_blank_line();
}
proto.handle_start_line = function (element, markup) {
this.assert_blank_line();
this.appendOutput(markup[1]);
this.walk(element);
this.assert_blank_line();
}
proto.handle_start_lines = function (element, markup) {
var text = element.firstChild.nodeValue;
if (!text) return;
this.assert_blank_line();
text = text.replace(/^/mg, markup[1]);
this.appendOutput(text);
this.assert_blank_line();
}
proto.handle_line_alone = function (element, markup) {
this.assert_blank_line();
this.appendOutput(markup[1]);
this.assert_blank_line();
}
proto.get_first_comment = function(element) {
var comment = element.firstChild;
if (comment && (comment.nodeType == 8))
return comment;
else
return null;
}
proto.is_opaque = function(element) {
var comment = this.get_first_comment(element);
if (!comment) return false;
var text = comment.data;
if (text.match(/^\s*wiki:/)) return true;
return false;
}
proto.handle_opaque_phrase = function(element) {
var comment = this.get_first_comment(element);
if (comment) {
var text = comment.data;
text = text.replace(/^ wiki:\s+/, '');
text = text.replace(/\s$/, '');
this.assert_space_or_newline();
this.appendOutput(text);
this.assert_space_or_newline();
}
}
proto.handle_opaque_block = function(element) {
var comment = this.get_first_comment(element);
if (!comment) return;
var text = comment.data;
text = text.replace(/^\s*wiki:\s+/, '');
this.appendOutput(text);
}
proto.make_wikitext_link = function(label, href, element) {
var before = this.config.markupRules.link[1];
var after = this.config.markupRules.link[2];
this.assert_space_or_newline();
if (! href) {
this.appendOutput(label);
}
else if (href == label) {
this.appendOutput(/doc/i/in/ingy/Wikiwyg/012/lib/Wikiwyg/href/index.html);
}
else if (this.href_is_wiki_link(/doc/i/in/ingy/Wikiwyg/012/lib/Wikiwyg/href/index.html)) {
if (this.camel_case_link(label))
this.appendOutput(label);
else
this.appendOutput(before + label + after);
}
else {
this.appendOutput(before + href + ' ' + label + after);
}
}
proto.camel_case_link = function(label) {
if (! this.config.supportCamelCaseLinks)
return false;
return label.match(/[a-z][A-Z]/);
}
proto.href_is_wiki_link = function(/doc/i/in/ingy/Wikiwyg/012/lib/Wikiwyg/href/index.html) {
if (! this.looks_like_a_url(/doc/i/in/ingy/Wikiwyg/012/lib/Wikiwyg/href/index.html))
return true;
if (! href.match(/\?/))
return false;
var no_arg_input = href.split('?')[0];
var no_arg_current = location.href.split('?')[0];
return no_arg_input == no_arg_current;
}
proto.looks_like_a_url = function(string) {
return string.match(/^(http|https|ftp|irc|mailto):/);
}
/*==============================================================================
Support for Internet Explorer in Wikiwyg.Wikitext
=============================================================================*/
if (Wikiwyg.is_ie) {
proto.setHeightOf = function() {
// XXX hardcode this until we can keep window from jumping after button
// events.
this.textarea.style.height = '200px';
}
proto.initializeObject = function() {
this.initialize_object();
this.area.addBehavior(this.config.javascriptLocation + "Selection.htc");
}
} // end of global if