From bb1aea885c044ae71e2373947d9b32fb56ddfc57 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Wed, 27 Jul 2016 00:08:11 +0300 Subject: [PATCH] new parser working... Signed-off-by: Alex A. Naanou --- wiki.js | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 190 insertions(+), 23 deletions(-) diff --git a/wiki.js b/wiki.js index cb2b89d..7df725b 100755 --- a/wiki.js +++ b/wiki.js @@ -386,12 +386,163 @@ var macro = { return text }, +} + + +// XXX should inline macros support named args??? +var macro2 = { + + __include_marker__: '__include_marker__', + + // Abstract macro syntax: + // Inline macro: + // @macro(arg ..) + // + // HTML-like: + // + // + // HTML-like with body: + // + // ..text.. + // + // + // XXX should inline macros support named args??? + __macro__pattern__: + [[ + // @macro(arg ..) + '@([a-zA-Z-_]+)\\(([^)]*)\\)' + ].join('|'), 'mg'], + + // default filters... + // + // NOTE: these are added AFTER the user defined filters... + __filters__: [ + 'wikiword', + ], + + // Macros... + // + macro: { + // select filter to post-process text... + filter: Macro('Filter to post-process text', + ['name'], + function(context, elem, state){ + var filter = $(elem).attr('name') + + filter[0] == '-' ? + // disabled -- keep at head of list... + state.filters.unshift(filter) + // normal -- tail... + : state.filters.push(filter) + + return '' + }), + + // include page/slot... + // + // NOTE: this will render the page in the caller's context. + // NOTE: included pages are rendered completely independently + // from the including page. + // + // XXX do we need to control the rendering of nested pages??? + // ...currently I do not think so... + // ...if required this can be done via global and local + // filters... (now filters are only local) + // XXX do we need to render just one slot??? (slot arg) + // e.g. include PageX SlotY + include: Macro('Include page', + ['src'], + function(context, elem, state){ + var path = $(elem).attr('src') + + // get and prepare the included page... + state.include + .push(context.get(path)) + + // return the marker... + return this.__include_marker__ + }), + + // NOTE: this is similar to include, the difference is that this + // includes the page source to the current context while + // include works in an isolated context + source: Macro('Include page source (without parsing)', + ['src'], + function(context, elem, state){ + var path = $(elem).attr('src') + + return context.get(path).raw + }), + + // fill/define slot (stage 1)... + // + // XXX which should have priority the arg text or the content??? + slot: Macro('Define/fill slot', + ['name', 'text'], + function(context, elem, state){ + var name = $(elem).attr('name') + + // XXX + text = $(elem).html() + text = text == '' ? $(elem).attr('text') : text + text = this.parse(context, text, state, true) + + if(state.slots[name] == null){ + state.slots[name] = text + // return a slot macro parsable by stage 2... + return ''+ text +'' + + } else if(name in state.slots){ + state.slots[name] = text + return '' + } + }), + }, + + // Post macros... + // + post_macro: { + slot: Macro('', + ['name'], + function(context, elem, state){ + var name = $(elem).attr('name') + + if(state.slots[name] == null){ + return $(elem).html() + + } else if(name in state.slots){ + return state.slots[name] + } + }), + }, + + // Filters... + // + // Signature: + // filter(text) -> html + // + // XXX + filter: { + default: 'html', + + html: function(context, elem){ return $(elem) }, + + json: 'text', + text: function(context, elem){ return $('
').html($(elem).text()) }, + + // XXX + //nl2br: function(context, text){ return $('
').html(text.replace(/\n/g, '
\n')) }, + + wikiword: function(context, elem){ + return $('') + .html(setWikiWords($(elem).html(), true, this.__include_marker__)) }, + }, // XXX this expect a different macro signature: // macro(context, element, state) // -> text - _parse: function(context, text, state, skip_post, pattern){ + parse: function(context, text, state, skip_post, pattern){ var that = this state = state || {} @@ -399,11 +550,15 @@ var macro = { state.slots = state.slots || {} state.include = state.include || [] - // XXX update .__macro__pattern__ to only support the @macro style... - //var pattern = pattern || this.__macro__pattern__ - pattern = pattern || RegExp('@([a-zA-Z-_]+)\\(([^)]*)\\)', 'mg') + //pattern = pattern || RegExp('@([a-zA-Z-_]+)\\(([^)]*)\\)', 'mg') + pattern = pattern || RegExp.apply(null, this.__macro__pattern__) - var parsed = $('').html(text) + // XXX need to quote regexp chars... + var include_marker = RegExp(this.__include_marker__, 'g') + + var parsed = typeof(text) == typeof('str') ? + $('').html(text) + : text var _parseText = function(context, text, macro){ return text.replace(pattern, function(match){ @@ -430,7 +585,7 @@ var macro = { }) // call macro... - return macro[name].call(context, elem, state) + return macro[name].call(that, context, elem, state) } return match @@ -440,11 +595,12 @@ var macro = { var _parse = function(context, parsed, macro){ $(parsed).contents().each(function(_, e){ // #text node -> parse the @ macros... - if(e.nodeType == 3){ - // parse text... - var t = $(e) + if(e.nodeType == e.TEXT_NODE){ + $(e).replaceWith(_parseText(context, $(e).text(), macro)) - t.replaceWith(_parseText(context, t.text(), macro)) + // comment node -> parse the @ macros... + } else if(e.nodeType == e.COMMENT_NODE){ + $(e).replaceWith(_parseText(context, '', macro)) // node -> html-style + attrs... } else { @@ -452,7 +608,7 @@ var macro = { // macro match -> call macro... if(name in macro){ - $(e).replaceWith(macro[name].call(context, e, state)) + $(e).replaceWith(macro[name].call(that, context, e, state)) // normal tag -> attrs + sub-tree... } else { @@ -474,12 +630,9 @@ var macro = { // macro stage... - // XXX need to update .macro... _parse(context, parsed, this.macro) // filter stage... - // XXX need to update .filters to take html and return html... - /* state.filters .concat(this.__filters__) // unique -- leave last occurance.. @@ -509,7 +662,6 @@ var macro = { // use the filter... parsed = k.call(that, context, parsed) }) - //*/ // merge includes... // @@ -524,14 +676,22 @@ var macro = { // XXX I do not like that we are reparsing the whole page here... // ...the only alternative I see is traversing the whole // page agin -- _parse(..) stage 1.5???... - .html(parsed.html().replace(this.__include_marker__, function(){ + .html(parsed.html().replace(include_marker, function(){ var page = state.include.shift() - return $('') + return $('
') + .append($('') .attr('src', page.path) - .append(page - .parse({ slots: state.slots }, true)) + //.append(page + // .parse({ slots: state.slots }, true)) + .append(that + .parse(context, + page.raw, + { slots: state.slots }, + true))) + .html() })) + /* XXX do we need this??? // tag includes... .find('include').each(function(i, elem){ var src = $(elem).attr('src') @@ -545,12 +705,17 @@ var macro = { // XXX this uses old Wiki.parse(..) method/parser... $(elem) .empty() - .append(that.get(src) - .parse({ slots: state.slots }, true)) + //.append(that.get(src) + // .parse({ slots: state.slots }, true)) + .append(that + .parse(context, + context.get(src).raw, + { slots: state.slots }, + true)) }) + //*/ // post macro... - // XXX need to update .post_macro... if(!skip_post){ _parse(context, parsed, this.post_macro) } @@ -744,6 +909,8 @@ var Wiki = { '\\[[^\\]]+\\]', ].join('|') +')', 'g'), + __macro_parser__: macro2, + // Resolve '.' and '..' relative to current page... // @@ -961,7 +1128,7 @@ var Wiki = { parse: function(state, skip_post){ // special case: if we are getting ./raw then do not parse text... return this.title == 'raw' ? this.raw - : macro.parse(this, this.raw, state, skip_post) + : this.__macro_parser__.parse(this, this.raw, state, skip_post) }, get text(){ return this.parse() },