benweet / stackedit

In-browser Markdown editor
https://stackedit.io/
Apache License 2.0
21.64k stars 2.72k forks source link

Can we define some new rules for markdown engine? #34

Closed vanabel closed 10 years ago

vanabel commented 11 years ago

It seems quite strange we want to add some new behavior to the markdown engine. But it is really reasonable to do so in some case: the main reason is to make the markdown more excellent.

In my situation, I want to add some theorem style css, this can be done as:

<div class="thm" style="border: solid 1px #ccc"><strong>Theorem.</strong> 
When we have a dream, please don't let it go easily!
</div>

But what I like to do this is by:

\begin{thm}
When we have a dream, please don't let it go easily!
\end{thm} 

Thus, my question is that can we add some self-defined rule, that markdown can translate the \begin{thm} to <div class="thm" style="border:solid 1px #ccc"> and the \end{thm} to </div>?

If, furthermore, we can define some css style somewhere, then the \begin{thm} only need to rendered as <div class="thm">.

This is quite convenient when it combined with my LaTeX2HTML plugin (preview it in wp) for Wordpress.

benweet commented 11 years ago

Hi @vanabel

You can play with PageDown converter using the new UserCustom extension. For instance, you can perform your conversion by adding this to the extension JavaScript code:

userCustom.onEditorConfigure = function(editor) {
    var converter = editor.getConverter();
    converter.hooks.chain("preConversion", function(text) {
        return text.replace(/\\begin{thm}([\s\S]*?)\\end{thm}/g, function(wholeMatch, m1) {
            return '<div class="thm">' + m1 + '</div>';
        });
    });
};

You can also add custom CSS to StackEdit by adding this:

userCustom.onReady = function() {
    $("head").append($('<style type="text/css">.thm {border:solid 1px #ccc;}</style>'));
}
vanabel commented 11 years ago

Thank you very very much! It works finely!

However, since I want to replace not only thm but also lem, cor and so on, I didn't know why the following code didn't work (not even for my purpose):

userCustom.onEditorConfigure = function(editor) {
    var converter = editor.getConverter();
        converter.hooks.chain("preConversion", function(text) {
                var array={"thm":"thm","lem":"lem"};
                  for (var val in array){
                        return text.replace(
                            /\\begin{array[val]}([\s\S]*?)\\end{array[val]}/g, 
                              function(wholeMatch, m1) {
                                    return '<div class="latex_"'+array[val]+'>' + m1 + '</div>';
                                });
                    };
    });
};
};

Could you please so kind to save me from my bad code again?

vanabel commented 11 years ago

Another thing is that why the line break is missed? For example, when I write something like:

\begin{thm}
this is really awesome!

Did you see it?
\end{thm}

It should be displayed on two lines but it is in the same one.

benweet commented 11 years ago

You can convert Markdown inside your block this way:

userCustom.onEditorConfigure = function(editor) {
    var converter = editor.getConverter();
    converter.hooks.chain("preConversion", function(text) {
        return text.replace(/\\begin{thm}([\s\S]*?)\\end{thm}/g, function(wholeMatch, m1) {
            return '<thm>' + m1 + '</thm>';
        });
    });
    converter.hooks.chain("preBlockGamut", function(text, blockGamutHookCallback) {
        return text.replace(/<thm>([\s\S]*?)<\/thm>/g, function(wholeMatch, m1) {
            return '<div class="thm">' + blockGamutHookCallback(m1) + '</div>';
        });
    });
};

Regarding your code, I think it would be useful for you to learn JavaScript and RegEx...

vanabel commented 11 years ago

@benweet that's work!

vanabel commented 11 years ago

I believe I can do it now, as a test:

var s = '\\begin{thm}\
some thm\
\\end{thm}\
somethings\
\\begin{lem}\
soem lem\\end{lem}\
test of Examples:\
\\begin{excs}\
some excs\
\\end{excs}\
some other thing\
\\begin{examp}\
some examp\
\\end{examp}';

var array={"thm":"Theorem","lem":"Lemmma", "cor":"Corollary", "prop":"Property","defn":"Definition","rem":"Remark","prob":"Problem", "excs":"Exercise","examp":"Example"};
var num_thm=1;      
var num_excs=1;

s = s.replace(/\\begin{(thm|lem|examp|excs)}([\s\S]*?)\\end{\1}/g, function(a, b, c) {
    if (b=="excs"|b=="examp"|b=="prob"){
    return '<div class="latex_'+b+'"><strong>'+array[b]+' '+num_excs+++'. </strong>'+c+"</div>";
    }
    else{
    return '<div class="latex_'+b+'"><strong>'+array[b]+' '+num_thm+++'. </strong>'+c+'</div>';
    }
})

document.write(s)
vanabel commented 11 years ago

This is my final version:

