johno / ember-remarkable

Ember addon for Remarkable markdown parsing helpers and components.
MIT License
26 stars 20 forks source link

Dynamic text not working on ember-cli 2.8 #25

Open milindalvares opened 8 years ago

milindalvares commented 8 years ago
{{md-text
            text = "{{link-to 'index' 'index'}}"
            dynamic=true
          }}

Works fine without the dynamic flag. No error in console or anything, just a blank page.

maciek134 commented 7 years ago

Error in console while trying to use dynamic=true in ember-cli > 2.6:

_ember['default'].HTMLBars.compile is not a function

They for some reason removed .compile from HTMLBars. I tried looking for solution, but couldn't find any. I'll gladly provide a pull request if anyone can point me in the right direction.

danieledraganti commented 7 years ago

Hello, I have found this useful answer on StackOverflow: https://stackoverflow.com/questions/37345098/dynamically-compile-a-htmlbars-template-at-runtime-in-ember-2-5 May be helpful; sure, at this point it will require more NPM dependencies, but I think it's worth the effort if it gives dynamic template compile from ember-remarkable.

vasilakisfil commented 6 years ago

By adding app.import('vendor/ember/ember-template-compiler.js'); on ember-cli-builld.js it worked (taken from the link pasted above), so I think we should close this issue @johnotander

buzzware commented 6 years ago

I'm having similar problems with ember 3.1 with Error: Cannot call compile without the template compiler loaded. Please load ember-template-compiler.js prior to calling compile. How? ember-template-compiler.js now lives at ember-source/dist/ember-template-compiler.js but I don't know how to use it in my module.

danieledraganti commented 6 years ago

@buzzware, I have followed the solution suggested by @vasilakisfil, and have also manually added the component to my app/components folder slightly editing the original code.

updateTemplate() {
        this.set('subLayout', null);
        scheduleOnce('afterRender', this, function() {
            try {
                let layout = null;
                if (this.get('dynamic'))
                    layout = Ember.HTMLBars.compile(this.get('parsedMarkdownUnsafe'), false);
                else
                    layout = Ember.HTMLBars.compile(htmlSafe(this.get('parsedMarkdownUnsafe')), false);
                this.set('subLayout', layout);
            }
            catch(error) {}
        });
    },

... or at least I believe I have edited it... I may have rolled it back to the original one somehow... but maybe this can guide you in the right direction. Keep in mind to add app.import('vendor/ember/ember-template-compiler.js'); to ember-cli.js too, though.

buzzware commented 6 years ago

@danidr Thanks for the reply, but I haven't understood your point. I'm trying to get Ember.HTMLBars.compile to work in production for the dynamic feature of this component with Ember 3.1.

There must be another step after app.import to use Ember.HTMLBars.compile as you do.

The source is here https://github.com/emberjs/ember.js/blob/87f7ee8a8e76c1809ad32b59eb62fc5cd35daa58/packages/ember-template-compiler/lib/system/compile.js and it specifically says "This is not present in production builds." but how do we import/include it anyway? My knowledge of JS module systems is very poor.

buzzware commented 6 years ago

