Brand new plugin interface


(rwdaigle) #58

Is there a pattern for packaging db migrations with a plugin?


(Tomasz Stachewicz) #59

I know Rails pattern for adding models, views, controllers and other code in engines. Is there a pattern for Discourse plugins to provide Ember code (views, templates, controllers) and have it picked up by the application?
After moving template and controller from app/assets/javascripts/discourse/{templates,controllers} to vendor/gems/discourse_foo/vendor/assets/javascripts/discourse/{templates,controllers} the templates and controllers are no longer recognized by the application’s Ember code: after this operation {{ render “foo” }} does not render anything.

Second question, tougher: how to extend existing templates in unobtrusive way, other than editing them in original locations (forum owners would not be happy, this is going back to phpbb) or override-and-maintain-whole-file? Rails Engines have GitHub - spree/deface: Rails plugin that allows you to customize ERB views in a Rails application without editing the underlying view. .
Or am I approaching it wrong and I should just use plugin’s javascript to inject the rendered content into designated part of the page?


(Kasper Peulen) #60

I’m using vagrant. What do you mean with restart your services ? How can I do that ?
The only way I’m able to make sure that changes like this actually occur is when I completely reinstall everything. I delete my github folder, I delete the box, and then reinstall everything again, and then it works, but I feel must be able to do this faster.


(Kasper Peulen) #61

##MathJax 0.2

Support math notations for Discourse using http://www.mathjax.org/. In this version mathjax is properly escaped from the markdown parser. I have also included some mathjax.hub.config similar as math.stackexchange. I have tested this, and you will need this commit as well to let everything between $...$ escaped properly. I have made a pull request for this.

I have only added the align environment. You can easily add other ones by hand, but there are quite much environments, and I think it would be better to make some good code that recognize all those environments at once, but I don’t know how to do that.

I have now added all the latex environments mathjax supports. I feel like there may be a smarter way to do this, but at least this works.

I found a smart way to add all the latex environments in once. This code is a lot shorter in this way.

There are still some problems with flickering in the preview. I have no idea how I could fix this.

Example

###plugins/mathjax/plugin.rb

# name: MathJax support for Discourse
# version: 0.2
# authors: Sam Saffron, Kasper Peulen

register_asset('javascripts/tex_dialect.js', :server_side)
register_javascript <<JS 

    Discourse.addInitializer(function () {

      $LAB.script('http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML').wait(function() {
         
MathJax.Hub.Config({ "HTML-CSS": { 
	preferredFont: "TeX", 
	availableFonts: ["STIX","TeX"], 
	linebreaks: { automatic:true }, 
	EqnChunk: (MathJax.Hub.Browser.isMobile ? 10 : 50) },
        tex2jax: { 
	inlineMath: [ ["$", "$"], ["\\\\(","\\\\)"] ], 
	displayMath: [ ["$$","$$"], ["\\\\[", "\\\\]"] ], 
	processEscapes: true},
        TeX: { 
	noUndefined: { attributes: { mathcolor: "red", mathbackground: "#FFEEEE", mathsize: "90%" } }, 
	Macros: { href: "{}" } },
        messageStyle: "none"
});

        var applyPreview = _.debounce(function(){
          MathJax.Hub.Queue(["Typeset",MathJax.Hub,"wmd-preview"]);
        }, 500);

        var applyBody = function(){
          MathJax.Hub.Queue(["Typeset",MathJax.Hub,"topic"]);
        };

        Discourse.PostView.prototype.on("postViewInserted", applyBody);
        Discourse.ComposerView.prototype.on("previewRefreshed", applyPreview);

      });

    });
JS

###plugins/mathjax/assets/javascripts/tex_dialect.js

Discourse.Dialect.inlineBetween({
  start: '\\(',
  stop: '\\)',
  rawContents: true,
  emitter: function(contents) { return '\\('+contents+'\\)'; }
});

Discourse.Dialect.inlineRegexp({
start: '$',
matcher: /(\$)([\S\s]+)(\$)/,
emitter: function(matches) {return matches[0];}
});

