إدراج قالب hbs في منفذ المكون الإضافي في الواجهة -> تفضيلات المستخدم إلى حساب تفضيلات المستخدم

مرحباً، عندما أرغب في الإضافة إلى تفضيلات المستخدم-الحساب بحيث يمكن للمستخدمين الاختيار بين الوضع المظلم أو الوضع الفاتح، أحاول إضافته باستخدام الكود أدناه ووضعه هناك باستخدام منفذ المكون الإضافي، المشكلة هي أنه لا يظهر للاختيار، الكود غير فعال. هل يمكنك أن تنصحني بكيفية وضعه هناك؟ إنه مهم جداً بالنسبة لي

حسناً شكراً

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

أريد لصق هذا الكود هنا لكي يعمل بشكل صحيح


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

هل يعرف أحد كيف يمكن القيام بمثل هذه التدخلات؟

مرحباً،

نعم أعتقد أن هذا لن ينجح بهذه الطريقة. أقترح قراءة Developing Discourse Themes & Theme Components.

إذا فهمت بشكل صحيح، فأنت تريد نقل هذا القسم من صفحة الواجهة :arrow_down_small:

إلى صفحة الحساب هنا :arrow_down_small:

إعجاب واحد (1)

نعم، هذا بالضبط ما أريد فعله. هل يمكنك مساعدتي في ذلك؟ لقد قرأت بالفعل الموضوع الذي اقترحته ولكنه لم يساعدني في هذه الحالة المحددة

هل من الممكن نقل جميع تفضيلات المستخدم إلى صفحة واحدة؟ أعتقد أن الأمر كان يعمل بهذه الطريقة في الإصدارات السابقة من Discourse.

لقد غطيت بالفعل جزءًا من سبب عدم نجاح هذا هنا:

لا يمكنك توقع أن ينجح هذا دون مراعاة وحدات التحكم أو JavaScript المكون.

من غير المرجح أن تعمل العناصر الواجهة للقوالب بين المسارات إلا إذا أخذت ذلك في الاعتبار، أي قد يعتمد القالب على:

  • خصائص محسوبة
  • إجراءات
  • بيانات مسلسلة
  • إلخ
إعجاب واحد (1)

مرحباً، أنا جزء من فريق Juraj،
نعم، لقد اكتشفنا ذلك بالفعل - وذلك أيضاً عن طريق تعديل إضافة موجودة لتضمين تفضيل واجهة المستخدم. (بما في ذلك قالب hbs ووحدة تحكم js). أعتقد أن الحل الوحيد هو إنشاء صفحة تفضيلات مستخدم جديدة ندرج فيها فقط التفضيلات التي نريد عرضها. كيف يمكننا استيراد الوظائف الموجودة لتعمل مع صفحة التفضيلات المخصصة لدينا؟

يجب أن يكون منفذ الإضافة جيدًا طالما أنه يمرر النموذج المطلوب.

داخل هذا المنفذ، ستحتاج إلى تكرار جميع عناصر جافاسكريبت المطلوبة من المصدر.

إليك مثال على بعض جافاسكريبت التي تقوم بإعداد وحدة تحكم داخل منفذ إضافة:

يمكنك تجنب هذه الطريقة غير القياسية لتعريف وحدة تحكم عن طريق القيام بكل شيء داخل مكون، على سبيل المثال، هكذا:

إعجاب واحد (1)

شكرا لردك. ولكن في هذه المرحلة نحن عند هذا الحد:

<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>

هذا هو الكود المنسوخ من قالب interface.hbs. لا يمكنني إدراج أي JS في نص المكون هذا. أين أضع الدالة setupComponent؟

انسخ بنية الملف للمكونات الإضافية المرتبطة (أو إذا كنت تستخدم مكون سمة، يمكنك استخدام مكون سمة نموذجي مكتوب وفقًا للمعايير المحدثة).\n\nلا تستخدم علامات النص البرمجي هذه، استخدم بنية ملف جافاسكريبت مناسبة، فهي أكثر احترافية (ومن المحتمل أن تكون أسهل في الصيانة).

إعجاب واحد (1)

إذًا، لقد قمت بإنشاء مكون سمة بالملفات التالية:

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

لقد قمت بلصق كود hbs ذي الصلة في القالب ونسخت كود JavaScript بالكامل من وحدة تحكم واجهة تفضيلات المستخدم. أحصل على نفس النتيجة كما عند لصقها مباشرة في علامة <script>. لا أعتقد أنني أفهم ما كنت تقصده بالمثال JavaScript الذي يقوم بإعداد وحدة تحكم داخل منفذ إضافة.

أقترح عليك دفع الكود الخاص بك إلى Github ومشاركته إن أمكن.

أفترض أن هذا خطأ إملائي، يجب أن يكون إما .js أو .js.es6

كن حذرًا قليلاً مع مصطلحاتك، فهو إما مكون سمة (Theme Component) أو مكون إضافي (Plugin).

إعجاب واحد (1)

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.

أول شيء يجب أن تنظر إليه: هل هناك أي أخطاء في وحدة التحكم؟

يا صديقي، “النسخ المباشر” لن يعمل على الأرجح في الكثير من الحالات. تحتاج إلى فهم ما تفعله وفعله.

export default Controller.extend({

هذا هو بيت القصيد. هذا على الأرجح لن يعمل في هذا السياق المحدد.

كما اقترحت، يرجى إلقاء نظرة على الكود المثال الذي شاركته.

هذا أقرب إلى ما تحتاجه:

export default {
  setupComponent(args, component) {

لأنه موصل

إعجاب واحد (1)

شكراً لمساعدتك. لا أرى أي أخطاء في وحدة التحكم وهذا هو أول شيء أتحقق منه دائمًا حيث يمكنني رؤية ما هو مفقود في الكود هناك.

لقد استبدلت جافاسكريبت بالدالتين اللتين أرسلتهما فقط ولكنني لا أعرف ما الذي يجب أن آخذه من المثال الذي قدمته. كما ذكرت، لست متأكدًا مما يجب تنفيذه نظرًا لأنني لا أرى أي أخطاء في وحدة التحكم.