I don’t understand why it wasn’t working before, but its working now. Weirdly, it started working when I added @glimmer/compiler as a dependency (not devDependency) in packages.json. But then I removed it, and rebuilt, and even did “rm -rf node_modules && rm-rf dist/* && npm install” and it still works. So, the only required addition is app.import('vendor/ember/ember-template-compiler.js'); to ember-cli-build.js

buzzware commented 6 years ago

@danidr I'm now having an issue with the markdown rendering working when the first route is loaded, but when I navigate and then hit the back button, the md-text component doesn't rerender. The model is a POJO, not Ember.Object. {{model.title}} updates fine, but {{md-text text=model.content html=true dynamic=true}} doesn't.

Would your updateTemplate code fix this? Can you paste the whole component?

I wonder if its something to do with the convoluted way dynamic rendering is happening here eg. md-text.hbs : {{#if dynamic}} {{md-dummy layout=precompiledTemplate}} {{else}} {{parsedMarkdown}} {{/if}}

danieledraganti commented 6 years ago

@buzzware Well, I have rewritten the component, but I honestly can't remember WHERE I edited it exactly... I'll just post the whole code for you here below. Sorry for spamming, but all this code is in a private repository, therefore I can't link to it directly. components/md-text.js

import Ember from 'ember';
import Component from '@ember/component';
import { computed, observer } from '@ember/object';
import { getOwner } from '@ember/application';
import { htmlSafe } from '@ember/string';
import { scheduleOnce } from '@ember/runloop';
import Remarkable from 'npm:remarkable';

export default Component.extend({
    tagName: '',

    text: '',
    breaks: true,
    typographer: true,
    linkify: true,
    linkTarget: '',
    html: false,
    extensions: true,
    dynamic: true,

    didInsertElement() {
        scheduleOnce('afterRender', this, 'updateTemplate');
    },

    highlightJsExcluded: computed(function () {
        let config;
        if (getOwner) {
            config = getOwner(this).resolveRegistration('config:environment');
        } else {
            let registry = this.container.registry || this.container._registry;
            config = registry.resolve('config:environment');
        }
        let remarkableConfig = config.remarkable || {};
        return remarkableConfig.excludeHighlightJs || false;
    }),

    highlight: computed('highlightJsExcluded', function() {

        let highlightJsExcluded = this.get('highlightJsExcluded');
        return (str, lang) => {
            if (!highlightJsExcluded) {
                if (lang === 'text' || lang === 'no-highlight') {
                    return '';
                }

                if (lang && hljs.getLanguage(lang)) {
                    try {
                        return hljs.highlight(lang, str).value;
                    } catch (err) {}
                }

                try {
                    return hljs.highlightAuto(str).value;
                } catch (err) {}
            }

            return '';
        };
    }),

    parsedMarkdownUnsafe: computed('text', 'html', 'typographer', 'linkify', 'linkTarget', function () {
        var md = new Remarkable({
            breaks: this.get('breaks'),
            typographer: this.get('typographer'),
            linkify: this.get('linkify'),
            linkTarget: this.get('linkTarget'),
            html: this.get('html'),
            highlight: this.get('highlight')
        });

        if (this.get('extensions')) {
            md.core.ruler.enable([
                'abbr'
            ]);
            md.block.ruler.enable([
                'footnote',
                'deflist'
            ]);
            md.inline.ruler.enable([
                'footnote_inline',
                'ins',
                'mark',
                'sub',
                'sup'
            ]);
        }
        md.core.ruler.disable([ 'smartquotes' ]);

        let plugins = this.get('plugins');
        if (plugins) {
            plugins.forEach((plugin) => md.use(plugin));
        }

        return md.render(this.get('text'));
    }),

    updateTemplate() {
        this.set('subLayout', null);
        scheduleOnce('afterRender', this, function() {
            try {
                let layout = null;
                if (this.get('dynamic'))
                    layout = Ember.HTMLBars.compile(this.get('parsedMarkdownUnsafe'), false);
                else
                    layout = Ember.HTMLBars.compile(htmlSafe(this.get('parsedMarkdownUnsafe')), false);
                this.set('subLayout', layout);
            }
            catch(error) {}
        });
    },

    observerSource: observer('text', function() { this.updateTemplate(); }),

}).reopenClass({
    positionalParams: ['text']
});

components/md-text-renderer.js

import Component from '@ember/component';

export default Component.extend({
    tagName: ''
});

templates/components/md-text.js

{{#if subLayout}}
    {{md-text-renderer layout=subLayout}}
{{/if}}

NOTES:

Let me know if it helps somehow.

buzzware commented 6 years ago

Big thanks @danidr ! Thats working. This dynamic rendering is very cool. I'm using it with https://github.com/buzzware/broccoli-static-site-json#remove-showdown to achieve something a bit like https://www.gatsbyjs.org ie dynamically loaded markdown with ember components

danieledraganti commented 6 years ago

@buzzware Glad to hear it worked! I'll have a look at your code.