Fügen Sie die hbs-Vorlage in den Plugin-Outlet auf der Seite ein -> user-preferences-interface zu user-preferences-account

Hallo, wenn ich zu user-preferences-account hinzufügen möchte, damit Benutzer wählen können, ob sie den Dunkel- oder Hellmodus wünschen, versuche ich, ihn mit dem folgenden Code hinzuzufügen und ihn dort über den Plugin-Outlet einzufügen. Das Problem ist, dass er nicht zur Auswahl angezeigt wird und der Code nicht funktioniert. Können Sie mir raten, wie ich ihn dort einfügen könnte? Das ist für mich sehr wichtig.

Vielen Dank

{{#if showColorSchemeSelector}}
  <fieldset class="control-group color-scheme">
    <legend class="control-label">{{i18n "user.color_scheme"}}</legend>
    <div class="control-subgroup light-color-scheme">
      {{#if showDarkColorSchemeSelector}}
        <div class="instructions">{{i18n "user.color_schemes.regular" }}</div>
      {{/if}}
      <div class="controls">
        {{combo-box
          content=userSelectableColorSchemes
          value=selectedColorSchemeId
          onChange=(action "loadColorScheme")
          options=(hash
            translatedNone=selectedColorSchemeNoneLabel
            autoInsertNoneItem=showColorSchemeNoneItem
          )
        }}
      </div>
    </div>
    {{#if showDarkColorSchemeSelector}}
      <div class="control-subgroup dark-color-scheme">
        <div class="instructions">{{i18n "user.color_schemes.dark" }}</div>
        <div class="controls">
          {{combo-box
            content=userSelectableDarkColorSchemes
            value=selectedDarkColorSchemeId
            onChange=(action "loadDarkColorScheme")}}
        </div>
      </div>

      <div class="instructions">
        {{i18n "user.color_schemes.dark_instructions" }}
      </div>
    {{/if}}

    {{#if previewingColorScheme}}
      {{#if previewingColorScheme}}
        {{d-button action=(action "undoColorSchemePreview") label="user.color_schemes.undo" icon="undo" class="btn-default btn-small undo-preview"}}
      {{/if}}

      <div class="controls color-scheme-checkbox">
        {{preference-checkbox labelKey="user.color_scheme_default_on_all_devices" checked=makeColorSchemeDefault}}
      </div>
    {{/if}}
  </fieldset>
{{/if}}

Ich möchte diesen Code hier einfügen, damit er richtig funktioniert

<script type="text/x-handlebars" data-template-name="/connectors/user-preferences-account/terajsok-custom-user-preferences"></script>

Weiß jemand, wie man solche Eingriffe durchführt?

Hallo,

Ich glaube nicht, dass das so funktionieren wird. Ich schlage vor, das Developing Discourse Themes & Theme Components zu lesen.

Wenn ich es richtig verstehe, möchten Sie diesen Abschnitt von der Benutzeroberfläche :pfeil_nach_unten:

Zur Kontoseite hier verschieben: :pfeil_nach_unten:

1 „Gefällt mir“

Ja, das ist genau das, was ich tun möchte. Könnten Sie mir dabei helfen? Ich habe das von Ihnen vorgeschlagene Thema bereits gelesen, aber es hat mir in diesem speziellen Fall nicht geholfen.

Ist es möglich, ALLE Benutzereinstellungen auf eine einzige Seite zu verschieben? Ich glaube, so hat es in früheren Versionen von Discourse funktioniert.

Ich habe hier bereits teilweise abgedeckt, warum das möglicherweise nicht funktioniert:

Sie können nicht erwarten, dass dies ohne Berücksichtigung der Controller oder der Component JS funktioniert.

Das Verschieben von nur Interface-Template-Elementen zwischen Routen wird wahrscheinlich nicht funktionieren, es sei denn, Sie berücksichtigen dies, d. h. das Template kann sich stützen auf:

  • berechnete Eigenschaften
  • Aktionen
  • serialisierte Daten
  • usw.
1 „Gefällt mir“

Hallo, ich bin Teil von Jurajs Team,

ja, das haben wir bereits herausgefunden – auch indem wir ein bestehendes Plugin bearbeitet haben, um die Benutzeroberflächenpräferenz einzubinden. (einschließlich des HBS-Templates und des JS-Controllers). Ich schätze, der einzige Ausweg ist, eine neue Seite für Benutzereinstellungen zu erstellen, auf der wir nur die Einstellungen einfügen, die wir anzeigen möchten. Wie importieren wir bestehende Funktionen, damit sie mit unserer benutzerdefinierten Einstellungsseite funktionieren?

Eine Plugin-Outlet sollte in Ordnung sein, solange sie das erforderliche Modell übergibt.

Innerhalb dieses Outlets müssen Sie alle erforderlichen JS-Elemente aus der Quelle duplizieren.

Hier ist ein Beispiel für JS, das einen Controller innerhalb eines Plugin-Outlets einrichtet:

Sie können diesen eher nicht standardmäßigen Weg zur Definition eines Controllers vermeiden, indem Sie alles innerhalb einer Komponente tun, z. B. so:

1 „Gefällt mir“

Vielen Dank für Ihre Antwort. An diesem Punkt sind wir jedoch hier:

<script type="text/x-handlebars" data-template-name="/connectors/user-preferences-account/tg-custom-prefs">

<fieldset class="control-group color-scheme">
    <legend class="control-label">{{i18n "user.color_scheme"}}</legend>
    <div class="control-subgroup light-color-scheme">
      <div class="controls">
        <ComboBox @content={{this.userSelectableColorSchemes}} @value={{this.selectedColorSchemeId}} @onChange={{action "loadColorScheme"}} @options={{hash
            translatedNone=this.selectedColorSchemeNoneLabel
            autoInsertNoneItem=this.showColorSchemeNoneItem
          }} />
      </div>
    </div>
</fieldset>
</script>

Es ist der Code, der aus der Vorlage interface.hbs kopiert wurde. Ich kann kein JS in dieses Komponentenskript einfügen. Wo platziere ich die setupComponent-Funktion?

Kopieren Sie die Dateistruktur der verknüpften Plugins (oder wenn Sie eine Theme-Komponente verwenden, können Sie eine Beispiel-Theme-Komponente verwenden, die nach aktuellen Standards geschrieben ist).

Verwenden Sie nicht diese Skript-Tags, sondern eine ordnungsgemäße JavaScript-Dateistruktur. Das ist professioneller (und wohl auch einfacher zu warten).

1 „Gefällt mir“

Im Grunde habe ich eine Theme-Komponente mit den folgenden Dateien erstellt

/about.json
/javascripts/discourse/connectors/user-preferences-account/component-test.hbs
/javascripts/discourse/connectors/user-preferences-account/component-test.js.es6

Ich habe den relevanten HBS-Code in die Vorlage eingefügt und den gesamten JavaScript-Code vom Controller für Benutzeroberflächeneinstellungen kopiert. Ich erhalte das gleiche Ergebnis wie beim direkten Einfügen in ein <script>-Tag. Ich glaube nicht, dass ich verstanden habe, was Sie mit dem Beispiel-JS meinten, das einen Controller innerhalb eines Plugin-Outlets einrichtet.

Ich schlage vor, Sie pushen Ihren Code auf Github und teilen ihn, wenn möglich.

Ich gehe davon aus, dass dies ein Tippfehler ist und entweder .js oder .js.es6 lauten sollte.

Seien Sie ein wenig vorsichtig mit Ihrer Terminologie, es ist entweder eine Theme-Komponente oder ein Plugin.

1 „Gefällt mir“

Sorry, yes I meant js.es6. Yes it’s a theme component.

I don’t have the theme component uploaded on github.

/about.json:

{
  "name": "Component Test",
  "component": true,
  "license_url": null,
  "about_url": null,
  "authors": null,
  "theme_version": null,
  "minimum_discourse_version": null,
  "maximum_discourse_version": null,
  "assets": {
  },
  "color_schemes": {
  },
  "modifiers": {
  },
  "learn_more": "https://meta.discourse.org/t/beginners-guide-to-using-discourse-themes/91966"
}

/javascripts/discourse/connectors/user-preferences-account/component-test.hbs

<fieldset class="control-group color-scheme">
    <legend class="control-label">{{i18n "user.color_scheme"}}</legend>
    <div class="control-subgroup light-color-scheme">
      <div class="controls">
        <ComboBox @content={{this.userSelectableColorSchemes}} @value={{this.selectedColorSchemeId}} @onChange={{action "loadColorScheme"}} @options={{hash
            translatedNone=this.selectedColorSchemeNoneLabel
            autoInsertNoneItem=this.showColorSchemeNoneItem
          }} />
      </div>
    </div>
</fieldset>

/javascripts/discourse/connectors/user-preferences-account/component-test.js.es6

import Controller, { inject as controller } from "@ember/controller";
import Session from "discourse/models/session";
import { setDefaultHomepage } from "discourse/lib/utilities";
import {
  listColorSchemes,
  loadColorSchemeStylesheet,
  updateColorSchemeCookie,
} from "discourse/lib/color-scheme-picker";
import { listThemes, setLocalTheme } from "discourse/lib/theme-selector";
import { not, reads } from "@ember/object/computed";
import I18n from "I18n";
import { computed } from "@ember/object";
import discourseComputed from "discourse-common/utils/decorators";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { reload } from "discourse/helpers/page-reloader";
import { propertyEqual } from "discourse/lib/computed";

const USER_HOMES = {
  1: "latest",
  2: "categories",
  3: "unread",
  4: "new",
  5: "top",
  6: "bookmarks",
  7: "unseen",
};

const TEXT_SIZES = ["smallest", "smaller", "normal", "larger", "largest"];
const TITLE_COUNT_MODES = ["notifications", "contextual"];

export default Controller.extend({
  currentThemeId: -1,
  previewingColorScheme: false,
  selectedDarkColorSchemeId: null,
  preferencesController: controller("preferences"),
  makeColorSchemeDefault: true,
  canPreviewColorScheme: propertyEqual("model.id", "currentUser.id"),

  init() {
    this._super(...arguments);

    this.set("selectedDarkColorSchemeId", this.session.userDarkSchemeId);
  },

  @discourseComputed("makeThemeDefault")
  saveAttrNames(makeThemeDefault) {
    let attrs = [
      "locale",
      "external_links_in_new_tab",
      "dynamic_favicon",
      "enable_quoting",
      "enable_defer",
      "automatically_unpin_topics",
      "allow_private_messages",
      "enable_allowed_pm_users",
      "homepage_id",
      "hide_profile_and_presence",
      "text_size",
      "title_count_mode",
      "skip_new_user_tips",
      "color_scheme_id",
      "dark_scheme_id",
    ];

    if (makeThemeDefault) {
      attrs.push("theme_ids");
    }

    return attrs;
  },

  @discourseComputed()
  availableLocales() {
    return JSON.parse(this.siteSettings.available_locales);
  },

  @discourseComputed
  defaultDarkSchemeId() {
    return this.siteSettings.default_dark_mode_color_scheme_id;
  },

  @discourseComputed
  textSizes() {
    return TEXT_SIZES.map((value) => {
      return { name: I18n.t(`user.text_size.${value}`), value };
    });
  },

  homepageId: computed(
    "model.user_option.homepage_id",
    "userSelectableHome.[]",
    function () {
      return (
        this.model.user_option.homepage_id ||
        this.userSelectableHome.firstObject.value
      );
    }
  ),

  @discourseComputed
  titleCountModes() {
    return TITLE_COUNT_MODES.map((value) => {
      return { name: I18n.t(`user.title_count_mode.${value}`), value };
    });
  },

  @discourseComputed
  userSelectableThemes() {
    return listThemes(this.site);
  },

  @discourseComputed("userSelectableThemes")
  showThemeSelector(themes) {
    return themes && themes.length > 1;
  },

  @discourseComputed("themeId")
  themeIdChanged(themeId) {
    if (this.currentThemeId === -1) {
      this.set("currentThemeId", themeId);
      return false;
    } else {
      return this.currentThemeId !== themeId;
    }
  },

  @discourseComputed
  userSelectableColorSchemes() {
    return listColorSchemes(this.site);
  },

  showColorSchemeSelector: reads("userSelectableColorSchemes.length"),
  selectedColorSchemeNoneLabel: I18n.t(
    "user.color_schemes.default_description"
  ),

  @discourseComputed(
    "userSelectableThemes",
    "userSelectableColorSchemes",
    "themeId"
  )
  currentSchemeCanBeSelected(userThemes, userColorSchemes, themeId) {
    if (!userThemes || !themeId) {
      return false;
    }

    const theme = userThemes.findBy("id", themeId);
    if (!theme) {
      return false;
    }

    return userColorSchemes.findBy("id", theme.color_scheme_id);
  },

  showColorSchemeNoneItem: not("currentSchemeCanBeSelected"),

  @discourseComputed("model.user_option.theme_ids", "themeId")
  showThemeSetDefault(userOptionThemes, selectedTheme) {
    return !userOptionThemes || userOptionThemes[0] !== selectedTheme;
  },

  @discourseComputed("model.user_option.text_size", "textSize")
  showTextSetDefault(userOptionTextSize, selectedTextSize) {
    return userOptionTextSize !== selectedTextSize;
  },

  homeChanged() {
    const siteHome = this.siteSettings.top_menu.split("|")[0].split(",")[0];
    const userHome = USER_HOMES[this.get("model.user_option.homepage_id")];

    setDefaultHomepage(userHome || siteHome);
  },

  @discourseComputed()
  userSelectableHome() {
    let homeValues = {};
    Object.keys(USER_HOMES).forEach((newValue) => {
      const newKey = USER_HOMES[newValue];
      homeValues[newKey] = newValue;
    });

    let result = [];
    this.siteSettings.top_menu.split("|").forEach((m) => {
      let id = homeValues[m];
      if (id) {
        result.push({ name: I18n.t(`filters.${m}.title`), value: Number(id) });
      }
    });
    return result;
  },

  @discourseComputed
  showDarkModeToggle() {
    return this.defaultDarkSchemeId > 0 && !this.showDarkColorSchemeSelector;
  },

  @discourseComputed
  userSelectableDarkColorSchemes() {
    return listColorSchemes(this.site, {
      darkOnly: true,
    });
  },

  @discourseComputed("userSelectableDarkColorSchemes")
  showDarkColorSchemeSelector(darkSchemes) {
    // when a default dark scheme is set
    // dropdown has two items (disable / use site default)
    // but we show a checkbox in that case
    const minToShow = this.defaultDarkSchemeId > 0 ? 2 : 1;
    return darkSchemes && darkSchemes.length > minToShow;
  },

  enableDarkMode: computed({
    set(key, value) {
      return value;
    },
    get() {
      return this.get("model.user_option.dark_scheme_id") === -1 ? false : true;
    },
  }),

  selectedColorSchemeId: computed({
    set(key, value) {
      return value;
    },
    get() {
      if (!this.session.userColorSchemeId) {
        return;
      }

      const theme = this.userSelectableThemes?.findBy("id", this.themeId);

      // we don't want to display the numeric ID of a scheme
      // when it is set by the theme but not marked as user selectable
      if (
        theme?.color_scheme_id === this.session.userColorSchemeId &&
        !this.userSelectableColorSchemes.findBy(
          "id",
          this.session.userColorSchemeId
        )
      ) {
        return;
      } else {
        return this.session.userColorSchemeId;
      }
    },
  }),

  actions: {
    save() {
      this.set("saved", false);
      const makeThemeDefault = this.makeThemeDefault;
      if (makeThemeDefault) {
        this.set("model.user_option.theme_ids", [this.themeId]);
      }

      const makeTextSizeDefault = this.makeTextSizeDefault;
      if (makeTextSizeDefault) {
        this.set("model.user_option.text_size", this.textSize);
      }

      if (!this.showColorSchemeSelector) {
        this.set("model.user_option.color_scheme_id", null);
      } else if (this.makeColorSchemeDefault) {
        this.set(
          "model.user_option.color_scheme_id",
          this.selectedColorSchemeId
        );
      }

      if (this.showDarkModeToggle) {
        this.set(
          "model.user_option.dark_scheme_id",
          this.enableDarkMode ? null : -1
        );
      } else {
        // if chosen dark scheme matches site dark scheme, no need to store
        if (
          this.defaultDarkSchemeId > 0 &&
          this.selectedDarkColorSchemeId === this.defaultDarkSchemeId
        ) {
          this.set("model.user_option.dark_scheme_id", null);
        } else {
          this.set(
            "model.user_option.dark_scheme_id",
            this.selectedDarkColorSchemeId
          );
        }
      }

      return this.model
        .save(this.saveAttrNames)
        .then(() => {
          this.set("saved", true);

          if (makeThemeDefault) {
            setLocalTheme([]);
          } else {
            setLocalTheme(
              [this.themeId],
              this.get("model.user_option.theme_key_seq")
            );
          }
          if (makeTextSizeDefault) {
            this.model.updateTextSizeCookie(null);
          } else {
            this.model.updateTextSizeCookie(this.textSize);
          }

          if (this.makeColorSchemeDefault) {
            updateColorSchemeCookie(null);
            updateColorSchemeCookie(null, { dark: true });
          } else {
            updateColorSchemeCookie(this.selectedColorSchemeId);

            if (
              this.defaultDarkSchemeId > 0 &&
              this.selectedDarkColorSchemeId === this.defaultDarkSchemeId
            ) {
              updateColorSchemeCookie(null, { dark: true });
            } else {
              updateColorSchemeCookie(this.selectedDarkColorSchemeId, {
                dark: true,
              });
            }
          }

          this.homeChanged();

          if (this.themeId !== this.currentThemeId) {
            reload();
          }
        })
        .catch(popupAjaxError);
    },

    selectTextSize(newSize) {
      const classList = document.documentElement.classList;

      TEXT_SIZES.forEach((name) => {
        const className = `text-size-${name}`;
        if (newSize === name) {
          classList.add(className);
        } else {
          classList.remove(className);
        }
      });

      // Force refresh when leaving this screen
      this.session.requiresRefresh = true;
      this.set("textSize", newSize);
    },

    loadColorScheme(colorSchemeId) {
      this.setProperties({
        selectedColorSchemeId: colorSchemeId,
        previewingColorScheme: this.canPreviewColorScheme,
      });

      if (!this.canPreviewColorScheme) {
        return;
      }

      if (colorSchemeId < 0) {
        const defaultTheme = this.userSelectableThemes.findBy(
          "id",
          this.themeId
        );

        if (defaultTheme && defaultTheme.color_scheme_id) {
          colorSchemeId = defaultTheme.color_scheme_id;
        }
      }
      loadColorSchemeStylesheet(colorSchemeId, this.themeId);
      if (this.selectedDarkColorSchemeId === -1) {
        // set this same scheme for dark mode preview when dark scheme is disabled
        loadColorSchemeStylesheet(colorSchemeId, this.themeId, true);
      }
    },

    loadDarkColorScheme(colorSchemeId) {
      this.setProperties({
        selectedDarkColorSchemeId: colorSchemeId,
        previewingColorScheme: this.canPreviewColorScheme,
      });

      if (!this.canPreviewColorScheme) {
        return;
      }

      if (colorSchemeId === -1) {
        // load preview of regular scheme when dark scheme is disabled
        loadColorSchemeStylesheet(
          this.selectedColorSchemeId,
          this.themeId,
          true
        );
        Session.currentProp("darkModeAvailable", false);
      } else {
        loadColorSchemeStylesheet(colorSchemeId, this.themeId, true);
        Session.currentProp("darkModeAvailable", true);
      }
    },

    undoColorSchemePreview() {
      this.setProperties({
        selectedColorSchemeId: this.session.userColorSchemeId,
        selectedDarkColorSchemeId: this.session.userDarkSchemeId,
        previewingColorScheme: false,
      });
      const darkStylesheet = document.querySelector("link#cs-preview-dark"),
        lightStylesheet = document.querySelector("link#cs-preview-light");
      if (darkStylesheet) {
        darkStylesheet.remove();
      }

      if (lightStylesheet) {
        lightStylesheet.remove();
      }
    },
  },
});

This is all I have, directly copied from the original files.

Das Erste, was Sie sich ansehen sollten: Gibt es Fehler in der Konsole?

Mein Freund, „direkt kopieren“ wird wahrscheinlich in vielen Fällen nicht funktionieren. Sie müssen verstehen, was Sie tun, und es dann tun.

export default Controller.extend({

Dies ist ein Paradebeispiel. Das wird in diesem speziellen Kontext wahrscheinlich nicht funktionieren.

Wie ich bereits vorgeschlagen habe, schauen Sie sich bitte den Beispielcode an, den ich geteilt habe.

Das ist eher das, was Sie brauchen:

export default {
  setupComponent(args, component) {

weil es ein Connector ist

1 „Gefällt mir“

Vielen Dank für Ihre Hilfe. Nein, ich sehe keine Fehler in der Konsole und das ist das Erste, was ich immer überprüfe, da ich dort sehen kann, was im Code fehlt.

Ich habe das JavaScript durch die beiden von Ihnen gesendeten Funktionen ersetzt, aber ich weiß nicht, was ich aus dem von Ihnen bereitgestellten Beispiel übernehmen soll. Wie gesagt, ich bin mir nicht sicher, was ich implementieren soll, da ich keine Fehler in der Konsole sehe.