Insertar la plantilla hbs en el outlet del plugin en la página - > user-preferences-interface a user-preferences-account

Hola, cuando quiero agregar a las preferencias del usuario-cuenta para que los usuarios puedan elegir si quieren modo oscuro o modo claro, intento agregarlo usando el código a continuación y ponerlo allí usando el “plugin outlet”, el problema es que no aparece para seleccionar, el código no es funcional. ¿Pueden aconsejarme cómo podría ponerlo allí? es muy importante para mí

bueno, gracias

{{#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}}

Quiero pegar este código aquí para que funcione correctamente

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

¿Alguien sabe cómo hacer este tipo de intervenciones?

Hola,

Sí, creo que eso no va a funcionar así. Sugiero leer la Developing Discourse Themes & Theme Components.

Si lo entiendo correctamente, quieres mover esta sección de la página de interfaz :arrow_down_small:

A la página de cuenta aquí :arrow_down_small:

1 me gusta

Sí, eso es exactamente lo que quiero hacer. ¿Podrías ayudarme con eso? Ya he leído el tema que sugeriste, pero no me ayudó en este caso particular.

¿Es posible mover TODAS las preferencias de usuario a una sola página? Supongo que funcionó así en versiones anteriores de Discourse.

Ya cubrí parte de por qué esto podría no funcionar aquí:

No puedes esperar que esto funcione sin considerar los controladores o el JS del componente.

Mover solo elementos de la plantilla de interfaz entre rutas es poco probable que funcione a menos que tengas en cuenta eso, es decir, la plantilla puede depender de:

  • Propiedades computadas
  • Acciones
  • Datos serializados
  • etc.
1 me gusta

Hola, soy parte del equipo de Juraj,

sí, ya nos enteramos de eso, también editando un plugin existente para incluir la preferencia de la interfaz de usuario. (incluyendo la plantilla hbs y el controlador js). Supongo que la única salida es crear una nueva página de preferencias de usuario donde incluyamos solo las preferencias que queremos mostrar. ¿Cómo importamos las funciones existentes para que funcionen con nuestra página de preferencias personalizada?

Un outlet de plugin debería estar bien siempre que pase el modelo requerido.

Dentro de ese outlet, necesitarás duplicar todos los elementos JS requeridos de la fuente.

Aquí tienes un ejemplo de JS configurando un Controller dentro de un outlet de plugin:

Puedes evitar esta forma bastante no estándar de definir un Controller haciendo todo dentro de un Component, por ejemplo, así:

1 me gusta

Gracias por tu respuesta. Sin embargo, en este momento estamos en esto:

<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 el código copiado de la plantilla interface.hbs. No puedo insertar ningún JS en el script de este componente. ¿Dónde pongo la función setupComponent?

Copia la estructura de archivos de los plugins enlazados (o si usas un Componente de Tema, puedes usar un Componente de Tema de ejemplo escrito con estándares actualizados).

No uses estas etiquetas de script, usa una estructura de archivo javascript adecuada, es más profesional (y posiblemente más fácil de mantener).

1 me gusta

Básicamente, creé un componente de tema con los siguientes archivos

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

Pegué el código hbs relevante en la plantilla y copié todo el código javascript del controlador de interfaz de preferencias de usuario. Estoy obteniendo el mismo resultado que al pegarlo directamente en una etiqueta . No creo que entienda a qué se refería con el ejemplo de JS configurando un controlador dentro de un plugin outlet.

Te sugiero que subas tu código a Github y lo compartas si es posible.

Supongo que esto es un error tipográfico, debería ser .js o .js.es6.

ten un poco de cuidado con tu terminología, es un Componente de Tema o un Plugin.

1 me gusta

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.

Lo primero que deberías mirar: ¿algún error en la consola?

Amigo, “copiar directamente” probablemente no funcionará en muchos casos. Necesitas entender lo que estás haciendo y hacerlo.

export default Controller.extend({

Este es un claro ejemplo. Probablemente no funcionará en este contexto en particular.

Como sugerí, por favor mira el código de ejemplo que compartí.

Esto se parece más a lo que necesitas:

export default {
  setupComponent(args, component) {

porque es un conector

1 me gusta

Gracias por tu ayuda. No veo ningún error en la consola y eso es lo primero que siempre reviso, ya que puedo ver lo que falta en el código allí.

Reemplacé el javascript con solo las dos funciones que enviaste, pero no sé qué tomar del ejemplo que proporcionaste. Como dije, no estoy seguro de qué implementar ya que no veo ningún error en la consola.