mirror of
https://github.com/flynx/pWiki.git
synced 2025-10-29 18:10:09 +00:00
refactoring plugins and block attribute handling...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
parent
7904e8c42e
commit
fee40ba47b
@ -5,6 +5,11 @@
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
var PLUGIN_ATTRS = true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Helpers...
|
// Helpers...
|
||||||
|
|
||||||
@ -192,25 +197,68 @@ var plugin = {
|
|||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
// XXX style attributes...
|
// XXX PLUGIN_ATTRS
|
||||||
|
// XXX this needs to know in what context it is called -- view or code...
|
||||||
|
// .__pre_parse__(..) implements the view handler but we have no
|
||||||
|
// way yet to hook into code parsing...
|
||||||
|
// XXX need to call plugins from JSONOutline...
|
||||||
var attributes = {
|
var attributes = {
|
||||||
__proto__: plugin,
|
__proto__: plugin,
|
||||||
|
|
||||||
__parse__: function(text, editor, elem){
|
// XXX where should we get .__block_attrs__???
|
||||||
var skip = new Set([
|
// ...editor, plugin, ...???
|
||||||
'text',
|
// XXX might be a good idea to split out the actual code handler to
|
||||||
'focused',
|
// be overloadable by other plugins...
|
||||||
'collapsed',
|
parseBlockAttrs: function(editor, text, keep=false, elem={}){
|
||||||
'id',
|
if(typeof(keep) == 'object'){
|
||||||
'children',
|
elem = keep
|
||||||
'style',
|
keep = typeof(elem) == 'boolean' ?
|
||||||
])
|
elem
|
||||||
return text
|
: false }
|
||||||
+ Object.entries(elem)
|
var system = editor.__block_attrs__
|
||||||
.reduce(function(res, [key, value]){
|
var clean = text
|
||||||
return skip.has(key) ?
|
// XXX for some reason changing the first group into (?<= .. )
|
||||||
res
|
// still eats up the whitespace...
|
||||||
: res + `<br>${key}: ${value}` }, '') },
|
// ...putting the same pattern in a normal group and
|
||||||
|
// returning it works fine...
|
||||||
|
//.replace(/(?<=[\n\h]*)(?:(?:\n|^)\s*\w*\s*::\s*[^\n]*\s*)*$/,
|
||||||
|
.replace(/([\n\t ]*)(?:(?:\n|^)[\t ]*\w+[\t ]*::[\t ]*[^\n]+[\t ]*)+$/,
|
||||||
|
function(match, ws){
|
||||||
|
var attrs = match
|
||||||
|
.trim()
|
||||||
|
.split(/(?:[\t ]*::[\t ]*|[\t ]*\n[\t ]*)/g)
|
||||||
|
while(attrs.length > 0){
|
||||||
|
var [name, val] = attrs.splice(0, 2)
|
||||||
|
elem[name] =
|
||||||
|
val == 'true' ?
|
||||||
|
true
|
||||||
|
: val == 'false' ?
|
||||||
|
false
|
||||||
|
: val
|
||||||
|
// keep non-system attrs...
|
||||||
|
if(keep
|
||||||
|
&& !(name in system)){
|
||||||
|
ws += `\n${name}::${val}` } }
|
||||||
|
return ws })
|
||||||
|
elem.text = keep == 'all' ?
|
||||||
|
text
|
||||||
|
: clean
|
||||||
|
return elem },
|
||||||
|
|
||||||
|
__parse_block__: function(code, editor, elem){
|
||||||
|
return this.parseBlockAttrs(
|
||||||
|
editor,
|
||||||
|
code,
|
||||||
|
editor.__code_attrs__,
|
||||||
|
elem)
|
||||||
|
.text },
|
||||||
|
__pre_parse__: function(text, editor, elem){
|
||||||
|
return this.parseBlockAttrs(
|
||||||
|
editor,
|
||||||
|
text,
|
||||||
|
editor.__view_attrs__,
|
||||||
|
elem)
|
||||||
|
.text },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -225,29 +273,30 @@ var blocks = {
|
|||||||
// markdown...
|
// markdown...
|
||||||
// style: headings...
|
// style: headings...
|
||||||
/* XXX chose either this or auto headings -- move docs...
|
/* XXX chose either this or auto headings -- move docs...
|
||||||
.replace(/^(?<!\\)######\s+(.*)$/, this.style(editor, elem, ['heading', 'heading-6']))
|
.replace(/^(?<!\\)######\s+([^]*)$/, this.style(editor, elem, ['heading', 'heading-6']))
|
||||||
.replace(/^(?<!\\)#####\s+(.*)$/, this.style(editor, elem, ['heading', 'heading-5']))
|
.replace(/^(?<!\\)#####\s+([^]*)$/, this.style(editor, elem, ['heading', 'heading-5']))
|
||||||
.replace(/^(?<!\\)####\s+(.*)$/, this.style(editor, elem, ['heading', 'heading-4']))
|
.replace(/^(?<!\\)####\s+([^]*)$/, this.style(editor, elem, ['heading', 'heading-4']))
|
||||||
.replace(/^(?<!\\)###\s+(.*)$/, this.style(editor, elem, ['heading', 'heading-3']))
|
.replace(/^(?<!\\)###\s+([^]*)$/, this.style(editor, elem, ['heading', 'heading-3']))
|
||||||
.replace(/^(?<!\\)##\s+(.*)$/, this.style(editor, elem, ['heading', 'heading-2']))
|
.replace(/^(?<!\\)##\s+([^]*)$/, this.style(editor, elem, ['heading', 'heading-2']))
|
||||||
.replace(/^(?<!\\)#\s+(.*)$/, this.style(editor, elem, ['heading', 'heading-1']))
|
.replace(/^(?<!\\)#\s+([^]*)$/, this.style(editor, elem, ['heading', 'heading-1']))
|
||||||
// XXX EXPERIMENTAL
|
// XXX EXPERIMENTAL
|
||||||
.replace(/^(?<!\\)@+\s+(.*)$/, this.style(editor, elem, ['heading', 'auto']))
|
.replace(/^(?<!\\)@+\s+([^]*)$/, this.style(editor, elem, ['heading', 'auto']))
|
||||||
/*/
|
/*/
|
||||||
// XXX EXPERIMENTAL
|
// XXX EXPERIMENTAL
|
||||||
.replace(/^(?<!\\)#+\s+(.*)$/, this.style(editor, elem, ['heading']))
|
// NOTE: '[^]' is the same as [\s\S] but is unique to JS...
|
||||||
.replace(/^(?<!\\)@+\s+(.*)$/, this.style(editor, elem, ['heading', 'no-toc']))
|
.replace(/^(?<!\\)#+\s+([^]*)$/, this.style(editor, elem, ['heading']))
|
||||||
|
.replace(/^(?<!\\)@+\s+([^]*)$/, this.style(editor, elem, ['heading', 'no-toc']))
|
||||||
//*/
|
//*/
|
||||||
// style: list...
|
// style: list...
|
||||||
//.replace(/^(?<!\\)[-\*]\s+(.*)$/m, style('list-item'))
|
//.replace(/^(?<!\\)[-\*]\s+([^]*)$/m, style('list-item'))
|
||||||
.replace(/^\s*(.*)(?<!\\):\s*$/, this.style(editor, elem, 'list'))
|
.replace(/^\s*([^]*)(?<!\\):\s*$/, this.style(editor, elem, 'list'))
|
||||||
.replace(/^\s*(.*)(?<!\\)#\s*$/, this.style(editor, elem, 'numbered-list'))
|
.replace(/^\s*([^]*)(?<!\\)#\s*$/, this.style(editor, elem, 'numbered-list'))
|
||||||
// style: misc...
|
// style: misc...
|
||||||
.replace(/^\s*(?<!\\)>\s+(.*)$/, this.style(editor, elem, 'quote'))
|
.replace(/^\s*(?<!\\)>\s+([^]*)$/, this.style(editor, elem, 'quote'))
|
||||||
.replace(/^\s*(?<!\\)((\/\/|;)\s+.*)$/, this.style(editor, elem, 'comment'))
|
.replace(/^\s*(?<!\\)((\/\/|;)\s+[^]*)$/, this.style(editor, elem, 'comment'))
|
||||||
.replace(/^\s*(?<!\\)NOTE:?\s*(.*)$/, this.style(editor, elem, 'NOTE'))
|
.replace(/^\s*(?<!\\)NOTE:?\s*([^]*)$/, this.style(editor, elem, 'NOTE'))
|
||||||
.replace(/^\s*(?<!\\)XXX\s+(.*)$/, this.style(editor, elem, 'XXX'))
|
.replace(/^\s*(?<!\\)XXX\s+([^]*)$/, this.style(editor, elem, 'XXX'))
|
||||||
.replace(/^(.*)\s*(?<!\\)XXX\s*$/, this.style(editor, elem, 'XXX'))
|
.replace(/^([^]*)\s*(?<!\\)XXX\s*$/, this.style(editor, elem, 'XXX'))
|
||||||
.replace(/^\s*---\+\s*$/, this.style(editor, elem, 'hr', '<hr>')) } ,
|
.replace(/^\s*---\+\s*$/, this.style(editor, elem, 'hr', '<hr>')) } ,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,6 +890,65 @@ var escaping = {
|
|||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
var JSONOutline = {
|
var JSONOutline = {
|
||||||
|
// Plugins...
|
||||||
|
//
|
||||||
|
// The order of plugins can be significant in the following cases:
|
||||||
|
// - parsing
|
||||||
|
// - event dropping
|
||||||
|
//
|
||||||
|
// NOTE: this is split into three to make recomposition simpler for
|
||||||
|
// inheritance...
|
||||||
|
// XXX do we need this structure???
|
||||||
|
//
|
||||||
|
// XXX split out DOM-specific plugins into Outline.plugins...
|
||||||
|
pre_plugins: [
|
||||||
|
// XXX PLUGIN_ATTRS
|
||||||
|
...(PLUGIN_ATTRS ?
|
||||||
|
[attributes]
|
||||||
|
: []),
|
||||||
|
//*/
|
||||||
|
blocks,
|
||||||
|
quoted,
|
||||||
|
],
|
||||||
|
norm_plugins: [
|
||||||
|
// NOTE: this needs to be before styling to prevent it from
|
||||||
|
// treating '[_] ... [_]' as italic...
|
||||||
|
tasks,
|
||||||
|
toc,
|
||||||
|
styling,
|
||||||
|
// XXX
|
||||||
|
tables,
|
||||||
|
symbols,
|
||||||
|
//syntax,
|
||||||
|
],
|
||||||
|
post_plugins: [
|
||||||
|
// keep this last...
|
||||||
|
// XXX revise -- should this be external???
|
||||||
|
escaping,
|
||||||
|
],
|
||||||
|
__plugins: undefined,
|
||||||
|
get plugins(){
|
||||||
|
return this.__plugins
|
||||||
|
?? (this.__plugins = [
|
||||||
|
...this.pre_plugins,
|
||||||
|
...this.norm_plugins,
|
||||||
|
...this.post_plugins,
|
||||||
|
]) },
|
||||||
|
|
||||||
|
// NOTE: if a handler returns false it will break plugin execution...
|
||||||
|
// XXX is this the right way to go???
|
||||||
|
runPlugins: function(method, ...args){
|
||||||
|
for(var plugin of this.plugins){
|
||||||
|
if(method in plugin){
|
||||||
|
if(plugin[method](...args) === false){
|
||||||
|
return false } } }
|
||||||
|
return true },
|
||||||
|
threadPlugins: function(method, value, ...args){
|
||||||
|
for(var plugin of this.plugins){
|
||||||
|
method in plugin
|
||||||
|
&& (value = plugin[method](value, ...args)) }
|
||||||
|
return value },
|
||||||
|
|
||||||
// format:
|
// format:
|
||||||
// {
|
// {
|
||||||
// <id>: <node>,
|
// <id>: <node>,
|
||||||
@ -919,6 +1027,12 @@ var JSONOutline = {
|
|||||||
__styles: undefined,
|
__styles: undefined,
|
||||||
|
|
||||||
// block render...
|
// block render...
|
||||||
|
//
|
||||||
|
// This will call plugins':
|
||||||
|
// .__pre_parse__(..)
|
||||||
|
// .__parse__(..)
|
||||||
|
// .__post_parse__(..)
|
||||||
|
//
|
||||||
// XXX PRE_POST_NEWLINE can we avoid explicitly patching for empty lines after pre???
|
// XXX PRE_POST_NEWLINE can we avoid explicitly patching for empty lines after pre???
|
||||||
__view_attrs__: false,
|
__view_attrs__: false,
|
||||||
__code2html__: function(code, elem={}){
|
__code2html__: function(code, elem={}){
|
||||||
@ -938,8 +1052,12 @@ var JSONOutline = {
|
|||||||
}[stage]
|
}[stage]
|
||||||
return that.threadPlugins(meth, text, that, elem) }
|
return that.threadPlugins(meth, text, that, elem) }
|
||||||
|
|
||||||
|
if(PLUGIN_ATTRS){
|
||||||
|
elem.text = code
|
||||||
|
} else {
|
||||||
elem = this.parseBlockAttrs(code, this.__view_attrs__, elem)
|
elem = this.parseBlockAttrs(code, this.__view_attrs__, elem)
|
||||||
code = elem.text
|
code = elem.text
|
||||||
|
}
|
||||||
|
|
||||||
// stage: pre...
|
// stage: pre...
|
||||||
var text = run('pre',
|
var text = run('pre',
|
||||||
@ -1014,6 +1132,7 @@ var JSONOutline = {
|
|||||||
// -> <elem>
|
// -> <elem>
|
||||||
//
|
//
|
||||||
// XXX move to config...
|
// XXX move to config...
|
||||||
|
// XXX PLUGIN_ATTRS...
|
||||||
__code_attrs__: false,
|
__code_attrs__: false,
|
||||||
parseBlockAttrs: function(text, keep=!!this.__code_attrs__, elem={}){
|
parseBlockAttrs: function(text, keep=!!this.__code_attrs__, elem={}){
|
||||||
if(typeof(keep) == 'object'){
|
if(typeof(keep) == 'object'){
|
||||||
@ -1069,7 +1188,12 @@ var JSONOutline = {
|
|||||||
// same level...
|
// same level...
|
||||||
if(sep.length == prev_sep.length){
|
if(sep.length == prev_sep.length){
|
||||||
var [_, block] = lst.splice(0, 2)
|
var [_, block] = lst.splice(0, 2)
|
||||||
var attrs = that.parseBlockAttrs(block)
|
// XXX PLUGIN_ATTRS...
|
||||||
|
if(PLUGIN_ATTRS){
|
||||||
|
var attrs = {}
|
||||||
|
attrs.text = that.threadPlugins('__parse_block__', block, that, attrs)
|
||||||
|
} else {
|
||||||
|
var attrs = that.parseBlockAttrs(block) }
|
||||||
attrs.text = that.__text2code__(attrs.text
|
attrs.text = that.__text2code__(attrs.text
|
||||||
// normalize indent...
|
// normalize indent...
|
||||||
.split(new RegExp('\n'+sep+' ', 'g'))
|
.split(new RegExp('\n'+sep+' ', 'g'))
|
||||||
@ -1237,44 +1361,15 @@ var Outline = {
|
|||||||
// XXX not sure what should the default be...
|
// XXX not sure what should the default be...
|
||||||
trim_block_text: false,
|
trim_block_text: false,
|
||||||
|
|
||||||
|
pre_plugins: [
|
||||||
// Plugins...
|
...JSONOutline.pre_plugins,
|
||||||
//
|
],
|
||||||
// The order of plugins can be significant in the following cases:
|
norm_plugins: [
|
||||||
// - parsing
|
...JSONOutline.norm_plugins,
|
||||||
// - event dropping
|
],
|
||||||
plugins: [
|
post_plugins: [
|
||||||
blocks,
|
...JSONOutline.post_plugins,
|
||||||
quoted,
|
|
||||||
|
|
||||||
// NOTE: this needs to be before styling to prevent it from
|
|
||||||
// treating '[_] ... [_]' as italic...
|
|
||||||
tasks,
|
|
||||||
toc,
|
|
||||||
styling,
|
|
||||||
// XXX
|
|
||||||
//attributes,
|
|
||||||
tables,
|
|
||||||
symbols,
|
|
||||||
//syntax,
|
|
||||||
|
|
||||||
// keep this last...
|
|
||||||
// XXX revise -- should this be external???
|
|
||||||
escaping,
|
|
||||||
],
|
],
|
||||||
// NOTE: if a handler returns false it will break plugin execution...
|
|
||||||
// XXX is this the right way to go???
|
|
||||||
runPlugins: function(method, ...args){
|
|
||||||
for(var plugin of this.plugins){
|
|
||||||
if(method in plugin){
|
|
||||||
if(plugin[method](...args) === false){
|
|
||||||
return false } } }
|
|
||||||
return true },
|
|
||||||
threadPlugins: function(method, value, ...args){
|
|
||||||
for(var plugin of this.plugins){
|
|
||||||
method in plugin
|
|
||||||
&& (value = plugin[method](value, ...args)) }
|
|
||||||
return value },
|
|
||||||
|
|
||||||
|
|
||||||
get header(){
|
get header(){
|
||||||
@ -2635,10 +2730,17 @@ var Outline = {
|
|||||||
if(elem.classList.contains('code')){
|
if(elem.classList.contains('code')){
|
||||||
var block = that.get(elem)
|
var block = that.get(elem)
|
||||||
// clean out attrs...
|
// clean out attrs...
|
||||||
|
// XXX PLUGIN_ATTRS...
|
||||||
|
if(PLUGIN_ATTRS){
|
||||||
|
elem.value =
|
||||||
|
that.trim_block_text ?
|
||||||
|
that.threadPlugins('__parse_block__', elem.value, that).trim()
|
||||||
|
: that.threadPlugins('__parse_block__', elem.value, that)
|
||||||
|
} else {
|
||||||
elem.value =
|
elem.value =
|
||||||
that.trim_block_text ?
|
that.trim_block_text ?
|
||||||
that.parseBlockAttrs(elem.value).text.trim()
|
that.parseBlockAttrs(elem.value).text.trim()
|
||||||
: that.parseBlockAttrs(elem.value).text
|
: that.parseBlockAttrs(elem.value).text }
|
||||||
that.update(block)
|
that.update(block)
|
||||||
// undo...
|
// undo...
|
||||||
if(elem.value != elem.dataset.original){
|
if(elem.value != elem.dataset.original){
|
||||||
|
|||||||
@ -146,6 +146,8 @@ var setup = function(){
|
|||||||
- attributes: need to show/hide the attributes -- option?
|
- attributes: need to show/hide the attributes -- option?
|
||||||
attr::value
|
attr::value
|
||||||
- Q: should this be completely handled by a plugin???
|
- Q: should this be completely handled by a plugin???
|
||||||
|
_(see: `PLUGIN_ATTRS`)_
|
||||||
|
- this plugin needs to be called from `JSONOutline` (???)
|
||||||
- `.parseBlockAttrs(..)`: add hook to plugins to handle output...
|
- `.parseBlockAttrs(..)`: add hook to plugins to handle output...
|
||||||
- _plugin will need to get the call context -- can be called when handling for view or code_
|
- _plugin will need to get the call context -- can be called when handling for view or code_
|
||||||
- `.parseBlockAttrs(..)`: add data attributes to code if missing...
|
- `.parseBlockAttrs(..)`: add data attributes to code if missing...
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user