إضافة زر استطلاع في أسفل المحرر

@Steven كان لطيفًا بما يكفي للمساعدة وتمكّن من إعداد هذا السكربت الذي يعمل تقريبًا، لكن النقر على الزر لا يفعل شيئًا:

<script type='text/x-handlebars' data-template-name='composer'>
{{#composer-body composer=model
                 showPreview=showPreview
                 openIfDraft=(action "openIfDraft")
                 typed=(action "typed")
                 cancelled=(action "cancelled")
                 save=(action "save")}}
  <div class="grippie"></div>
  {{#if visible}}
      {{composer-messages composer=model
                          messageCount=messageCount
                          addLinkLookup=(action "addLinkLookup")}}
      {{#if model.viewOpenOrFullscreen}}
        <div class="reply-area {{if canEditTags 'with-tags'}}">
          <div class='composer-fields'>
            {{plugin-outlet name="composer-open" args=(hash model=model)}}
            <div class='reply-to'>
              {{#unless model.viewFullscreen}}
                <div class="reply-details">
                  {{composer-action-title
                    model=model
                    openComposer=(action "openComposer")
                    closeComposer=(action "closeComposer")
                    canWhisper=canWhisper
                    tabindex=8}}
                  {{plugin-outlet name="composer-action-after" noTags=true args=(hash model=model)}}

                  {{#unless site.mobileView}}
                    {{#if isWhispering}}
                      <span class='whisper'>{{d-icon "far-eye-slash"}}</span>
                    {{/if}}
                    {{#if model.unlistTopic}}
                      <span class='whisper'>({{i18n 'composer.unlist'}})</span>
                    {{/if}}
                    {{#if model.noBump}}
                      <span class="no-bump">{{d-icon "anchor"}}</span>
                    {{/if}}
                  {{/unless}}

                  {{#if canEdit}}
                    {{#link-to-input onClick=(action "displayEditReason") showInput=showEditReason icon="info-circle" class="display-edit-reason"}}
                      {{text-field value=editReason tabindex="7" id="edit-reason" maxlength="255" placeholderKey="composer.edit_reason_placeholder"}}
                    {{/link-to-input}}
                  {{/if}}
                </div>
              {{/unless}}
              {{composer-toggles composeState=model.composeState
                        toggleComposer=(action "toggle")
                        toggleToolbar=(action "toggleToolbar")
                        toggleFullscreen=(action "fullscreenComposer")}}
            </div>
            {{#unless model.viewFullscreen}}
              {{#if model.canEditTitle}}
                {{#if model.creatingPrivateMessage}}
                  <div class='user-selector'>
                    {{composer-user-selector topicId=topicModel.id
                                             usernames=model.targetRecipients
                                             hasGroups=model.hasTargetGroups
                                             focusTarget=focusTarget
                                             class="users-input"}}
                    {{#if showWarning}}
                      <label class='add-warning'>
                        {{input type="checkbox" checked=model.isWarning tabindex="3"}}
                        {{i18n "composer.add_warning"}}
                      </label>
                    {{/if}}
                  </div>
                {{/if}}

                <div class="title-and-category {{if showPreview 'with-preview'}}">

                  {{composer-title composer=model lastValidatedAt=lastValidatedAt focusTarget=focusTarget}}

                  {{#if model.showCategoryChooser}}
                    <div class="category-input">
                      {{category-chooser
                        value=model.categoryId
                        tabindex="3"
                        onChange=(action (mut model.categoryId))
                        isDisabled=disableCategoryChooser
                        options=(hash
                          scopedCategoryId=scopedCategoryId
                        )
                      }}
                      {{popup-input-tip validation=categoryValidation}}
                    </div>
                  {{/if}}
                  {{#if canEditTags}}
                    {{mini-tag-chooser
                      value=model.tags
                      tabindex=4
                      isDisabled=disableTagsChooser
                      onChange=(action (mut model.tags))
                      options=(hash
                        categoryId=model.categoryId
                        minimum=model.minimumRequiredTags
                      )
                    }}
                    {{popup-input-tip validation=tagValidation}}
                  {{/if}}
                </div>
              {{/if}}

              {{plugin-outlet name="composer-fields" args=(hash model=model)}}
            {{/unless}}

          </div>

          {{composer-editor topic=topic
                            composer=model
                            lastValidatedAt=lastValidatedAt
                            canWhisper=canWhisper
                            storeToolbarState=(action "storeToolbarState")
                            onPopupMenuAction=(action "onPopupMenuAction")
                            showUploadModal=(route-action "showUploadSelector")
                            popupMenuOptions=popupMenuOptions
                            draftStatus=model.draftStatus
                            isUploading=isUploading
                            allowUpload=allowUpload
                            uploadIcon=uploadIcon
                            isCancellable=isCancellable
                            uploadProgress=uploadProgress
                            groupsMentioned=(action "groupsMentioned")
                            cannotSeeMention=(action "cannotSeeMention")
                            importQuote=(action "importQuote")
                            togglePreview=(action "togglePreview")
                            showToolbar=showToolbar
                            afterRefresh=(action "afterRefresh")
                            focusTarget=focusTarget}}

          <div class='submit-panel'>
            {{plugin-outlet name="composer-fields-below" args=(hash model=model)}}

            <div class='save-or-cancel'>
              {{#unless model.viewFullscreen}}
                {{composer-save-button action=(action "save")
                                       icon=saveIcon
                                       label=saveLabel
                                       disableSubmit=disableSubmit}}

              {{#if site.mobileView}}
                <a href {{action "cancel"}} class='cancel' tabindex="6" title="{{i18n 'cancel'}}">
                  {{#if canEdit}}
                    {{d-icon "times"}}
                  {{else}}
                    {{d-icon "far-trash-alt"}}
                  {{/if}}
                </a>
              {{else}}
                <a href {{action "cancel"}} class='cancel' tabindex="6" >{{i18n 'cancel'}}</a>
              {{/if}}
            {{/unless}}


              {{#if site.mobileView}}
                {{#if whisperOrUnlistTopic}}
                  <span class='whisper'>
                    {{d-icon "far-eye-slash"}}
                  </span>
                {{/if}}
                {{#if model.noBump}}
                  <span class="no-bump">{{d-icon "anchor"}}</span>
                {{/if}}
              {{/if}}


              {{#if isUploading}}
                <div id="file-uploading">
                  {{loading-spinner size="small"}}<span>{{i18n 'upload_selector.uploading'}} {{uploadProgress}}%</span>
                  {{#if isCancellable}}
                    <a href id="cancel-file-upload" {{action "cancelUpload"}}>{{d-icon "times"}}</a>
                  {{/if}}
                </div>
              {{/if}}
              <div id='draft-status' class="{{if isUploading 'hidden'}}">
                {{#if model.draftSaving}}<div class="spinner small"></div>{{/if}}
                {{#if model.draftSaved}}{{d-icon 'check' class='save-animation'}}{{/if}}
                {{#if model.draftStatus}}
                  <span title="{{model.draftStatus}}">
                    {{#if model.draftConflictUser}}
                      {{avatar model.draftConflictUser imageSize="small"}} {{d-icon 'user-edit'}}
                    {{else}}
                      {{d-icon 'sync-alt'}}
                    {{/if}}
                    {{#unless site.mobileView}}
                      {{model.draftStatus}}
                    {{/unless}}
                  </span>
                {{/if}}
              </div>
            </div>

              {{#if site.mobileView}}
                {{#if allowUpload}}
                  <a class="btn btn-default no-text mobile-file-upload {{if isUploading 'hidden'}}">
                    {{d-icon uploadIcon}}
                  </a>
                {{/if}}

                <a href class="btn btn-default no-text mobile-preview" {{action "showPollBuilder"}}>
                  {{d-icon "chart-bar"}}
                </a>
                
                <a href class="btn btn-default no-text mobile-preview" title="{{i18n 'composer.show_preview'}}" {{action "togglePreview"}}>
                  {{d-icon "desktop"}}
                </a>

                {{#if showPreview}}
                  {{d-button action=(action "togglePreview") class="hide-preview" label="composer.hide_preview"}}
                {{/if}}
              {{else}}
                <a href {{action "togglePreview"}} class='toggle-preview'>{{{toggleText}}}</a>
              {{/if}}

          </div>
        </div>

      {{else}}
        <div class='saving-text'>
          {{#if model.createdPost}}
            {{i18n 'composer.saved'}} <a class='permalink' href="{{unbound createdPost.url}}" {{action "viewNewReply"}}>{{i18n 'composer.view_new_post'}}</a>
          {{else}}
            {{i18n 'composer.saving'}} {{loading-spinner size="small"}}
          {{/if}}
        </div>

        <div class='draft-text'>
          {{#if model.topic}}
            {{d-icon "share"}} {{{draftTitle}}}
          {{else}}
            {{i18n "composer.saved_draft"}}
          {{/if}}
        </div>

        {{composer-toggles composeState=model.composeState
          toggleFullscreen=(action "openIfDraft")
          toggleComposer=(action "toggle")
          toggleToolbar=(action "toggleToolbar")}}

      {{/if}}

  {{/if}}

{{/composer-body}}
</script>

كانت استنتاجاته المحتملة كالتالي: «إنه يعمل فقط إذا استخدمنا زر الاستبيان في المكوّن أولًا. أعتقد أن السبب هو أن Discourse ستقوم بتشغيل الإجراء showPollBuilder (وهو ما يفتح منشئ الاستبيانات) فقط بعد تشغيل الإجراء onPopupMenuAction (الأيقونة التي تفتح قائمة الإجراءات في شريط الأدوات، مثل إخفاء التفاصيل، أو ضبابية الإSpoiler، أو إنشاء استبيان).»

هل يمانع أحد من تولي الأمر؟ :slight_smile:
(شكرًا مجددًا لـ Steven على المساعدة السخية جدًا!)

على الأرجح لا تحتاج إلى تجاوز قالب composer بالكامل. استخدم منفذ composer-fields-below بدلاً من ذلك.

لم أستطع مقاومتي ونظرت في عمق الموضوع قليلاً. ههه، والآن مرت ساعتان بالفعل.


يجب عليك إضافة ملف Handlebars بهذه الطريقة لعرض الزر.


ثم تحتاج إلى إجراء مشابه لذلك الموجود في إضافة الاستطلاع:

يمكننا تزويد نافذة بناء الاستطلاع بـ “حدث شريط أدوات” وهمي، لكن المشكلة هي أنك تحتاج أيضًا إلى تكرار المنطق في مكون المحرر.

الجزء المتعلق بـ _getSelected و _addText. سأكون مهتمًا جدًا بمعرفة ما إذا كانت هناك أي واجهة برمجة تطبيقات (API) تسمح بإضافة نص برمجيًا إلى منطقة النص في المحرر من “الخارج”.

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

لكنني أردت جعل الكود يعمل أولاً، ثم التعديل لاحقاً، لكنني علقت في مرحلة البرمجة.

لا، حسب علمي (AFAIK) ليس لدينا أي شيء للقيام بذلك في الوقت الحالي (ATM).

أوه، حسنًا، فهمت. عمل رائع! :slight_smile:

هذا في الواقع أكثر تعقيدًا مما يبدو (فكم من الصعوبة يمكن أن يكون نقل زر لليمين؟ :slight_smile: )

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

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

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

أي:

api.modifyClass("component:d-editor", {
  @on('didInsertElement')
  makeToolbarAccessible() {
    if (this.outletArgs && this.outletArgs.editorType === 'composer') {
      const controller = getOwner(this).lookup('controller:composer');
      controller.set('editorToolbar', this.toolbar);
    }
  }
});

ثم في المخرج، نحصل على شريط الأدوات من وحدة تحكم المؤلف ونضيف زرًا جديدًا إليه. قد يكون هناك طريقة لاستخدام زر الاستبيان الموجود (وهو الأمر المثالي)، لكنه مغلف داخل منطق القائمة المنبثقة، ولم أستطع رؤية طريقة لفكه.

setupComponent(attrs, ctx) {
  const controller = getOwner(this).lookup('controller:composer');
  
  controller.addObserver('editorToolbar', function() {
    if (this._state === 'destroying') return;

    const toolbar = controller.editorToolbar;
          
    toolbar.addButton({
      group: "extras",
      icon: "chart-bar",
      title: "poll.ui_builder.title",
      sendAction: e => {
        controller.send('storeToolbarState', e);
        this.send("showPollBuilder");
      }
    });
    
    const extras = toolbar.groups.find(g => g.group == 'extras');
    const pollButton = extras.buttons.find(b => b.icon == "chart-bar");
        
    ctx.set('pb', pollButton);
  });
}

ثم في القالب نفسه

{{d-button
  type="button"
  action=pb.action
  actionParam=pb
  translatedTitle=pb.title
  icon=pb.icon
  class=pb.className}}

@nexo جرب هذا المكون الخاص بالقالب: discourse-poll-button-bottom.zip (2.5 KB)

ملاحظة: لقد قمت بتحميله للتو على thepavilion.io ويبدو أنه يعمل (على الهواتف المحمولة فقط).

واو، يبدو ذلك حلاً رائعًا! مشروعي ممل جدًا مقارنةً به:

export default {
  actions: {
    showPollBuilderNextToSave() {
$("button[title='Options']").trigger('click')



console.log($("button[title='Options']"))
Ember.run.later((function() {
  $("li[data-value='showPollBuilder']").trigger('click');
    console.log($("li[data-value='showPollBuilder']"))
 
}), 50);

    }
  }
};

أنا أستخدم jQuery فقط للنقر على الزر :smiley: ربما توجد طريقة أفضل لإيجاد المحدد الأول دون ترميز عنوان “Options” بشكل ثابت، في حال كان ذلك يمثل مشكلة.

أجل، عمل رائع :+1: خيار آخر أيضًا.

واو، لقد صمتت يا أنغوس.. هذا مذهل، أنت عبقري يا بني! لقد ألهمتني للبدء في تعلم التطوير ابتداءً من اليوم، تمامًا كما ألهمني يوهاني لتعلم CSS قبل عام. شكرًا لك يا أنغوس، رائع جدًا. :trophy: