לדלג לתוכן

משתמש:מוטי בוט/codex-hello-world.js

מתוך המכלול, האנציקלופדיה היהודית

לתשומת ליבך: לאחר הפרסום, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.

  • פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload) או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
  • גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
  • אדג': להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh) או ללחוץ על צירוף המקשים Ctrl-F5.
//<nowiki>
(function () {
  var style = document.createElement("style");
  style.innerHTML = `
#jwb-app-layout {
  display: flex;
  flex-direction: row;
  min-height: 98vh;
  box-sizing: border-box;
  position: relative;
  padding-bottom: 60px;
}
#jwb-main-area {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  min-width: 0;
}
#jwb-preview {
  flex: 0 0 auto;
  background: #fff;
  border-bottom: 1px solid #ddd;
  padding: 1em 2em 0.5em 2em;
}
#jwb-center-area {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 0;
}
#jwb-tabs-area {
  flex: 0 0 auto;
  min-height: 200px;
  max-height: none;
  overflow-y: visible;
  background: #f8f8f8;
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
  padding: 1em 2em;
  display: grid;
}
#jwb-tabs-area .cdx-tabs__tab-content {
  grid-area: 1 / 1 / 2 / 2;
}
#jwb-tabs-area .cdx-tabs__tab-content {
  min-height: 0;
}
#jwb-tabs-area .cdx-tabs__tab-content {
  /* כל הטאבים יתפסו את אותו שטח, הגבוהה ביותר תקבע */
  position: relative;
}
#jwb-edit-area {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 0;
}
#jwb-edit {
  flex: 0 0 auto;
  padding: 1em 2em;
  background: #fafaff;
  border-top: 1px solid #eee;
  height: 320px;
  max-height: 40vh;
  min-height: 200px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
#jwb-edit .cdx-text-area {
  flex: 1 1 auto;
  min-height: 0;
  height: 100%;
  max-height: 100%;
}
#jwb-controls {
  display: flex;
  gap: 0.5em;
  align-items: center;
  padding: 0.5em 2em;
  background: #f4f4f4;
  border-bottom: 1px solid #eee;
}
.jwb-controls-top {
  border-bottom: none;
  background: transparent;
  padding-bottom: 0;
}
.jwb-controls-bottom {
  border-bottom: 1px solid #eee;
  background: #f4f4f4;
  padding-bottom: 0.5em;
}
#jwb-pageslist-sidebar {
  flex: 0 0 320px;
  background: #f8f8f8;
  border-left: 2px solid #ddd;
  box-shadow: 2px 0 8px #0001;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-width: 320px;
  max-width: 320px;
  padding: 0;
}
.pageslist-spacer {
  flex: 1 1 auto;
}
#pagesList-container {
  flex: 0 0 auto;
  padding: 1em 0.5em 1em 0.5em;
  max-height: 50vh;
  overflow-y: auto;
}
#pagesList {
  min-height: 120px;
  max-height: 40vh;
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
}
#jwb-state {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 97.5vw;
  background: #eaeaea;
  border-top: 1px solid #ccc;
  padding: 0.5em 2em;
  z-index: 200;
  text-align: left;
  font-size: 1.1em;
  box-shadow: 0 -2px 8px #0001;
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 1em;
}
#jwb-state > * {
  display: inline;
  margin: 0;
}
/* Slide transition for tabs */
.slide-tabs-enter-active, .slide-tabs-leave-active {
  transition: max-height 0.4s cubic-bezier(.4,0,.2,1), opacity 0.4s cubic-bezier(.4,0,.2,1);
  overflow: hidden;
}
.slide-tabs-enter-from, .slide-tabs-leave-to {
  max-height: 0;
  opacity: 0;
}
.slide-tabs-enter-to, .slide-tabs-leave-from {
  max-height: 1000px;
  opacity: 1;
}
.cdx-label__description {
  display: block;
}`;
  document.head.appendChild(style);
})();