Discourse.Dialect.replaceBlock({
  start: /(\\\[)([\s\S]*)/,
  stop: '\\]',
  rawContents: true,
  emitter: function(contents) { return '\\['+contents+'\\]'; }
});

Discourse.Dialect.inlineRegexp({
  start: '\\begin',
  matcher: /(\\begin{[\S\s]+})([\S\s]*)(\\end{[\S\s]+})/,
  emitter: function(matches) { return matches[0]; }
});

/**
This is a function that allows $$..$$ to be used as align if a "&" is typed.
Usefull for lazy latex typers like me, it works like a shortcut.

Discourse.Dialect.inlineRegexp({
start: '$',
matcher: /(\$)([\S\s]+)(\$)/,
emitter: function(matches) {
if ( matches[0].match(/(\$\$)([\S\s]+[&][\S\s]+)(\$\$)/) ){
return '\\begin{align*}'+matches[2].slice(1,-1)+'\\end{align*}'; }
else {return matches[0];}
}
});
**/

Discourse should render LaTeX
#63

Can this plugin be used as an example of plugin to modify oneboxes?


(Vikhyat Korrapati) #66

The Onebox examples are out of date now, since switching to the onebox gem.

Adding a host to the whitelist:

Onebox::Engine::WhitelistedGenericOnebox.whitelist.push "aetus.net"

To implement a custom Onebox you just need to define a class whose name ends with Onebox that implements to_html. Example that fetches information from a JSON API and renders it:

module Onebox
  module Engine
    class HummingbirdOnebox
      include Engine
      include JSON

      matches_regexp /https?:\/\/hummingbird\.me\/anime\/.+/

      def url
        slug = @url.match(/https?:\/\/hummingbird\.me\/anime\/(.+)/)[1]
        "http://hummingbird.me/api/v1/anime/#{slug}"
      end

      def to_html
        anime = raw
        "
        <div class='onebox-result'>
          <div class='source'>
            <div class='info'>
              <a href='#{@url}' class='track-link' target='_blank'>
                Anime (#{anime["show_type"]})
              </a>
            </div>
          </div>
          <div class='onebox-result-body'>
            <img src='#{anime["cover_image"]}' class='thumbnail'>
            <h3><a href='#{@url}' target='_blank'>#{anime["title"]}</a></h3>
            <h4>#{anime["genres"].map {|x| x["name"] } * ", "}</h4>
            #{anime["synopsis"]}
          </div>
          <div class='clearfix'></div>
        </div>
        "
      end
    end
  end
end

Google Calendar example:

module Onebox
  module Engine
    class GoogleCalendarOnebox
      include Engine
      matches_regexp /^https?:\/\/(?:www\.)?google\.com\/calendar\/embed\?.+/

      def to_html
        "<iframe src='#{@url}' style='border-width:0' frameborder='0' scrolling='no' width='100%'></iframe>"
      end
    end
  end
end

Onebox and whitelist
Can we get Tutorial for Onebox-ing plugin
Topic Templates
(Sean O'Hara) #67

Does anyone know how to get discourse to ‘recognize’ a plugin that has been added to the plugins directly? I added the oauth plugin found here: discourse_oauth2_example/plugin.rb at master · michaelkirk/discourse_oauth2_example · GitHub to the directory, and it seems to be ignored by discourse (it is not an enable oauth method at login).

thx


(Michael - DiscourseHosting.com) #68

did you restart everything?


(Sean O'Hara) #69

Yeah, I restarting several times. I know the file is being eval’ed because I can get it to error when restarting, but apart from that I don’t see any effect on the application.


(Sean O'Hara) #70

Ok, it’s working now… I had to rm -rf tmp/cache. Should have tried that before posting here. Sorry for the noise! And thanks for the help @michaeld.


(Sam Saffron) #71

Should not be needed any more:

https://github.com/discourse/discourse/commit/8e9cfdfcda0da1b02e917983658d00250650f264


(Michael - DiscourseHosting.com) #72

Can you tell a bit more about that ‘fancy cache’ @sam ?


(Régis Hanol) #73

He’s talking about that


(Michael - DiscourseHosting.com) #74

Nice!

Do I understand correctly that this does mean that all public assets are unavailable during precompilation though ? Of course this occurs less frequently because the precompilation phase is much faster, but still.


(Sam Saffron) #75

Yeah, just checked in something slightly less aggressive that should do.


(Denis Peplin) #76

Assets precompile outputs error in development mode:

$ rake assets:precompile
rake aborted!
rake assets:precompile should only be run in RAILS_ENV=production, you are risking unminified assets

But rm -rf tmp/cache works fine.


(Sam Saffron) #77

assets precompile is meaningless in development.


Tmp/cache needs to be manually cleared when developing plugins
(adamfortuna) #78

We’ve been upgrading our current discourse forum ( http://discuss.codeschool.com/ ) to use the plugin interface rather than the custom job we started working on 6 months back and it’s seriously reduced the code size and complexity. Have been able to re-fork from master with only adding the new plugin and have things work, which was a nice surprise. Awesome job on the interface for it!

The only things I’m curious about right now which aren’t able to be added to the plugin are:


Gem requirements. We have some gems that are on an custom gem server (new source in the gemfile). Also Gems which are only needed in development (our deployment gem). Right now I’m updating the Gemfile for these.

Images? All of the examples I’ve seen so far haven’t used images, so I was wondering if there was an easy way to register and use those? register_asset 'images/logo.png' kind of thing? Right now I just threw these in root/vendor/images, but would love to move them over to the plugin.


(Sam Saffron) #79

We support gem custom source

For Dev only gems you can switch on

if Rails.env.development?
   gem 'devgem'
end

(Sam Saffron) #80

Have a look at how emoji plugin registers all the images it needs (just happens automatically if you follow the convention)