userCustom.onEditorConfigure = function (editor) {
  var converter = editor.getConverter();
  var array = {
    "thm": "Theorem",
    "lem": "Lemmma",
    "cor": "Corollary",
    "prop": "Property",
    "defn": "Definition",
    "rem": "Remark",
    "prob": "Problem",
    "excs": "Exercise",
    "examp": "Example"
  };
  var num_thm = 1;
  var num_excs = 1;
  converter.hooks.chain("preConversion", function (text) {
    return text.replace(/\\begin{(thm|lem|cor|prop|defn|rem|prob|examp|excs)}([\s\S]*?)\\end{\1}/g, function (wholeMatch, b, c) {
      return '<' + b + '>' + c + '</' + b + '>';
    });
  });
  converter.hooks.chain("preBlockGamut", function (text, blockGamutHookCallback) {
    return text.replace(/<(thm|lem|cor|prop|defn|rem|prob|examp|excs)>([\s\S]*?)<\/\1>/g, function (wholeMatch, b, c) {
      if (b == "excs" | b == "examp" | b == "prob") {
        return '<div class="latex_' + b + '"><strong>' + array[b] + ' ' + num_excs+++'. </strong>' + c + '</div>';
      } else {
        return '<div class="latex_' + b + '"><strong>' + array[b] + ' ' + num_thm+++'. </strong>' + c + '</div>';
      }
    });
  });
};
userCustom.onReady = function () {
  $("head").append($(
    '<style type="text/css">\n@import url("https://yandex.st/highlightjs/7.3/styles/solarized_light.min.css");\n\
    .latex_thm, .latex_lem, .latex_cor, .latex_defn, .latex_prop, .latex_rem{\n\
        border:solid 1px #ccc;\n\
        font-style:normal;\n\
        margin:15px 0;\n\
        padding:5px;\n\
        background: lightcyan;\n\
        border: solid 3px green;\n\
        -moz-border-radius: 1.0em;\n\
        -webkit-border-radius: 7px;\n\
        box-shadow: 0 0 0 green;\n\
        }\n\
        .latex_prob, .latex_examp, .latex_excs {\
        font-style:normal;\n\
        margin:10px 0;\n\
        padding:5px;\n\
        background: lightgoldenrodyellow;\n\
        border: solid 3px rgb(255, 203, 136);\n\
        -moz-border-radius: 1.0em; \n\
        -webkit-border-radius: 7px; \n\
        box-shadow: 0 0 0 green;\n\
        }\n\
</style>'
  ));
};
benweet commented 11 years ago

You are missing a point. I've changed my first implementation to be able to interpret Markdown inside your blocks. You need to use blockGamutHookCallback(c) otherwise the step preBlockGamut is useless and the following code is not interpreted correctly:

\begin{thm}
*Foo*

**Bar**
\end{thm} 
vanabel commented 11 years ago

Yes, I do, thanks for your comments!

vanabel commented 10 years ago

@benweet It seems that the user defined functional is not work any more, I tried your code:

userCustom.onEditorConfigure = function(editor) {
    var converter = editor.getConverter();
    converter.hooks.chain("preConversion", function(text) {
        return text.replace(/\\begin{thm}([\s\S]*?)\\end{thm}/g, function(wholeMatch, m1) {
            return '<div class="thm">' + m1 + '</div>';
        });
    });
};

which is provided by your at first. Now it not work in stackedit! Can you have a look at it?

benweet commented 10 years ago

Hi @vanabel The callback has been renamed. Just replace userCustom.onEditorConfigure by userCustom.onPagedownConfigure.

vanabel commented 10 years ago

Still something wrong, I tried the following code:

userCustom.onPagedownConfigure= function(editor) {
    var converter = editor.getConverter();
    converter.hooks.chain("preConversion", function(text) {
        return text.replace(/\\begin{thm}([\s\S]*?)\\end{thm}/g, function(wholeMatch, m1) {
            return '<thm>' + m1 + '</thm>';
        });
    });
    converter.hooks.chain("preBlockGamut", function(text, blockGamutHookCallback) {
        return text.replace(/<thm>([\s\S]*?)<\/thm>/g, function(wholeMatch, m1) {
            return '<div class="thm">' + blockGamutHookCallback(m1) + '</div>';
        });
    });
};

It works when I disable mathjax extension, not work when it is activated!

benweet commented 10 years ago

Can you try this:

userCustom.onPagedownConfigure= function(editor) {
    var converter = editor.getConverter();
    var preConversion = converter.hooks.preConversion;
    converter.hooks.preConversion = function(text) {
        text = text.replace(/\\begin{thm}([\s\S]*?)\\end{thm}/g, function(wholeMatch, m1) {
            return '<thm>' + m1 + '</thm>';
        });
        return preConversion(text);
    };
    converter.hooks.chain("preBlockGamut", function(text, blockGamutHookCallback) {
        return text.replace(/<thm>([\s\S]*?)<\/thm>/g, function(wholeMatch, m1) {
            return '<div class="thm">' + blockGamutHookCallback(m1) + '</div>';
        });
    });
};
vanabel commented 10 years ago

@benweet It works! thanks!

vanabel commented 10 years ago

@benweet It seems that this final code is not work anymore.

alejandroiglesias commented 10 years ago

@benweet i'm also scratching my head looking into how to make a custom extension, but it's not working. I managed to create a file in the extensions directory, add it to eventMgr.js for it to be loaded and it's being called. The problem is that aside from being loaded, the replacement is not working. Can you at least detail how to create an extension for a basic tag replacement like [abc]foo[/abc]?

benweet commented 10 years ago

This should work:

userCustom.onPagedownConfigure = function(editor) {
    var converter = editor.getConverter();
    converter.hooks.chain("preBlockGamut", function(text) {
        return text.replace(/\[abc\]foo\[\/abc\]/g, 'bar');
    });
};

You can copy/paste that at the end of userCustom.js or directly in the app: Settings->Extensions->UserCustom.

benweet commented 10 years ago

By the way if you modify the code, you have to run stackedit with the ?debug switch to see your changes. Basically http://localhost/?debug, after installing the bower dependencies as described in the developer guide.

alejandroiglesias commented 10 years ago

@benweet thank you very much for your comments. Yes, i was running the app with the ?debug param. The problem was in my regular expression. I was using

[abc]
foo
[/abc]

instead of [abc]foo[/abc] as the input. I had to replace my dot character with [^] for it to catch it having newline characters. Now it works wonderfully.