Having some issues with inserting iframes using Discourse's Ember API

The plugin puts an i-frame into Discourse and you can find it here

I keep it more or less updated to the latest version so the breaking change came recently. We’re currently running 3.3.0.beta1-dev.

In console i get 3 error messages which look like this:

docuss.js:225 Uncaught (in promise) ReferenceError: Ember is not defined
at docuss.js:225:1

Most probably this Ember object has been removed from the Discourse API in a recent version of Discourse, so this error comes after a Discourse upgrade effecting those objects.

Here’s all the fixes i made:

Change 1

assets\javascripts\discourse\initializers\docuss.js.es6
line 232

old:

const afterRender = res =>
  new Promise(resolve => {
    // @ts-ignore
    Ember.run.schedule('afterRender', null, () => resolve(res))

new:

import { schedule } from '@ember/runloop'

const afterRender = res =>
  new Promise(resolve => {
     schedule('afterRender', null, () => resolve(res))
  })

Change 2

assets\javascripts\discourse\lib\DcsIFrame.js.es6
line 858

old:

  const afterRender = res =>
	new Promise(resolve => {
		Ember.run.schedule('afterRender', null, () => resolve(res))
	})

new:

	import { schedule } from '@ember/runloop'

	const afterRender = res =>
	  new Promise(resolve => {
		schedule('afterRender', null, () => resolve(res))
	  })

Change 3

assets\javascripts\discourse\lib\onDidTransition.js.es6
line 239

old:

const afterRender = res =>
  new Promise(resolve => {
    Ember.run.schedule('afterRender', null, () => resolve(res))

new:

import { schedule } from '@ember/runloop'

const afterRender = res =>
  new Promise(resolve => {
      schedule('afterRender', null, () => resolve(res))

That cleared up all the error messages in console but created a series of new ones:

 Discourse v3.3.0.beta1-dev — https://github.com/discourse/discourse/commits/4c7d58a883 — Ember v5.5.0
app.js:197 Uncaught ReferenceError: Ember is not defined
    at s.callback (docuss.js:210:1)
    at s.exports (loader.js:106:1)
    at requireModule (loader.js:27:1)
    at y (app.js:171:18)
    at w (app.js:194:19)
    at app.js:157:29
    at e.start (app.js:51:5)
    at HTMLDocument.<anonymous> (start-app.js:5:7)
    at discourse-boot.js:20:12
    at discourse-boot.js:1:1

Here’s a live platform with the plugin turned on incase its helpful

Is that issue familiar to anyone ran into issues with Ember APIs objects changing. Any suggestions on how to fix them would be greatly appreciated.

2 Likes

Hello!

You forget this one:

I believe you could do something like that. This still should work.

import { observes } from "discourse-common/utils/decorators";

@observes("model.tags")
tagsChanged() {

}

On a side note, the composer controller has been moved to a service now.

4 Likes

Have you checked out the recommended alternative from the GitHub page?

The Author I believe is active here.

1 Like

Thanks for the suggestion @Heliosurge. We’ve baked the old one in pretty deep to our project though, so with the authors blessing we’ve taken over maintaining it.

A bit short on devs with the relevant skills in our Open Source community at the moment though.

1 Like

Yeah makes perfect sense.

1 Like

Thanks for that @Arkshine. My laptop died when a replacement charger fried the charging circuit, so i wasn’t able to test it out until i was able to repair the laptop yesterday.

I put the import statement at the top of the page and your code underneath but seem to be hitting syntax errors when i try to add that or similar variations of it:

Visual Basic Studio finds these errors:

// New tagsChanged function with @observes decorator
@observes("model.tags")
tagsChanged() {
  // See if it is a balloon tag

The open bracket at the end of this line: tagsChanged() {

has this error message:
‘;’ expected.ts(1005)

  1. The last bracket in the code also has an error flag with this message:

‘}’ expected.ts(1005)
docuss.js.es6(219, 54): The parser expected to find a ‘}’ to match the ‘{’ token here.

This is line 219:
tagsChanged: Ember.observer('model.tags', function() {

My server says this when i try to build:

  251 |     }, 0);
  252 |   }
> 253 | }.observes("model.tags"),
      |                          ^
        in /tmp/broccoli-6523ExbXtskE5c0h/out-1067-funnel
        at Babel (Babel: discourse-plugins)
  - name: Error
  - nodeAnnotation: Babel: discourse-plugins
  - nodeName: Babel
  - originalErrorMessage: /var/www/discourse/app/assets/javascripts/discourse/discourse/plugins/docuss/discourse/initializers/docuss.js: Unexpected token (253:25)

I can’t see why, but i was never able to get this fix to work, or a number of variations on it which is odd as it worked on the other files just fine. My focused shifted for a while but its been bugging me.

Looking back at it now and can’t see what’s causing the issue. I’ve reverted it back to the orginal. Can anyone see what needs to be changed here to update to the new Ember API?

Here are a few pointers:

  • The site settings have been moved to a service:

    const siteSettings = container.lookup('service:site-settings');
    if (!siteSettings.docuss_enabled) {
      return;
    }
    
  • location:discourse-locationlocation:history

  • afterRender().then(() => onAfterRender(container));
    afterRender is a decorator you put above a method in a component class; you are not supposed to use it directly as a function.
    I think you want (it doesn’t seem to be needed), possibly:

    import { schedule } from '@ember/runloop';
    schedule("afterRender", () => onAfterRender(container))
    
  • You have a large piece of code out of the composeStateChanged function, it seems.
    Also, you can use the router service here: container.lookup('router:main').transitionTo(path);this.router.transitionTo(path);

  • The header has been modernized. Customization in home-logo widget is deprecated in your context. More information here: Upcoming Header Changes - Preparing Themes and Plugins.
    In your case, you will need glimmer header mode setting to auto or enabled. Then, you can use a plugin outlet to replace the content:

    api.renderInOutlet("home-logo-contents", <template>
      <HomeLogoContents
        @logoSmallUrl={{container.dcsHeaderLogo._smallLogoUrl}}
        @logoUrl={{container.dcsHeaderLogo._logoUrl}}
        @minimized={{@outletArgs.minimized}}
        @mobileLogoUrl={{container.dcsHeaderLogo._mobileLogoUrl}}
        @showMobileLogo={{@outletArgs.showMobileLogo}}
        @title={{@outletArgs.title}}
      />
    </template>);
    

    Note: to use the glimmer <template> syntax, make sure you rename the file extension to .gjs.
    You can also use this way:

     api.registerValueTransformer("home-logo-image-url", (transformer) => {
        let url = transformer.value;
        if (transformer.context.name === 'logo') {
          url = container.dcsHeaderLogo._logoUrl;
        } else if (transformer.context.name === 'logo_small') {
          url = container.dcsHeaderLogo._smallLogoUrl;
        } else if (transformer.context.name === 'logo_mobile') {
          url = container.dcsHeaderLogo._mobileLogoUrl;
        }
        return url;
      });
    

    To change the URL:

    api.registerValueTransformer("home-logo-href", () => container.dcsHeaderLogo._href);
    

    Note: I believe the code to re-render in setLogo won’t work on a glimmer component.

    Note after testing: However, neither solution will work because the header is rendered before you can get the logos from the JSON. I don’t have a ready solution for that. I’m not sure if there is a better way: I would move the JSON loading to a service and track the result. Then, use the plugin outlet above with a glimmer component. This way, based on a tracking variable, you can automatically trigger an update on the component.

With that, it kind of works somehow. There are still no working pieces like the composer. I did not look too deeply into this. At the very least, there is no more blocking error. :slightly_smiling_face:

I hope that helps.

3 Likes

That’s really helpful, thanks :slight_smile:

1 Like