mw.loader.using(["vue", "@wikimedia/codex"], function (require) {
  const Vue = require("vue");
  const {
    CdxTabs,
    CdxTab,
    CdxSelect,
    CdxTextInput,
    CdxButton,
    CdxCheckbox,
    CdxTextArea,
    CdxRadio,
    CdxField,
  } = require("@wikimedia/codex");

  const app = Vue.createApp({
    name: "JWBInterface",
    components: {
      CdxTabs,
      CdxTab,
      CdxSelect,
      CdxTextInput,
      CdxButton,
      CdxCheckbox,
      CdxTextArea,
      CdxRadio,
      CdxField,
    },
    template: `  <div id="jwb-app-layout">
    <div id="jwb-main-area">
      <div id="jwb-preview">
        <h3>תצוגה מקדימה</h3>
        <div v-html="previewText"></div>
      </div>
      <div id="jwb-center-area">
        <div v-if="!isRunning" id="jwb-controls" class="jwb-controls-top">
          <cdx-button
            v-for="btn in buttons"
            :key="btn.key"
            :action="btn.action"
            :weight="btn.weight"
            @click="btn.onClick"
          >
            {{ btn.label }}
          </cdx-button>
        </div>
        <div v-if="!isRunning" id="jwb-tabs-area">
          <cdx-tabs>
            <cdx-tab name="general" label="כללי">
              <!-- תוכן הטאב הכללי -->
              <fieldset id="pagelist">
                <legend>{{ "label-pagelist" }}</legend>
                <cdx-button id="pagelistButton" @click="pagelistGenerate">
                  {{ "pagelist-generate" }}
                </cdx-button>
                <cdx-button id="removeDupes" @click="removeDupes">
                  {{ "button-remove-dupes" }}
                </cdx-button>
                <cdx-button id="sortArticles" @click="sortArticles">
                  {{ "button-sort" }}
                </cdx-button>
              </fieldset>
              <fieldset id="limits">
                <legend>{{ "label-limits" }}</legend>
                <p>זמן חיפוש</p>
                <cdx-text-input
                  v-model="limits.inputValueTimeLimit"
                  input-type="number"
                  id="timelimit"
                  min="0"
                  >timelimit-label</cdx-text-input
                >
                <p>מספר תווים מקסימלי</p>
                <cdx-text-input
                  v-model="limits.inputValueSizeLimit"
                  input-type="number"
                  id="sizelimit"
                  min="0"
                  >diff-size-limit</cdx-text-input
                >
              </fieldset>
            </cdx-tab>
            <cdx-tab name="edit-setting" label="עריכה">
              <!-- תוכן טאב אפשרויות העריכה -->
              <fieldset id="save-setting">
                <legend>{{ "label-save-setting" }}</legend>
                <cdx-checkbox
                  v-model="editFields.checkboxValueEditMinor"
                  key="minor-edit"
                  >{{ "label-minor-edit" }}</cdx-checkbox
                >
                <cdx-checkbox
                  v-model="editFields.checkboxValueHasTag"
                  key="hasTag"
                  >{{ "label-hasTag" }}</cdx-checkbox
                >
                <cdx-text-input
                  v-model="editFields.inputTextSummary"
                  key="summary"
                  >{{ "label-summary" }}</cdx-text-input
                >
                <cdx-checkbox
                  v-model="editFields.checkboxValueAutoSave"
                  key="auto-save"
                  >{{ "auto save" }}</cdx-checkbox
                >
                <cdx-text-input
                  v-model="editFields.inputValueSaveInterval"
                  input-type="number"
                  id="save-interval"
                  >{{ "save-interval" }}</cdx-text-input
                >
              </fieldset>
              <fieldset id="edit-options">
                <legend>{{ "edit-options" }}</legend>
                <cdx-field :is-fieldset="true">
                  <template #label> display completion </template>
                  <cdx-radio
                    v-for="radio in radiosDisplay"
                    :key="'radio-' + radio.value"
                    v-model="radioValueDisplay"
                    name="radio-group-descriptions"
                    :input-value="radio.value"
                    :inline="true"
                  >
                    {{ radio.label }}
                    <template #description>
                      {{ radio.description }}
                    </template>
                  </cdx-radio>
                </cdx-field>
              </fieldset>
              <fieldset id="more-options">
                <legend>{{ "more options" }}</legend>
                <cdx-field :is-fieldset="true">
                  <template #label> redirects completion </template>
                  <cdx-radio
                    v-for="radio in radiosRedirects"
                    :key="'radio-' + radio.value"
                    v-model="radioValueRedirects"
                    name="radio-group-descriptions"
                    :input-value="radio.value"
                    :inline="true"
                  >
                    {{ radio.label }}
                    <template #description>
                      {{ radio.description }}
                    </template>
                  </cdx-radio>
                </cdx-field>
              </fieldset>
            </cdx-tab>
            <cdx-tab name="import-options" label="ייבוא">
              <cdx-checkbox v-model="enableImport">
                אפשר טעינה של ויקיטקסט מאתר חיצוני
              </cdx-checkbox>
              <fieldset :disabled="!enableImport" style="margin-top: 1em">
                <legend>אפשרויות ייבוא</legend>
                <cdx-field :is-fieldset="true">
                  <template #label> בחר מצב ייבוא </template>
                  <cdx-radio
                    v-for="mode in importModes"
                    :key="mode.value"
                    v-model="importMode"
                    :input-value="mode.value"
                    name="import-mode"
                  >
                    {{ mode.label }}
                  </cdx-radio>
                </cdx-field>
                <cdx-checkbox v-model="enableWikidata" style="margin-top: 1em">
                  שלב טעינה מוויקינתונים
                </cdx-checkbox>
              </fieldset>
            </cdx-tab>
            <cdx-tab name="replace-options" label="החלפות">
              <fieldset id="replacements">
                <legend>החלפות</legend>
                <div
                  v-for="(replacement, idx) in replacements"
                  :key="idx"
                  style="
                    margin-bottom: 1em;
                    display: flex;
                    gap: 0.5em;
                    align-items: center;
                  "
                >
                  <cdx-text-input
                    v-model="replacement.source"
                    placeholder="מקור"
                    style="width: 40%"
                  />
                  <span>→</span>
                  <cdx-text-input
                    v-model="replacement.target"
                    placeholder="החלפה"
                    style="width: 40%"
                  />
                  <cdx-button
                    @click="removeReplacement(idx)"
                    size="small"
                    style="margin-right: 0.5em"
                    >הסר</cdx-button
                  >
                </div>
                <cdx-button @click="addReplacement" size="small"
                  >הוסף החלפה</cdx-button
                >
              </fieldset>
            </cdx-tab>
            <cdx-tab name="skip-settings" label="הגדרות דילוג">
              <fieldset id="skip-settings">
                <legend>הגדרות דילוג</legend>
                <cdx-checkbox v-model="skipSettings.skipIfEmpty">דלג אם הדף ריק</cdx-checkbox>
                <cdx-checkbox v-model="skipSettings.skipNoChange">דלג אם לא בוצעו שינויים</cdx-checkbox>
                <div style="margin: 0.5em 0;">
                  <span>דלג לפי קיום הדף:</span>
                  <cdx-radio v-model="skipSettings.existsOption" name="existsOption" input-value="any">כל מצב</cdx-radio>
                  <cdx-radio v-model="skipSettings.existsOption" name="existsOption" input-value="yes">רק אם קיים</cdx-radio>
                  <cdx-radio v-model="skipSettings.existsOption" name="existsOption" input-value="no">רק אם לא קיים</cdx-radio>
                </div>
                <cdx-text-input v-model="skipSettings.skipIfTitleContains" placeholder="דלג אם שם הדף מכיל..." />
                <cdx-text-input v-model="skipSettings.skipIfTemplate" placeholder="דלג אם הדף מכיל תבנית..." />
                <cdx-text-input v-model="skipSettings.skipContains" placeholder="דלג אם הדף מכיל מחרוזת..." />
                <cdx-text-input v-model="skipSettings.skipNotContains" placeholder="דלג אם הדף לא מכיל מחרוזת..." />
                <cdx-checkbox v-model="skipSettings.containRegex">השתמש בביטוי רגולרי</cdx-checkbox>
                <cdx-text-input v-if="skipSettings.containRegex" v-model="skipSettings.containFlags" placeholder="דגלי regex (למשל: gi)" />
                <cdx-text-input v-model="skipSettings.skipCategories" placeholder="דלג אם הדף בקטגוריה... (מופרד בפסיקים)" />
              </fieldset>
            </cdx-tab>
            <cdx-tab v-if="isSysop" name="adminTab" label="כלים למפעילים">
              <fieldset>
                <legend>העברה</legend>
                <cdx-checkbox v-model="admin.moveSuppressRedirect">דיכוי הפניה</cdx-checkbox>
                <cdx-checkbox v-model="admin.moveTalk">העבר דף שיחה</cdx-checkbox>
                <cdx-checkbox v-model="admin.moveSubpages">העבר דפי משנה</cdx-checkbox>
                <cdx-text-input v-model="admin.moveTo" placeholder="שם חדש לדף" />
                <cdx-button>העבר</cdx-button>
              </fieldset>
              <fieldset>
                <legend>מחיקה</legend>
                <cdx-checkbox v-model="admin.deleteTalk">מחק גם דף שיחה</cdx-checkbox>
                <cdx-button>מחק</cdx-button>
              </fieldset>
              <fieldset>
                <legend>הגנה</legend>
                <div>עריכה:
                  <cdx-select v-model="admin.editProt" :options="admin.protOptions" />
                </div>
                <div>העברה:
                  <cdx-select v-model="admin.moveProt" :options="admin.protOptions" />
                </div>
                <div>העלאה:
                  <cdx-select v-model="admin.uploadProt" :options="admin.protOptions" />
                </div>
                <cdx-text-input v-model="admin.protectExpiry" placeholder="תוקף (למשל: infinite)" />
                <cdx-button>הגן</cdx-button>
              </fieldset>
            </cdx-tab>
            <!-- הוסף טאבים נוספים כנדרש -->
          </cdx-tabs>
        </div>
        <div v-if="isRunning" id="jwb-edit-area">
          <div id="jwb-edit">
            <h3>עריכה</h3>
            <cdx-text-area v-model="inputTextEdit" rows="10"></cdx-text-area>
          </div>
          <div id="jwb-controls" class="jwb-controls-bottom">
            <cdx-button
              v-for="btn in buttons"
              :key="btn.key"
              :action="btn.action"
              :weight="btn.weight"
              @click="btn.onClick"
            >
              {{ btn.label }}
            </cdx-button>
          </div>
        </div>
      </div>
    </div>
    <div id="jwb-pageslist-sidebar">
      <div class="pageslist-spacer"></div>
      <div id="pagesList-container">
        <cdx-text-area
          v-model="inputTextPagesList"
          id="pagesList"
        ></cdx-text-area>
      </div>
    </div>
    <div id="jwb-state">
      <span
        >בעריכה: <b>{{ currentPage }}</b></span
      >
      <span> | סטטיסטיקה: {{ stats }}</span>
    </div>
  </div>`,
    setup() {
      const isRunning = Vue.ref(false);
      const currentPage = Vue.ref(1);
      const stats = Vue.ref("0/0");

      const radioValueDisplay = Vue.ref("diff");
      const radioValueRedirects = Vue.ref("flow");
      const enableImport = Vue.ref(false);
      const importMode = Vue.ref("import-only");
      const enableWikidata = Vue.ref(false);
      const inputTextEdit = Vue.ref("");
      const inputTextPagesList = Vue.ref("");

      function startStop() {
        isRunning.value = !isRunning.value;
      }
      function toggleDisplayMode() {
        radioValueDisplay.value =
          radioValueDisplay.value === "Preview" ? "diff" : "Preview";
      }
      function savePage() {
        // כאן תבוא לוגיקת שמירה
      }
      function skipPage() {
        // כאן תבוא לוגיקת דילוג
      }

      const importModes = [
        { value: "import-only", label: "ייבוא בלבד (יצירת דף חדש)" },
        { value: "update-only", label: "עדכון בלבד (עריכת דף קיים)" },
        { value: "both", label: "ייבוא ועדכון" },
      ];
      const radiosDisplay = [
        {
          label: "diff mode",
          description:
            "Corrects up to two typos. Removes redirects that are very similar to the main title.",
          value: "diff",
        },
        {
          label: "Preview mode",
          description:
            "No typo correction. No accent folding. Strict matching.",
          value: "Preview",
        },
      ];
      const radiosRedirects = [
        {
          label: "flow",
          description: "flows",
          value: "flow",
        },
        {
          label: "skip",
          description: "skip",
          value: "skip",
        },
        {
          label: "edit",
          description: "edit",
          value: "edit",
        },
      ];
      const buttons = Vue.computed(() => [
        {
          key: "startStop",
          label: isRunning.value ? "עצירה" : "הפעלה",
          action: isRunning.value ? "destructive" : "progressive",
          weight: "primary",
          onClick: startStop,
        },
        {
          key: "toggleDisplay",
          label:
            radioValueDisplay.value === "Preview"
              ? "הצגת הבדלים"
              : "תצוגה מקדימה",
          action: "normal",
          onClick: toggleDisplayMode,
        },
        {
          key: "save",
          label: "שמירה",
          action: "progressive",
          onClick: savePage,
        },
        {
          key: "skip",
          label: "דילוג",
          action: "destructive",
          onClick: skipPage,
        },
      ]);
      const editFields = Vue.reactive({
        inputTextSummary: "",
        inputValueSaveInterval: "",
        checkboxValueEditMinor: false,
        checkboxValueHasTag: false,
        checkboxValueAutoSave: false,
      });
      // קיבוץ שדות מגבלות
      const limits = Vue.reactive({
        inputValueTimeLimit: "",
        inputValueSizeLimit: "",
      });

      // החלפות
      const replacements = Vue.reactive([{ source: "", target: "" }]);
      function addReplacement() {
        replacements.push({ source: "", target: "" });
      }
      function removeReplacement(idx) {
        if (replacements.length > 1) {
          replacements.splice(idx, 1);
        } else {
          replacements[0].source = "";
          replacements[0].target = "";
        }
      }

      const skipSettings = Vue.reactive({
        skipIfEmpty: false,
        skipNoChange: false,
        existsOption: "any", // any/yes/no
        skipIfTitleContains: "",
        skipIfTemplate: "",
        skipContains: "",
        skipNotContains: "",
        containRegex: false,
        containFlags: "",
        skipCategories: "",
      });
      const isSysop = Vue.ref(false); // יש להחליף בזיהוי אמיתי של הרשאות
      const admin = Vue.reactive({
        moveSuppressRedirect: false,
        moveTalk: false,
        moveSubpages: false,
        moveTo: "",
        deleteTalk: false,
        editProt: "",
        moveProt: "",
        uploadProt: "",
        protectExpiry: "",
        protOptions: [
          { value: "all", label: "ללא הגנה" },
          { value: "autoconfirmed", label: "מאומתים" },
          { value: "sysop", label: "מפעילים" },
        ],
      });
      return {
        isRunning,
        radioValueDisplay,
        radioValueRedirects,
        radiosDisplay,
        radiosRedirects,
        enableImport,
        importMode,
        enableWikidata,
        importModes,
        inputTextEdit,
        inputTextPagesList,
        editFields,
        limits,
        replacements,
        addReplacement,
        removeReplacement,
        savePage,
        skipPage,
        toggleDisplayMode,
        startStop,
        currentPage,
        stats,
        buttons,
        skipSettings,
        isSysop,
        admin,
      };
    },
  });
  const jwbContainer = document.createElement("div");
  jwbContainer.id = "jwb-container";
  document.body.innerHTML = "";
  document.body.appendChild(jwbContainer);
  app.mount("#jwb-container");
});
//</nowiki>