Compare commits

..

2 Commits

Author SHA1 Message Date
sajjadtalkhabi 9660e3fe8f fix: linter
Deploy banu-front / deploy (push) Successful in 1m28s
2026-05-28 15:52:48 +03:30
sajjadtalkhabi 3f3c66a02d fix: test 2026-05-28 15:40:22 +03:30
55 changed files with 2057 additions and 1173 deletions
+7 -1
View File
@@ -6,7 +6,13 @@ module.exports = {
es2021: true,
},
plugins: ['prettier', 'unicorn', 'import', 'waterfall'],
ignorePatterns: ['node_modules/', 'dist/', 'build/', '*.min.js', 'src/components/icons/icon-names.d.ts'],
ignorePatterns: [
'node_modules/',
'dist/',
'build/',
'*.min.js',
'src/components/icons/icon-names.d.ts',
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
+2 -2
View File
@@ -11,9 +11,9 @@ jobs:
env:
IMAGE: banu-front
CONTAINER: banu-front
PORT: "8080"
PORT: '8080'
VITE_API_BASE_URL: http://109.122.252.86/api
VITE_USE_MOCKS: "false"
VITE_USE_MOCKS: 'false'
steps:
- name: Clone repository at current commit
run: |
+4
View File
@@ -0,0 +1,4 @@
{
"*.{js,vue}": "eslint --fix",
"*.scss": "prettier --write"
}
-1
View File
@@ -1,4 +1,3 @@
{
"recommendations": [
"esbenp.prettier-vscode",
+399 -570
View File
File diff suppressed because it is too large Load Diff
+17 -11
View File
@@ -3,6 +3,7 @@
Source of truth: the Postman collection covering Terms, Courses, Sessions, Exams, Homeworks, Media (2026-05). This doc lists every place where backend and FE disagree on shape, plus FE-side concepts the backend doc has no slot for. Each item needs a product/design call before we wire it up.
Conventions in the rest of this doc:
- **B → FE** means the backend exposes a field/endpoint that the FE doesn't surface yet.
- **FE → B** means the FE shows/sends a field the backend doc doesn't accept.
- **shape diff** means both sides handle the concept but in different shapes (enum values, nesting, naming).
@@ -14,7 +15,7 @@ Conventions in the rest of this doc:
### Endpoints
| Backend | FE today | Status |
|---|---|---|
| --- | --- | --- |
| `GET /terms?per_page&active_only` | `getTermsList` | aligned |
| `GET /terms/:id` | `showTerm` | aligned |
| `POST /terms` | `addNewTerm` | aligned |
@@ -28,7 +29,7 @@ Conventions in the rest of this doc:
### Fields
| Backend → FE | FE has it as | Notes |
|---|---|---|
| --- | --- | --- |
| `starts_at`, `ends_at` (ISO datetime) | `startDate`, `endDate` | Naming diff; we send `starts_at`/`ends_at` in the mock already — confirm the FE form should rename or keep an adapter. |
| `cover_url` (read) + `cover_media_id` (write) | `coverUrl` / `coverMediaId` | aligned in shape, just camelCase. |
| `created_at` | `createdAt` | aligned. |
@@ -36,6 +37,7 @@ Conventions in the rest of this doc:
| `description` | `description` | aligned. |
**FE → B** (need decision):
- `studentsCount`, `coursesCount` — computed UI counts. Backend response doesn't include them. Either compute client-side or ask backend for `?include=counts`.
- `image` (UI alias of cover) — FE keeps this for a fallback. Backend response only has `cover_url`.
@@ -46,7 +48,7 @@ Conventions in the rest of this doc:
### Endpoints
| Backend | FE today | Status |
|---|---|---|
| --- | --- | --- |
| `GET /courses?term_id&per_page` | `getCoursesList` | aligned (drop `/admin/` prefix in `endpoints.js`). |
| `GET /courses/:id` | `showCourse` | aligned. Backend response includes nested `term` and `teacher` — FE already reads `course.term` / `course.teacher`, good. |
| `POST /courses` | `addNewCourse` | aligned. Backend currently requires `term_id` (422 example), but per user instruction the standalone (template-tab) flow must allow `term_id: null`. **Decide:** ask backend to make `term_id` nullable, or refuse to submit until a term is picked. |
@@ -59,7 +61,7 @@ Conventions in the rest of this doc:
### Fields
| Backend ↔ FE | Notes |
|---|---|
| --- | --- |
| `term_id``termId` | aligned. Nullable in CourseFormPage, required in AddOfferedCourseModal — schema reflects this. |
| `teacher_id``teacherId` | aligned. |
| `capacity``capacity` | aligned. |
@@ -69,6 +71,7 @@ Conventions in the rest of this doc:
| Nested `term`, `teacher` on show response | FE already reads. |
**FE → B** (need decision):
- `sessionsCount` — number-of-sessions field on the create form. Backend has nothing. Either compute server-side from related sessions, or drop the field.
- `prerequisites` (array of { courseId, course }) — backend has no prerequisite relation. Drop or ask backend for it.
- `contentType` (video/voice/text) + `contentMediaId` — single course-level content file. Backend treats files only as session media. Decide whether course-level content should move to "intro session" or stay a course concept.
@@ -81,7 +84,7 @@ Conventions in the rest of this doc:
### Endpoints
| Backend | FE today | Status |
|---|---|---|
| --- | --- | --- |
| `GET /sessions?course_id&per_page` | `getSessionsList` | aligned. |
| `GET /sessions/:id` | `showSession` | aligned. |
| `POST /sessions` | `addNewSession` | aligned. |
@@ -93,7 +96,7 @@ Conventions in the rest of this doc:
### Fields — biggest gap of all five resources
| Backend | FE today | Notes |
|---|---|---|
| --- | --- | --- |
| `type` enum: `online \| offline \| content` | `sessionType` enum: `in_person`, `online`, `video`, `audio`, `text`, `slide`, `pdf` | **Shape diff.** FE has 7 values; backend has 3. There's an existing `SESSION_TYPE_TO_SPEC` mapper in `services/mock/fixtures/admin-sessions.js`. Decide whether the FE keeps the richer 7-value enum (and we map down to backend's 3) or collapses. |
| `starts_at`, `location`, `link` | All three live **inside** `form.sessionConfig.*` plus also derived to top-level `startsAt` / `location` / `link` in the mock | **Structural diff.** Backend wants flat fields; FE form nests them under `sessionConfig` keyed by `sessionType`. The mock derives top-level from `sessionConfig.*` for show payloads. Decide whether the FE form should flatten the schema to match backend or keep the conditional-by-type config UI. |
| `media_ids[]` (write) / `media[]` (read with `collection_name`, `file_name`, `mime_type`, `file_size`, `url`, `download_url`) | `materials[]` with `{ fileId, isRequired, type, title, order }` | **Shape diff.** Backend's media rows are typed by upload-purpose (video/voice/pdf/slide/attachment); FE has its own `type` enum. Decide which shape the FE keeps. |
@@ -108,7 +111,7 @@ Conventions in the rest of this doc:
### Endpoints
| Backend | FE today | Status |
|---|---|---|
| --- | --- | --- |
| `GET /exams/:id` (with questions+options) | `showExam` | aligned. |
| `POST /exams` | `addNewExam` | aligned. |
| `PATCH /exams/:id` | `updateExam` | aligned. |
@@ -122,7 +125,7 @@ Conventions in the rest of this doc:
### Fields
| Backend ↔ FE | Notes |
|---|---|
| --- | --- | --- |
| `session_id``sessionId` | aligned. |
| `title``title` | aligned. |
| `description``description` | aligned. |
@@ -131,6 +134,7 @@ Conventions in the rest of this doc:
| Backend question shape: `{ question_text, position, options: [{ option_text, is_correct }] }` | FE: `{ title, score, correctAnswerId, answers: [{ id, title }] }` | **Shape diff.** Backend hides `is_correct` from public reads (only on add). FE concept of `score` (per-question weighting) has no backend slot. Decide: keep FE scoring (ask backend to store) or drop. |
**FE → B** (need decision):
- `durationMinutes` — no backend slot.
- `randomize` — no backend slot.
- `endDate` / `startDate` — exam validity window, no backend slot.
@@ -143,7 +147,7 @@ Conventions in the rest of this doc:
### Endpoints
| Backend | FE today | Status |
|---|---|---|
| --- | --- | --- |
| `POST /homeworks` | `addNewAssignment` | aligned (URL renamed to `/homeworks`; FE key name kept). |
| `PATCH /homeworks/:id` | `updateAssignment` | aligned. |
| `DELETE /homeworks/:id` | `deleteAssignment` | aligned. |
@@ -155,7 +159,7 @@ Conventions in the rest of this doc:
### Fields
| Backend ↔ FE | Notes |
|---|---|
| --- | --- | --- |
| `session_id``sessionId` | aligned. |
| `title`, `description` | aligned. |
| `deadline` (single datetime) | FE: `startDate` + `endDate` + computed `durationDays` | **Shape diff.** Backend has one deadline; FE has a window. Decide: drop start/end and use single deadline, or ask backend to add a window. |
@@ -166,6 +170,7 @@ Conventions in the rest of this doc:
| Submission `reviewed_at` (read) | — | Backend provides; FE doesn't surface. |
**FE → B** (need decision):
- `priority` enum (`mandatory \| optional`) — no backend slot.
- `submissionsCount` — derived count, no backend slot.
@@ -176,7 +181,7 @@ Conventions in the rest of this doc:
### Endpoints
| Backend | FE today | Status |
|---|---|---|
| --- | --- | --- |
| `POST /media` (multipart with `purpose` + `file`) | `uploadMedia` | aligned URL & method. |
| `GET /media/:id/download` | — | **Backend → FE.** Add as `downloadMedia`. |
| `DELETE /media/:id` | — | **Backend → FE.** Add as `deleteMedia`. |
@@ -194,6 +199,7 @@ Conventions in the rest of this doc:
### Snake_case vs camelCase
Backend wire format is snake_case throughout. FE today reads camelCase (e.g., the mock returns `coverUrl`, `isActive`). When the real backend lands, the FE will either need:
- a HTTP-layer transformer (camelize on response, snake_case on request), or
- camelCase field aliases on the backend serializer.
+1 -1
View File
@@ -1,4 +1,4 @@
<!doctype html>
<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8" />
+688
View File
@@ -13,6 +13,7 @@
"@tanstack/vue-query-devtools": "^5.62.2",
"@tinymce/tinymce-vue": "^4.0.7",
"axios": "^1.12.2",
"husky": "^8.0.0",
"jalaali-js": "^1.2.8",
"lodash": "^4.18.1",
"pinia": "^3.0.3",
@@ -33,6 +34,7 @@
"eslint-plugin-unicorn": "^55.0.0",
"eslint-plugin-vue": "^9.15.1",
"eslint-plugin-waterfall": "^1.0.1",
"lint-staged": "^15.5.2",
"postcss-html": "^1.8.0",
"prettier": "2.8.8",
"sass": "^1.83.0",
@@ -1926,6 +1928,22 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/ansi-escapes": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz",
"integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==",
"dev": true,
"license": "MIT",
"dependencies": {
"environment": "^1.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -2431,6 +2449,136 @@
"node": ">=0.8.0"
}
},
"node_modules/cli-cursor": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz",
"integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==",
"dev": true,
"license": "MIT",
"dependencies": {
"restore-cursor": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-truncate": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz",
"integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==",
"dev": true,
"license": "MIT",
"dependencies": {
"slice-ansi": "^5.0.0",
"string-width": "^7.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-truncate/node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/cli-truncate/node_modules/ansi-styles": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/cli-truncate/node_modules/emoji-regex": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"dev": true,
"license": "MIT"
},
"node_modules/cli-truncate/node_modules/is-fullwidth-code-point": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz",
"integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-truncate/node_modules/slice-ansi": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz",
"integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.0.0",
"is-fullwidth-code-point": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/cli-truncate/node_modules/string-width": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cli-truncate/node_modules/strip-ansi": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.2.2"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -2458,6 +2606,13 @@
"dev": true,
"license": "MIT"
},
"node_modules/colorette": {
"version": "2.0.20",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true,
"license": "MIT"
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -2949,6 +3104,19 @@
"node": ">=6"
}
},
"node_modules/environment": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
"integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/error-ex": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
@@ -3596,6 +3764,37 @@
"node": ">=0.10.0"
}
},
"node_modules/eventemitter3": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
"integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
"dev": true,
"license": "MIT"
},
"node_modules/execa": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3",
"get-stream": "^8.0.1",
"human-signals": "^5.0.0",
"is-stream": "^3.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^5.1.0",
"onetime": "^6.0.0",
"signal-exit": "^4.1.0",
"strip-final-newline": "^3.0.0"
},
"engines": {
"node": ">=16.17"
},
"funding": {
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -3897,6 +4096,19 @@
"node": ">= 0.4"
}
},
"node_modules/get-east-asian-width": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
"integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -3934,6 +4146,19 @@
"node": ">= 0.4"
}
},
"node_modules/get-stream": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/get-symbol-description": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
@@ -4264,6 +4489,31 @@
"entities": "^4.4.0"
}
},
"node_modules/human-signals": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=16.17.0"
}
},
"node_modules/husky": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/husky/-/husky-8.0.0.tgz",
"integrity": "sha512-4qbE/5dzNDNxFEkX9MNRPKl5+omTXQzdILCUWiqG/lWIAioiM5vln265/l6I2Zx8gpW8l1ukZwGQeCFbBZ6+6w==",
"license": "MIT",
"bin": {
"husky": "lib/bin.js"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
}
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -4705,6 +4955,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-stream": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/is-string": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
@@ -4949,6 +5212,19 @@
"node": ">= 0.8.0"
}
},
"node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
"integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -4956,6 +5232,75 @@
"dev": true,
"license": "MIT"
},
"node_modules/lint-staged": {
"version": "15.5.2",
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz",
"integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^5.4.1",
"commander": "^13.1.0",
"debug": "^4.4.0",
"execa": "^8.0.1",
"lilconfig": "^3.1.3",
"listr2": "^8.2.5",
"micromatch": "^4.0.8",
"pidtree": "^0.6.0",
"string-argv": "^0.3.2",
"yaml": "^2.7.0"
},
"bin": {
"lint-staged": "bin/lint-staged.js"
},
"engines": {
"node": ">=18.12.0"
},
"funding": {
"url": "https://opencollective.com/lint-staged"
}
},
"node_modules/lint-staged/node_modules/chalk": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/lint-staged/node_modules/commander": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
"integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/listr2": {
"version": "8.3.3",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz",
"integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"cli-truncate": "^4.0.0",
"colorette": "^2.0.20",
"eventemitter3": "^5.0.1",
"log-update": "^6.1.0",
"rfdc": "^1.4.1",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -4992,6 +5337,101 @@
"dev": true,
"license": "MIT"
},
"node_modules/log-update": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz",
"integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-escapes": "^7.0.0",
"cli-cursor": "^5.0.0",
"slice-ansi": "^7.1.0",
"strip-ansi": "^7.1.0",
"wrap-ansi": "^9.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/log-update/node_modules/ansi-styles": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/log-update/node_modules/is-fullwidth-code-point": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz",
"integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"get-east-asian-width": "^1.3.1"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/log-update/node_modules/slice-ansi": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"is-fullwidth-code-point": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
"node_modules/log-update/node_modules/strip-ansi": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.2.2"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -5041,6 +5481,13 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true,
"license": "MIT"
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -5099,6 +5546,32 @@
"node": ">= 0.6"
}
},
"node_modules/mimic-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mimic-function": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
"integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -5291,6 +5764,35 @@
"node": ">=0.10.0"
}
},
"node_modules/npm-run-path": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
"integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^4.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/npm-run-path/node_modules/path-key": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -5426,6 +5928,22 @@
"wrappy": "1"
}
},
"node_modules/onetime": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
"integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"mimic-fn": "^4.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -5607,6 +6125,19 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pidtree": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
"dev": true,
"license": "MIT",
"bin": {
"pidtree": "bin/pidtree.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/pinia": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.4.tgz",
@@ -6135,6 +6666,39 @@
"node": ">=4"
}
},
"node_modules/restore-cursor": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
"integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==",
"dev": true,
"license": "MIT",
"dependencies": {
"onetime": "^7.0.0",
"signal-exit": "^4.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/restore-cursor/node_modules/onetime": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
"integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"mimic-function": "^5.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -6590,6 +7154,16 @@
"node": ">= 0.4"
}
},
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -6687,6 +7261,19 @@
"node": ">=4"
}
},
"node_modules/strip-final-newline": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
@@ -7814,6 +8401,91 @@
"node": ">=0.10.0"
}
},
"node_modules/wrap-ansi": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
"integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-styles": "^6.2.1",
"string-width": "^7.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/ansi-regex": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
"integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/wrap-ansi/node_modules/emoji-regex": {
"version": "10.6.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"dev": true,
"license": "MIT"
},
"node_modules/wrap-ansi/node_modules/string-width": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"emoji-regex": "^10.3.0",
"get-east-asian-width": "^1.0.0",
"strip-ansi": "^7.1.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/wrap-ansi/node_modules/strip-ansi": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^6.2.2"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
@@ -7844,6 +8516,22 @@
"node": ">=12"
}
},
"node_modules/yaml": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
"dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14.6"
},
"funding": {
"url": "https://github.com/sponsors/eemeli"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+3
View File
@@ -11,6 +11,7 @@
"lint:fix": "eslint . --ext .js,.vue --fix --max-warnings=0",
"lint:css:check": "stylelint \"src/**/*.{css,scss,vue}\" --max-warnings=0",
"lint:css:fix": "stylelint \"src/**/*.{css,scss,vue}\" --fix --max-warnings=0",
"prepare": "husky install",
"format": "prettier --write .",
"format:check": "prettier --check ."
},
@@ -20,6 +21,7 @@
"@tanstack/vue-query-devtools": "^5.62.2",
"@tinymce/tinymce-vue": "^4.0.7",
"axios": "^1.12.2",
"husky": "^8.0.0",
"jalaali-js": "^1.2.8",
"lodash": "^4.18.1",
"pinia": "^3.0.3",
@@ -40,6 +42,7 @@
"eslint-plugin-unicorn": "^55.0.0",
"eslint-plugin-vue": "^9.15.1",
"eslint-plugin-waterfall": "^1.0.1",
"lint-staged": "^15.5.2",
"postcss-html": "^1.8.0",
"prettier": "2.8.8",
"sass": "^1.83.0",
+3 -3
View File
@@ -8,14 +8,14 @@
import { storeToRefs } from 'pinia'
import { computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useModalStore } from '@/store/modal'
import { useAuthStore } from '@/store/auth'
import { useGetMeQuery } from '@/services/query/auth'
import { tokenService } from '@/services/api/token-service'
import { useModalStore } from '@/store/modal'
import AdminLayout from '@/layouts/AdminLayout.vue'
import { useGetMeQuery } from '@/services/query/auth'
import PublicLayout from '@/layouts/PublicLayout.vue'
import StudentLayout from '@/layouts/StudentLayout.vue'
import ConfirmModal from '@/components/ConfirmModal.vue'
import { tokenService } from '@/services/api/token-service'
import { VueQueryDevtools } from '@tanstack/vue-query-devtools'
const route = useRoute()
+3 -5
View File
@@ -47,7 +47,7 @@ const customer = (init) => {
init.placeholder = props.placeholder
// Paste pictures and automatically process base64
init.urlconverter_callback = (url, node, onSave, name) => {
init.urlconverter_callback = (url, node, _onSave, _name) => {
if (node === 'img' && url.startsWith('blob:')) {
tinymce.activeEditor && tinymce.activeEditor.uploadImages()
}
@@ -73,7 +73,7 @@ onMounted(() => {
// Listen for text changes and pass them to the outside world
watch(
() => state.contentValue,
(n) => {
() => {
debounce(() => {
emit('update:modelValue', state.contentValue)
})
@@ -112,7 +112,5 @@ const imgUploadFn = async (blobInfo, success, failure) => {
return failure(`HTTP Error: ${response.status}`)
}
const { myInit, contentValue, timeout } = toRefs(state)
const { myInit, contentValue } = toRefs(state)
</script>
<style></style>
+2 -2
View File
@@ -54,8 +54,8 @@ const onToggle = () => {
}
&--selected .checkbox-field__box {
background: #999999;
border-color: #999999;
background: #999;
border-color: #999;
}
&__box {
+1 -1
View File
@@ -122,7 +122,7 @@ onBeforeUnmount(revokePreview)
align-items: center;
gap: 0.75rem;
padding: 1rem;
background: #eeeeee;
background: #eee;
border-radius: 1.5rem;
min-height: 18rem;
justify-content: space-between;
@@ -5,12 +5,12 @@
<div class="assignment-item__sub">
<span class="assignment-item__sub-label">دوره:</span>
<span class="assignment-item__sub-value">
{{ assignment.course?.title || assignment.courseTitle || '—' }}
{{ assignment.session?.course?.title || '—' }}
</span>
<span class="assignment-item__dot">|</span>
<span class="assignment-item__sub-label">جلسه:</span>
<span class="assignment-item__sub-value">
{{ assignment.session?.title || assignment.sessionTitle || '—' }}
{{ assignment.session?.title || '—' }}
</span>
</div>
</div>
@@ -92,12 +92,10 @@ const duration = computed(() =>
)
const submissions = computed(() =>
props.assignment.submissionsCount == null ? '—' : `${props.assignment.submissionsCount} نفر`
props.assignment.submittersCount == null ? '—' : `${props.assignment.submittersCount} نفر`
)
const createdAt = computed(
() => props.assignment.faCreatedAt || formatJalaaliDate(props.assignment.createdAt) || '—'
)
const createdAt = computed(() => formatJalaaliDate(props.assignment.createdAt) || '—')
</script>
<style lang="scss" scoped>
@@ -7,6 +7,18 @@
</template>
</TextField>
<SelectField
v-model="form.termId"
name="termId"
label="ترم"
:options="termOptions"
option-label="title"
option-value="id"
:searchable="true"
:on-search="searchTerms"
@update:modelValue="onTermChange"
/>
<SelectField
v-if="form.termId"
v-model="form.courseId"
name="courseId"
label="دوره"
@@ -15,8 +27,10 @@
option-value="id"
:searchable="true"
:on-search="searchTemplates"
@update:modelValue="onCourseChange"
/>
<SelectField
v-if="form.courseId"
v-model="form.sessionId"
name="sessionId"
label="جلسه"
@@ -65,6 +79,7 @@ import TextField from '@/components/form/TextField.vue'
import CircleButton from '@/components/CircleButton.vue'
import SelectField from '@/components/form/SelectField.vue'
import DatePickerField from '@/components/form/DatePickerField.vue'
import { useAdminTermsListQuery } from '@/services/query/admin-terms'
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
import { useAdminSessionsListQuery } from '@/services/query/admin-sessions'
@@ -73,6 +88,7 @@ const props = defineProps({
type: Object,
default: () => ({
title: '',
termId: '',
courseId: '',
sessionId: '',
fromDate: '',
@@ -85,6 +101,7 @@ const emit = defineEmits(['update:modelValue', 'apply', 'reset'])
const emptyForm = () => ({
title: '',
termId: '',
courseId: '',
sessionId: '',
fromDate: '',
@@ -102,10 +119,21 @@ watch(
const todayIso = new Date().toISOString()
const termSearch = ref('')
const termFilters = computed(() => ({ title: termSearch.value }))
const termPagination = ref({ page: 1, perPage: 100 })
const { data: termsResponse } = useAdminTermsListQuery(termFilters, termPagination)
const termOptions = computed(() => termsResponse.value?.data ?? [])
const templateSearch = ref('')
const templateFilters = computed(() => ({ title: templateSearch.value }))
const templateFilters = computed(() => ({
title: templateSearch.value,
termId: form.value.termId || undefined,
}))
const templatePagination = ref({ page: 1, perPage: 10 })
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination)
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination, {
enabled: () => !!form.value.termId,
})
const templateOptions = computed(() => templatesResponse.value?.data ?? [])
const sessionSearch = ref('')
@@ -114,9 +142,18 @@ const sessionListFilters = computed(() => ({
courseId: form.value.courseId || undefined,
}))
const sessionPagination = ref({ page: 1, perPage: 10 })
const { data: sessionsResponse } = useAdminSessionsListQuery(sessionListFilters, sessionPagination)
const { data: sessionsResponse } = useAdminSessionsListQuery(
sessionListFilters,
sessionPagination,
{
enabled: () => !!form.value.courseId,
}
)
const sessionOptions = computed(() => sessionsResponse.value?.data ?? [])
const searchTerms = useDebounce((q) => {
termSearch.value = q || ''
}, 400)
const searchTemplates = useDebounce((q) => {
templateSearch.value = q || ''
}, 400)
@@ -124,6 +161,15 @@ const searchSessions = useDebounce((q) => {
sessionSearch.value = q || ''
}, 400)
const onTermChange = () => {
form.value.courseId = ''
form.value.sessionId = ''
}
const onCourseChange = () => {
form.value.sessionId = ''
}
const hasFilters = computed(() =>
Object.values(form.value).some((v) => v !== '' && v !== null && v !== undefined)
)
@@ -157,7 +203,7 @@ const onReset = () => {
}
@media (min-width: 1280px) {
grid-template-columns: repeat(5, 1fr);
grid-template-columns: repeat(6, 1fr);
}
}
@@ -21,6 +21,18 @@
<SvgIcon name="book" :size="20" color="var(--color-thd-gray)" />
</template>
</TextField>
<SelectField
v-model="form.termId"
name="termId"
label="ترم مرتبط"
:options="termOptions"
option-label="title"
option-value="id"
:searchable="true"
:on-search="searchTerms"
:error="errors.termId"
@update:model-value="onTermChange"
/>
<SelectField
v-model="form.courseId"
name="courseId"
@@ -30,6 +42,7 @@
option-value="id"
:searchable="true"
:on-search="searchTemplates"
:disabled="!form.termId"
:error="errors.courseId"
@update:model-value="onCourseChange"
/>
@@ -77,13 +90,13 @@
</div>
<div class="add-assignment__files">
<LineTitleBlock title="فایل‌های تکلیف" title-en="Assignment Files" />
<FileUploader
v-model="attachments"
accept=".mp4,.mov,.avi,.mp3,.wav,.jpg,.jpeg,.png,.pdf,.txt,.doc,.docx"
:multiple="true"
:max-files="10"
context="assignment"
@select="onAttachmentsSelect"
@error="onAttachmentsError"
/>
</div>
@@ -117,6 +130,7 @@
</template>
<script setup>
import { toast } from 'vue3-toastify'
import useYup from '@/composables/useYup'
import { computed, ref, watch } from 'vue'
import useModal from '@/composables/useModal'
@@ -128,10 +142,12 @@ import BaseButton from '@/components/BaseButton.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import TextField from '@/components/form/TextField.vue'
import SelectField from '@/components/form/SelectField.vue'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import FileUploader from '@/components/form/FileUploader.vue'
import { objectToFormData } from '@/utils/object-to-formdata'
import { useUploadMediaMutation } from '@/services/query/auth'
import TextareaField from '@/components/form/TextareaField.vue'
import DatePickerField from '@/components/form/DatePickerField.vue'
import { useAdminTermsListQuery } from '@/services/query/admin-terms'
import { assignmentSchema } from '@/features/admin/assignments/schema'
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
import { useAdminSessionsListQuery } from '@/services/query/admin-sessions'
@@ -158,6 +174,7 @@ const priorityOptions = Object.entries(ASSIGNMENT_PRIORITY).map(([value, label])
const form = ref({
title: '',
termId: '',
courseId: '',
sessionId: '',
startDate: '',
@@ -172,10 +189,28 @@ const schema = assignmentSchema
const { validate, validateAt, errors, resetErrors } = useYup(schema)
const termSearch = ref('')
const termFilters = computed(() => ({ title: termSearch.value }))
const termPagination = ref({ page: 1, perPage: 100 })
const { data: termsResponse } = useAdminTermsListQuery(termFilters, termPagination)
const selectedTerm = ref(null)
const termOptions = computed(() => {
const base = termsResponse.value?.data ?? []
if (selectedTerm.value && !base.some((t) => t.id === selectedTerm.value.id)) {
return [...base, selectedTerm.value]
}
return base
})
const templateSearch = ref('')
const templateFilters = computed(() => ({ title: templateSearch.value }))
const templateFilters = computed(() => ({
title: templateSearch.value,
termId: form.value.termId || undefined,
}))
const templatePagination = ref({ page: 1, perPage: 10 })
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination)
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination, {
enabled: () => !!form.value.termId,
})
const selectedTemplate = ref(null)
const templateOptions = computed(() => {
const base = templatesResponse.value?.data ?? []
@@ -203,6 +238,9 @@ const sessionOptions = computed(() => {
return base
})
const searchTerms = useDebounce((q) => {
termSearch.value = q || ''
}, 400)
const searchTemplates = useDebounce((q) => {
templateSearch.value = q || ''
}, 400)
@@ -210,37 +248,78 @@ const searchSessions = useDebounce((q) => {
sessionSearch.value = q || ''
}, 400)
const onTermChange = (value) => {
form.value.termId = value
form.value.courseId = ''
form.value.sessionId = ''
selectedTemplate.value = null
selectedSession.value = null
}
const onCourseChange = (value) => {
form.value.courseId = value
form.value.sessionId = ''
selectedSession.value = null
}
const uploadMediaMutation = useUploadMediaMutation()
const onAttachmentsSelect = async (files) => {
for (const file of files) {
try {
const fd = objectToFormData({ file, purpose: 'homework_file', context: 'homework' })
const response = await uploadMediaMutation.mutateAsync(fd)
const payload = response?.data ?? response
const id = payload?.id ?? payload?.uploadId
if (id == null) continue
attachments.value = [
...attachments.value,
{ id, name: file.name, size: file.size, url: payload?.url ?? '' },
]
} catch {
toast.error(`بارگذاری فایل "${file.name}" با خطا مواجه شد.`)
}
}
}
const onAttachmentsError = (msg) => toast.error(msg)
const { data: existingAssignment } = useAdminAssignmentQuery(assignmentId, {
enabled: () => !!assignmentId.value,
})
watch(existingAssignment, (assignment) => {
if (!assignment) return
const tpl = assignment.course
const sessionEntity = assignment.session
const tpl = sessionEntity?.course || assignment.course
const termEntity = tpl?.term || assignment.term
const termId = termEntity?.id || tpl?.termId || assignment.termId || ''
const priorityValue =
assignment.priority ||
(typeof assignment.isPriority === 'boolean'
? assignment.isPriority
? 'mandatory'
: 'optional'
: 'mandatory')
if (termEntity) selectedTerm.value = termEntity
if (tpl) selectedTemplate.value = tpl
if (sessionEntity) selectedSession.value = sessionEntity
form.value = {
title: assignment.title || '',
courseId: tpl?.id || assignment.courseId || '',
termId,
courseId: tpl?.id || sessionEntity?.courseId || assignment.courseId || '',
sessionId: sessionEntity?.id || assignment.sessionId || '',
startDate: assignment.startDate || '',
endDate: assignment.endDate || '',
priority: assignment.priority || 'mandatory',
endDate: assignment.endDate || assignment.deadline || '',
priority: priorityValue,
description: assignment.description || '',
}
attachments.value = Array.isArray(assignment.attachments)
? assignment.attachments.map((file) => ({
id: file.id,
name: file.title || `فایل ${file.id}`,
url: file.fileUrl || '',
type: file.type || 'other',
attachments.value = Array.isArray(assignment.media)
? assignment.media.map((m) => ({
id: m.id,
name: m.fileName || `فایل ${m.id}`,
size: m.fileSize ?? 0,
url: m.url || m.downloadUrl || '',
}))
: []
})
@@ -254,13 +333,13 @@ const onSubmit = async (close) => {
const { isValid, payload } = await validate(form.value)
if (!isValid) return
const finalPayload = {
...payload,
attachments: attachments.value.map((file, index) => ({
fileId: file.id,
type: file.type || 'other',
title: file.name,
order: index + 1,
})),
sessionId: payload.sessionId,
title: payload.title,
description: payload.description ?? '',
deadline: payload.endDate || null,
isActive: true,
isPriority: payload.priority === 'mandatory',
mediaIds: attachments.value.map((file) => file.id).filter((id) => id != null),
}
if (isEditMode.value) {
await updateMutation.mutateAsync({ id: assignmentId.value, payload: finalPayload })
@@ -14,12 +14,9 @@
<div class="assignment-details__head">
<p class="assignment-details__title">{{ assignment.title || '—' }}</p>
<p class="assignment-details__sub">
<span>
دوره:
{{ assignment.course?.title || assignment.courseTitle || '—' }}
</span>
<span>دوره: {{ courseTitle }}</span>
<span class="assignment-details__sep">|</span>
<span>جلسه: {{ assignment.session?.title || assignment.sessionTitle || '—' }}</span>
<span>جلسه: {{ sessionTitle }}</span>
</p>
</div>
@@ -28,21 +25,10 @@
title="تاریخ شروع"
:numeric-desc="formatJalaaliDate(assignment.startDate) || ''"
/>
<LineInfoBlock
title="تاریخ پایان"
:numeric-desc="formatJalaaliDate(assignment.endDate) || ''"
/>
<LineInfoBlock
title="مدت زمان"
:numeric-desc="
assignment.durationDays != null ? `${assignment.durationDays} روز` : ''
"
/>
<LineInfoBlock title="اولویت" :desc="ASSIGNMENT_PRIORITY[assignment.priority] || '—'" />
<LineInfoBlock
title="تعداد فرستندگان"
:numeric-desc="assignment.submissionsCount ?? 0"
/>
<LineInfoBlock title="تاریخ پایان" :numeric-desc="deadlineLabel" />
<LineInfoBlock title="مدت زمان" :numeric-desc="durationLabel" />
<LineInfoBlock title="اولویت" :desc="priorityLabel" />
<LineInfoBlock title="تعداد فرستندگان" :numeric-desc="submittersLabel" />
<LineInfoBlock
title="تاریخ ثبت"
:numeric-desc="
@@ -55,18 +41,18 @@
<LineInfoBlock title="توضیحات" :desc="assignment.description" />
</div>
<div v-if="assignment.attachments?.length" class="assignment-details__attachments">
<div v-if="attachmentItems.length > 0" class="assignment-details__attachments">
<LineTitleBlock title="فایل‌های تکلیف" title-en="Attachments" />
<ul class="assignment-details__attachments-list">
<li v-for="file in assignment.attachments" :key="file.id">
<li v-for="file in attachmentItems" :key="file.id">
<a
:href="file.fileUrl || '#'"
:href="file.url || '#'"
target="_blank"
rel="noopener noreferrer"
class="assignment-details__file"
>
<SvgIcon name="file" :size="16" color="var(--color-prim-gray)" />
<span>{{ file.title || `فایل ${file.id}` }}</span>
<span>{{ file.title }}</span>
</a>
</li>
</ul>
@@ -112,6 +98,65 @@ const assignmentId = computed(() => modalData.value.id ?? null)
const { data: assignment, isLoading } = useAdminAssignmentQuery(assignmentId, {
enabled: () => !!assignmentId.value,
})
const courseTitle = computed(
() =>
assignment.value?.session?.course?.title ||
assignment.value?.course?.title ||
assignment.value?.courseTitle ||
'—'
)
const sessionTitle = computed(
() => assignment.value?.session?.title || assignment.value?.sessionTitle || '—'
)
const deadlineRaw = computed(() => assignment.value?.endDate || assignment.value?.deadline || '')
const deadlineLabel = computed(() => formatJalaaliDate(deadlineRaw.value) || '—')
const durationLabel = computed(() => {
if (assignment.value?.durationDays != null) return `${assignment.value.durationDays} روز`
const start = assignment.value?.startDate || assignment.value?.createdAt
const end = deadlineRaw.value
if (!start || !end) return '—'
const diff = Math.ceil((new Date(end).getTime() - new Date(start).getTime()) / 86_400_000)
return diff >= 0 ? `${diff} روز` : '—'
})
const priorityLabel = computed(() => {
const priority =
assignment.value?.priority ||
(typeof assignment.value?.isPriority === 'boolean'
? assignment.value.isPriority
? 'mandatory'
: 'optional'
: null)
return ASSIGNMENT_PRIORITY[priority] || '—'
})
const submittersLabel = computed(
() => assignment.value?.submittersCount ?? assignment.value?.submissionsCount ?? 0
)
const attachmentItems = computed(() => {
const media = assignment.value?.media
if (Array.isArray(media) && media.length > 0) {
return media.map((m) => ({
id: m.id,
title: m.fileName || `فایل ${m.id}`,
url: m.url || m.downloadUrl || '',
}))
}
const legacy = assignment.value?.attachments
if (Array.isArray(legacy)) {
return legacy.map((a) => ({
id: a.id,
title: a.title || `فایل ${a.id}`,
url: a.fileUrl || '',
}))
}
return []
})
</script>
<style lang="scss" scoped>
@@ -1,10 +1,14 @@
<template>
<BasicModal width="95%" max-width="60rem" min-width="auto" :show-close-button="true">
<template #default="{ data, close }">
<BasicModal
title="تکالیف فرستادگان"
title-en="Delegates Submissions"
width="95%"
max-width="60rem"
min-width="auto"
:show-close-button="true"
>
<template #default="{ close }">
<div class="assignment-submissions">
<LineTitleBlock title="تکالیف فرستادگان" title-en="Delegates Submissions" />
<p v-if="data?.title" class="assignment-submissions__assignment">{{ data.title }}</p>
<SkeletonLoaderBlock v-if="isLoading" :rows="4" :cols-per-row="1" />
<div v-else-if="submissions.length > 0" class="assignment-submissions__list">
<div
@@ -73,7 +77,6 @@ import SvgIcon from '@/components/icons/SvgIcon.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import { formatJalaaliDate } from '@/utils/date-utils'
import { usePagination } from '@/composables/usePagination'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import PaginationBlock from '@/components/blocks/PaginationBlock.vue'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import { useAdminAssignmentSubmissionsQuery } from '@/services/query/admin-assignments'
@@ -101,15 +104,16 @@ const paginationMeta = computed(() => ({
}))
const userName = (user) =>
`${user?.firstName || ''} ${user?.lastName || ''}`.trim() || user?.fullName || '—'
user?.name || `${user?.firstName || ''} ${user?.lastName || ''}`.trim() || user?.fullName || '—'
const locationFromAddress = (user) => {
const province = user?.address?.province?.name || ''
const city = user?.address?.city?.name || ''
const province = user?.province?.name || user?.address?.province?.name || ''
const city = user?.city?.name || user?.address?.city?.name || ''
return [province, city].filter(Boolean).join('، ')
}
const submittedAt = (sub) => sub.faSubmittedAt || formatJalaaliDate(sub.submittedAt) || '—'
const submittedAt = (sub) =>
sub.faSubmittedAt || formatJalaaliDate(sub.submittedAt || sub.createdAt || sub.reviewedAt) || '—'
const onShowDetails = (submission) => {
openModal('AssignmentSubmissionDetailsModal', {
@@ -77,6 +77,7 @@ const { openModal, isModal } = useModal()
const filters = ref({
title: '',
termId: '',
courseId: '',
sessionId: '',
fromDate: '',
@@ -4,7 +4,7 @@ export const assignmentSchema = object().shape({
title: string().required().min(3),
courseId: string().required(),
sessionId: string().required(),
startDate: string().required(),
startDate: string().nullable().notRequired(),
endDate: string().required(),
priority: string().required(),
description: string().nullable().notRequired(),
@@ -82,7 +82,6 @@ import BaseButton from '@/components/BaseButton.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import CircleButton from '@/components/CircleButton.vue'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import { adminCoursesKeys } from '@/services/query/admin-courses'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import {
@@ -35,15 +35,15 @@
/>
</div>
<div class="exam-question-builder__col exam-question-builder__col--score">
<label class="exam-question-builder__label">ترتیب</label>
<label class="exam-question-builder__label">بارم نمره</label>
<input
:value="question.position"
:value="question.score"
:disabled="disabled || isLocked(question)"
type="text"
inputmode="numeric"
placeholder="1"
class="exam-question-builder__input"
@input="updateQuestion(question.id, { position: $event.target.value })"
@input="updateQuestion(question.id, { score: $event.target.value })"
/>
</div>
</div>
@@ -147,7 +147,7 @@ const createOption = () => ({ id: createId('option'), optionText: '', isCorrect:
const createQuestion = () => ({
id: createId('question'),
questionText: '',
position: questions.value.length + 1,
score: '',
options: [createOption(), createOption()],
__local: true,
})
@@ -7,6 +7,18 @@
</template>
</TextField>
<SelectField
v-model="form.termId"
name="termId"
label="ترم"
:options="termOptions"
option-label="title"
option-value="id"
:searchable="true"
:on-search="searchTerms"
@update:modelValue="onTermChange"
/>
<SelectField
v-if="form.termId"
v-model="form.courseId"
name="courseId"
label="دوره"
@@ -15,6 +27,18 @@
option-value="id"
:searchable="true"
:on-search="searchTemplates"
@update:modelValue="onCourseChange"
/>
<SelectField
v-if="form.courseId"
v-model="form.sessionId"
name="sessionId"
label="جلسه"
:options="sessionOptions"
option-label="title"
option-value="id"
:searchable="true"
:on-search="searchSessions"
/>
<DatePickerField v-model="form.fromDate" name="fromDate" label="از تاریخ" :max="todayIso" />
<DatePickerField v-model="form.toDate" name="toDate" label="تا تاریخ" :max="todayIso" />
@@ -55,18 +79,34 @@ import TextField from '@/components/form/TextField.vue'
import CircleButton from '@/components/CircleButton.vue'
import SelectField from '@/components/form/SelectField.vue'
import DatePickerField from '@/components/form/DatePickerField.vue'
import { useAdminTermsListQuery } from '@/services/query/admin-terms'
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
import { useAdminSessionsListQuery } from '@/services/query/admin-sessions'
const props = defineProps({
modelValue: {
type: Object,
default: () => ({ title: '', courseId: '', fromDate: '', toDate: '' }),
default: () => ({
title: '',
termId: '',
courseId: '',
sessionId: '',
fromDate: '',
toDate: '',
}),
},
})
const emit = defineEmits(['update:modelValue', 'apply', 'reset'])
const emptyForm = () => ({ title: '', courseId: '', fromDate: '', toDate: '' })
const emptyForm = () => ({
title: '',
termId: '',
courseId: '',
sessionId: '',
fromDate: '',
toDate: '',
})
const form = ref({ ...emptyForm(), ...props.modelValue })
watch(
@@ -79,15 +119,56 @@ watch(
const todayIso = new Date().toISOString()
const termSearch = ref('')
const termFilters = computed(() => ({ title: termSearch.value }))
const termPagination = ref({ page: 1, perPage: 100 })
const { data: termsResponse } = useAdminTermsListQuery(termFilters, termPagination)
const termOptions = computed(() => termsResponse.value?.data ?? [])
const templateSearch = ref('')
const templateFilters = computed(() => ({ title: templateSearch.value }))
const templateFilters = computed(() => ({
title: templateSearch.value,
termId: form.value.termId || undefined,
}))
const templatePagination = ref({ page: 1, perPage: 10 })
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination)
const { data: templatesResponse } = useAdminCoursesListQuery(templateFilters, templatePagination, {
enabled: () => !!form.value.termId,
})
const templateOptions = computed(() => templatesResponse.value?.data ?? [])
const sessionSearch = ref('')
const sessionListFilters = computed(() => ({
title: sessionSearch.value,
courseId: form.value.courseId || undefined,
}))
const sessionPagination = ref({ page: 1, perPage: 10 })
const { data: sessionsResponse } = useAdminSessionsListQuery(
sessionListFilters,
sessionPagination,
{
enabled: () => !!form.value.courseId,
}
)
const sessionOptions = computed(() => sessionsResponse.value?.data ?? [])
const searchTerms = useDebounce((q) => {
termSearch.value = q || ''
}, 400)
const searchTemplates = useDebounce((q) => {
templateSearch.value = q || ''
}, 400)
const searchSessions = useDebounce((q) => {
sessionSearch.value = q || ''
}, 400)
const onTermChange = () => {
form.value.courseId = ''
form.value.sessionId = ''
}
const onCourseChange = () => {
form.value.sessionId = ''
}
const hasFilters = computed(() =>
Object.values(form.value).some((v) => v !== '' && v !== null && v !== undefined)
@@ -118,7 +199,11 @@ const onReset = () => {
gap: 0.5rem;
@media (min-width: 768px) {
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(3, 1fr);
}
@media (min-width: 1280px) {
grid-template-columns: repeat(6, 1fr);
}
}
@@ -259,8 +259,7 @@ const answerStateClass = (answerId, question) => {
display: flex;
flex-wrap: wrap;
align-items: center;
column-gap: 1.25rem;
row-gap: 0.5rem;
gap: 0.5rem 1.25rem;
color: #8e8e8e;
}
@@ -336,8 +335,7 @@ const answerStateClass = (answerId, question) => {
&__answers {
display: flex;
flex-wrap: wrap;
column-gap: 3rem;
row-gap: 1.25rem;
gap: 1.25rem 3rem;
}
&__answer {
@@ -134,7 +134,7 @@ const blankOption = () => ({ id: createId('option'), optionText: '', isCorrect:
const blankQuestion = () => ({
id: createId('question'),
questionText: '',
position: 1,
score: '',
options: [blankOption(), { ...blankOption(), id: createId('option') }],
__local: true,
})
@@ -172,7 +172,7 @@ const normalizeExistingQuestions = (raw = []) => {
return {
id: q.id ?? createId(`question-${qIdx}`),
questionText: q.questionText || '',
position: q.position ?? qIdx + 1,
score: q.score ?? '',
options: options.map((o, oIdx) => ({
id: o.id ?? createId(`option-${qIdx}-${oIdx}`),
optionText: o.optionText || '',
@@ -220,7 +220,8 @@ const validateLocalQuestions = () => {
questionError.value = ''
return localOnes.map((q, idx) => ({
questionText: q.questionText.trim(),
position: Number(q.position) || idx + 1,
position: idx + 1,
score: Number(q.score) || 0,
options: q.options
.filter((o) => String(o.optionText || '').trim())
.map((o) => ({
@@ -75,7 +75,14 @@ const router = useRouter()
const queryClient = useQueryClient()
const { openModal, isModal } = useModal()
const filters = ref({ title: '', courseId: '', fromDate: '', toDate: '' })
const filters = ref({
title: '',
termId: '',
courseId: '',
sessionId: '',
fromDate: '',
toDate: '',
})
const { pagination, setPage, reset: resetPagination } = usePagination({ page: 1, perPage: 10 })
const { data, isLoading } = useAdminExamsListQuery(filters, pagination, {
@@ -125,7 +125,7 @@ const onSubmit = (close) => {
}
&__divider {
border-block-end: 1px solid #dddddd;
border-block-end: 1px solid #ddd;
margin-block: 0.5rem;
}
@@ -80,7 +80,7 @@ const onSendMessage = (data) => {
}
&__divider {
border-block-end: 1px solid #dddddd;
border-block-end: 1px solid #ddd;
margin-block: 0.5rem;
}
@@ -90,7 +90,6 @@ import SvgIcon from '@/components/icons/SvgIcon.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import SelectField from '@/components/form/SelectField.vue'
import { usePagination } from '@/composables/usePagination'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import PaginationBlock from '@/components/blocks/PaginationBlock.vue'
import { useAdminTermsListQuery } from '@/services/query/admin-terms'
import { useAdminCoursesListQuery } from '@/services/query/admin-courses'
@@ -125,9 +125,7 @@ const contentType = computed(() => collectionToContentType(contentMedia.value?.c
const contentTypeLabel = computed(() => COURSE_CONTENT_TYPE[contentType.value] || '—')
const mediaUrl = computed(
() => contentMedia.value?.url || contentMedia.value?.downloadUrl || ''
)
const mediaUrl = computed(() => contentMedia.value?.url || contentMedia.value?.downloadUrl || '')
const mediaFileName = computed(() => contentMedia.value?.fileName || 'فایل پیوست')
</script>
@@ -34,9 +34,9 @@
<div class="add-term-student__text">
<p class="add-term-student__name">{{ userLabel(user) }}</p>
<p class="add-term-student__meta">
<span>{{ user.address?.province?.name || '—' }}</span>
<span>{{ user?.province?.name || '—' }}</span>
<span class="add-term-student__sep">،</span>
<span>{{ user.address?.city?.name || '—' }}</span>
<span>{{ user?.city?.name || '—' }}</span>
</p>
</div>
</div>
@@ -46,11 +46,11 @@
<LineInfoBlock title="کد ملی" :numeric-desc="user.nationalCode || ''" />
<LineInfoBlock title="وضعیت تاهل" :desc="MARITAL_STATUS[user.maritalStatus] || '—'" />
<LineInfoBlock title="جنسیت" :desc="GENDER[user.gender] || '—'" />
<LineInfoBlock title="استان" :desc="user.address?.province?.name || '—'" />
<LineInfoBlock title="شهر" :desc="user.address?.city?.name || '—'" />
<LineInfoBlock title="استان" :desc="user?.province?.name || '—'" />
<LineInfoBlock title="شهر" :desc="user?.city?.name || '—'" />
</div>
<LineInfoBlock title="آدرس" :desc="user.address?.address || '—'" />
<LineInfoBlock title="آدرس" :desc="user?.address || '—'" />
<LineInfoBlock title="بیوگرافی" :desc="user.bio || '—'" />
</div>
@@ -10,9 +10,9 @@
<div class="verification-item__info">
<p class="verification-item__name">{{ fullName }}</p>
<p class="verification-item__location">
<span>{{ user.address?.province?.name || '—' }}</span>
<span>{{ user?.province?.name || '—' }}</span>
<span class="verification-item__sep">،</span>
<span>{{ user.address?.city?.name || '—' }}</span>
<span>{{ user?.city?.name || '—' }}</span>
</p>
</div>
</div>
@@ -26,10 +26,10 @@
:desc="profile.faMaritalStatus || MARITAL_STATUS[profile.maritalStatus] || ''"
/>
<LineInfoBlock title="جنسیت" :desc="profile.faGender || GENDER[profile.gender] || ''" />
<LineInfoBlock title="استان" :desc="user.address?.province?.name || '-'" />
<LineInfoBlock title="شهر" :desc="user.address?.city?.name || '-'" />
<LineInfoBlock title="استان" :desc="user?.province?.name || '-'" />
<LineInfoBlock title="شهر" :desc="user?.city?.name || '-'" />
<div class="user-verification-details__cell user-verification-details__cell--span-3">
<LineInfoBlock title="آدرس" :desc="user.address?.address || '-'" />
<LineInfoBlock title="آدرس" :desc="user?.address || '-'" />
</div>
</div>
</section>
@@ -247,7 +247,6 @@ import {
SEMINARY_LEVEL,
SESSION_CANCELLATION_RESPONSE,
UNIVERSITY_LEVEL,
USER_STATUS,
VERIFICATION_MEDIA_TYPE,
} from '@/enums'
@@ -231,9 +231,9 @@ import LineTitleBlock from '@/components/LineTitleBlock.vue'
import ImageCropper from '@/components/form/ImageCropper.vue'
import { GENDER, MARITAL_STATUS, ROLE_LABELS } from '@/enums'
import { objectToFormData } from '@/utils/object-to-formdata'
import { useUploadMediaMutation } from '@/services/query/auth'
import TextareaField from '@/components/form/TextareaField.vue'
import PasswordField from '@/components/form/PasswordField.vue'
import { useUploadMediaMutation } from '@/services/query/auth'
import DatePickerField from '@/components/form/DatePickerField.vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
@@ -337,9 +337,9 @@ watch(existingUser, (user) => {
gender: user.profile?.gender || '',
bio: user.profile?.bio || '',
phoneNumber: user.phoneNumber || '',
provinceId: user.address?.province?.id || '',
cityId: user.address?.city?.id || '',
address: user.address?.address || '',
provinceId: user?.province?.id || '',
cityId: user?.city?.id || '',
address: user?.address || '',
avatarId: user.profile?.avatarId || null,
}
initialNationalCode.value = user.nationalCode || ''
@@ -111,11 +111,11 @@ import TextareaField from '@/components/form/TextareaField.vue'
import { useSaveRegisterDataMutation } from '@/services/query/auth'
import StepActions from '@/features/auth/components/studentRegister/StepActions.vue'
import { educationalInformationSchema } from '@/features/auth/schema/student-register'
import { EDUCATION_STATUS, SEMINARY_LEVEL, STUDENT_REGISTRATION, UNIVERSITY_LEVEL } from '@/enums'
import {
toKeyValueList,
useStudentRegistrationStore,
} from '@/features/auth/store/student-registration'
import { EDUCATION_STATUS, SEMINARY_LEVEL, STUDENT_REGISTRATION, UNIVERSITY_LEVEL } from '@/enums'
const store = useStudentRegistrationStore()
@@ -113,8 +113,8 @@ import SelectField from '@/components/form/SelectField.vue'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import TextareaField from '@/components/form/TextareaField.vue'
import { PROPAGATION_PLATFORM, STUDENT_REGISTRATION } from '@/enums'
import { useSaveRegisterDataMutation } from '@/services/query/auth'
import { PROPAGATION_PLATFORM, STUDENT_REGISTRATION } from '@/enums'
import StepActions from '@/features/auth/components/studentRegister/StepActions.vue'
import { professionalInformationSchema } from '@/features/auth/schema/student-register'
import {
@@ -37,11 +37,12 @@
</template>
<script setup>
import { computed, ref } from 'vue'
import { toast } from 'vue3-toastify'
import useYup from '@/composables/useYup'
import { computed, ref } from 'vue'
import { STUDENT_REGISTRATION } from '@/enums'
import LineTitleBlock from '@/components/LineTitleBlock.vue'
import { useSaveRegisterDataMutation } from '@/services/query/auth'
import StepActions from '@/features/auth/components/studentRegister/StepActions.vue'
import { skillAssessmentPart7Schema } from '@/features/auth/schema/student-register'
import MediaRecorder from '@/features/auth/components/studentRegister/MediaRecorder.vue'
@@ -49,7 +50,6 @@ import {
toKeyValueList,
useStudentRegistrationStore,
} from '@/features/auth/store/student-registration'
import { useSaveRegisterDataMutation } from '@/services/query/auth'
const store = useStudentRegistrationStore()
@@ -251,7 +251,7 @@ export const useStudentRegistrationStore = defineStore('studentRegistration', ()
Object.entries(flat).forEach(([key, value]) => {
const section = FIELD_TO_SECTION[key]
if (!section) return
buckets[section] = { ...(buckets[section] || {}), [key]: value }
buckets[section] = { ...buckets[section], [key]: value }
})
Object.entries(buckets).forEach(([section, patch]) => {
const target = sectionRefs[section]
@@ -35,12 +35,12 @@
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import { useStudentExamQuery } from '@/services/query/student-exams'
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import SimpleTitleIconBlock from '@/components/blocks/SimpleTitleIconBlock.vue'
import StudentExamSummary from '@/features/student/exams/components/StudentExamSummary.vue'
import StudentExamAttemptItem from '@/features/student/exams/components/StudentExamAttemptItem.vue'
import { useStudentExamQuery } from '@/services/query/student-exams'
const route = useRoute()
const router = useRouter()
@@ -295,7 +295,10 @@ const { data: profile } = useGetMeQuery()
watch(profile, (user) => {
if (!user) return
const nameParts = String(user.name || '').trim().split(/\s+/).filter(Boolean)
const nameParts = String(user.name || '')
.trim()
.split(/\s+/)
.filter(Boolean)
const firstName = user.firstName || nameParts[0] || ''
const lastName = user.lastName || nameParts.slice(1).join(' ') || ''
const phone = user.phone || user.phoneNumber || ''
@@ -309,9 +312,9 @@ watch(profile, (user) => {
gender: user.profile?.gender || '',
bio: user.profile?.bio || '',
phoneNumber: phone,
provinceId: user.address?.province?.id || '',
cityId: user.address?.city?.id || '',
address: user.address?.address || '',
provinceId: user?.province?.id || '',
cityId: user?.city?.id || '',
address: user?.address || '',
avatarId: user.profile?.avatarId || null,
}
initialNationalCode.value = user.nationalCode || ''
@@ -108,10 +108,10 @@ import BaseButton from '@/components/BaseButton.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import TabsBlock from '@/components/blocks/TabsBlock.vue'
import { objectToFormData } from '@/utils/object-to-formdata'
import { useUploadMediaMutation } from '@/services/query/auth'
import VoiceRecorder from '@/components/form/VoiceRecorder.vue'
import ImageUploader from '@/components/form/ImageUploader.vue'
import VideoPlayerBlock from '@/components/blocks/VideoPlayerBlock.vue'
import { useUploadMediaMutation } from '@/services/query/auth'
import BoxedIconTitleBlock from '@/components/blocks/BoxedIconTitleBlock.vue'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import {
@@ -5,10 +5,7 @@
</div>
<div class="student-term-summary__info">
<div
class="student-term-summary__status"
:class="`student-term-summary__status--${status}`"
>
<div class="student-term-summary__status" :class="`student-term-summary__status--${status}`">
<span class="student-term-summary__status-label">وضعیت دوره :</span>
<span class="student-term-summary__status-value">{{ statusLabel }}</span>
</div>
+29 -33
View File
@@ -1,35 +1,31 @@
// //tinymce
// import tinymce from "tinymce/tinymce";
import "tinymce/tinymce";
import "tinymce/themes/silver";
import "tinymce/icons/default";
import "tinymce/skins/ui/oxide/skin.css";
// Vue.use(tinymce);
// skin css /lightgray/skin.min.css
import "tinymce/skins/ui/oxide/content.min.css";
import "tinymce/skins/ui/oxide/skin.min.css";
// //plugins
import "tinymce/plugins/textcolor";
import "tinymce/plugins/colorpicker";
import "tinymce/plugins/advlist";
import "tinymce/plugins/autolink";
import "tinymce/plugins/lists";
import "tinymce/plugins/paste";
import "tinymce/plugins/link";
import "tinymce/plugins/preview";
import "tinymce/plugins/anchor";
import "tinymce/plugins/charmap";
import "tinymce/plugins/print";
import "tinymce/plugins/image";
import "tinymce/plugins/searchreplace";
import "tinymce/plugins/directionality";
import "tinymce/plugins/wordcount";
// import "tinymce/plugins/help";
import "tinymce/plugins/table";
import "tinymce/plugins/media";
import "tinymce/plugins/insertdatetime";
import "tinymce/plugins/fullscreen";
import "tinymce/plugins/code";
import "tinymce/plugins/visualblocks";
import "@/plugins/tinymce/langs/fa_IR";
import "@/styles/plugins/tinymce.css";
import 'tinymce/tinymce'
import 'tinymce/plugins/link'
import 'tinymce/plugins/code'
import 'tinymce/themes/silver'
import 'tinymce/icons/default'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/paste'
import 'tinymce/plugins/print'
import 'tinymce/plugins/image'
import 'tinymce/plugins/table'
import 'tinymce/plugins/media'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/charmap'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/textcolor'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/colorpicker'
import 'tinymce/plugins/visualblocks'
import '@/styles/plugins/tinymce.css'
import 'tinymce/plugins/searchreplace'
import '@/plugins/tinymce/langs/fa_IR'
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/skins/ui/oxide/skin.css'
import 'tinymce/skins/ui/oxide/skin.min.css'
import 'tinymce/skins/ui/oxide/content.min.css'
+471 -391
View File
@@ -1,392 +1,472 @@
import tinymce from "tinymce/tinymce";
import tinymce from 'tinymce/tinymce'
tinymce.addI18n('fa_IR',{
"Redo": "\u0628\u0627\u0632\u0627\u0646\u062c\u0627\u0645",
"Undo": "\u0648\u0627\u06af\u0631\u062f",
"Cut": "\u0628\u0631\u0634",
"Copy": "\u06a9\u067e\u06cc",
"Paste": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646",
"Select all": "\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u0645\u0647",
"New document": "\u0633\u0646\u062f \u062c\u062f\u06cc\u062f",
"Ok": "\u062a\u0623\u06cc\u06cc\u062f",
"Cancel": "\u0644\u063a\u0648",
"Visual aids": "\u06a9\u0645\u06a9\u200c\u0647\u0627\u06cc \u0628\u0635\u0631\u06cc",
"Bold": "\u067e\u0631\u0631\u0646\u06af",
"Italic": "\u06a9\u062c",
"Underline": "\u0632\u06cc\u0631 \u062e\u0637 \u062f\u0627\u0631",
"Strikethrough": "\u062e\u0637 \u0632\u062f\u0646",
"Superscript": "\u0628\u0627\u0644\u0627\u0646\u06af\u0627\u0634\u062a",
"Subscript": "\u0632\u06cc\u0631\u0646\u06af\u0627\u0634\u062a",
"Clear formatting": "\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0642\u0627\u0644\u0628\u200c\u0628\u0646\u062f\u06cc",
"Align left": "\u062a\u0631\u0627\u0632\u0628\u0646\u062f\u06cc \u0627\u0632 \u0686\u067e",
"Align center": "\u062a\u0631\u0627\u0632\u0628\u0646\u062f\u06cc \u0627\u0632 \u0648\u0633\u0637",
"Align right": "\u062a\u0631\u0627\u0632\u0628\u0646\u062f\u06cc \u0627\u0632 \u0631\u0627\u0633\u062a",
"Justify": "\u062a\u0631\u0627\u0632\u0628\u0646\u062f\u06cc \u062f\u0648\u0637\u0631\u0641\u0647",
"Bullet list": "\u0641\u0647\u0631\u0633\u062a \u0646\u0634\u0627\u0646\u0647\u200c\u062f\u0627\u0631",
"Numbered list": "\u0641\u0647\u0631\u0633\u062a \u0634\u0645\u0627\u0631\u0647\u200c\u062f\u0627\u0631",
"Decrease indent": "\u06a9\u0627\u0647\u0634 \u062a\u0648\u0631\u0641\u062a\u06af\u06cc",
"Increase indent": "\u0627\u0641\u0632\u0627\u06cc\u0634 \u062a\u0648\u0631\u0641\u062a\u06af\u06cc",
"Close": "\u0628\u0633\u062a\u0646",
"Formats": "\u0642\u0627\u0644\u0628\u200c\u0628\u0646\u062f\u06cc\u200c\u0647\u0627",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0627\u0632 \u062f\u0633\u062a\u0631\u0633\u06cc \u0645\u0633\u062a\u0642\u06cc\u0645 \u0628\u0647 \u06a9\u0644\u06cc\u067e\u200c\u0628\u0648\u0631\u062f \u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc \u0646\u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0644\u0637\u0641\u0627\u064b \u0627\u0632 \u0645\u06cc\u0627\u0646\u0628\u0631\u0647\u0627\u06cc Ctrl+X\/C\/V \u0635\u0641\u062d\u0647 \u06a9\u0644\u06cc\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0646\u06cc\u062f.",
"Headers": "\u0633\u0631\u0628\u0631\u06af\u200c\u0647\u0627",
"Header 1": "\u0633\u0631\u0628\u0631\u06af 1",
"Header 2": "\u0633\u0631\u0628\u0631\u06af 2",
"Header 3": "\u0633\u0631\u0628\u0631\u06af 3",
"Header 4": "\u0633\u0631\u0628\u0631\u06af 4",
"Header 5": "\u0633\u0631\u0628\u0631\u06af 5",
"Header 6": "\u0633\u0631\u0628\u0631\u06af 6",
"Headings": "\u0633\u0631\u0641\u0635\u0644\u200c\u0647\u0627",
"Heading 1": "\u0633\u0631\u0641\u0635\u0644\u200c 1",
"Heading 2": "\u0633\u0631\u0641\u0635\u0644 2",
"Heading 3": "\u0633\u0631\u0641\u0635\u0644 3",
"Heading 4": "\u0633\u0631\u0641\u0635\u0644 4",
"Heading 5": "\u0633\u0631\u0641\u0635\u0644 5",
"Heading 6": "\u0633\u0631\u0641\u0635\u0644 6",
"Preformatted": "\u0627\u0632 \u067e\u06cc\u0634 \u0642\u0627\u0644\u0628\u200c\u0628\u0646\u062f\u06cc\u200c\u0634\u062f\u0647",
"Div": "\u0628\u062e\u0634",
"Pre": "\u067e\u06cc\u0634",
"Code": "\u06a9\u062f",
"Paragraph": "\u067e\u0627\u0631\u0627\u06af\u0631\u0627\u0641",
"Blockquote": "\u0646\u0642\u0644 \u0642\u0648\u0644 \u0628\u0644\u0648\u06a9\u06cc",
"Inline": "\u0647\u0645\u200c\u0631\u0627\u0633\u062a\u0627",
"Blocks": "\u0628\u0644\u0648\u06a9\u200c\u0647\u0627",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u0627\u0645\u06a9\u0627\u0646 \u0686\u0633\u0628\u0627\u0646\u062f\u0646\u060c \u062f\u0631 \u062d\u0627\u0644\u062a \u0645\u062a\u0646 \u062e\u0627\u0644\u0635 \u062a\u0646\u0638\u06cc\u0645 \u06af\u0634\u062a\u0647. \u062a\u0627 \u0632\u0645\u0627\u0646 \u062a\u063a\u06cc\u06cc\u0631 \u0627\u06cc\u0646 \u062d\u0627\u0644\u062a\u060c \u0645\u062d\u062a\u0648\u0627\u06cc \u0645\u0648\u0631\u062f \u0686\u0633\u0628\u0627\u0646\u062f\u0646\u060c \u0628\u0647 \u0635\u0648\u0631\u062a \u0645\u062a\u0646 \u062e\u0627\u0644\u0635 \u062e\u0648\u0627\u0647\u062f \u0686\u0633\u0628\u06cc\u062f.",
"Fonts": "\u0641\u0648\u0646\u062a\u200c\u200c\u0647\u0627",
"Font Sizes": "\u0627\u0646\u062f\u0627\u0632\u0647\u0654 \u0641\u0648\u0646\u062a",
"Class": "\u0637\u0628\u0642\u0647",
"Browse for an image": "\u06af\u0634\u062a\u0646 \u0628\u0631\u0627\u06cc \u0639\u06a9\u0633 \u0645\u0648\u0631\u062f \u0646\u0638\u0631",
"OR": "\u06cc\u0627",
"Drop an image here": "\u062a\u0635\u0648\u06cc\u0631 \u0645\u0648\u0631\u062f \u0646\u0638\u0631 \u0631\u0627 \u0627\u06cc\u0646\u062c\u0627 \u0631\u0647\u0627 \u06a9\u0646\u06cc\u062f",
"Upload": "\u0622\u067e\u0644\u0648\u062f",
"Block": "\u0628\u0644\u0648\u06a9",
"Align": "\u062a\u0631\u0627\u0632\u0628\u0646\u062f\u06cc",
"Default": "\u067e\u06cc\u0634 \u0641\u0631\u0636",
"Circle": "\u062f\u0627\u06cc\u0631\u0647",
"Disc": "\u062f\u0627\u06cc\u0631\u0647\u0621 \u062a\u0648\u067e\u0631",
"Square": "\u0686\u0647\u0627\u0631 \u06af\u0648\u0634",
"Lower Alpha": "\u062d\u0631\u0648\u0641 \u06a9\u0648\u0686\u06a9",
"Lower Greek": "\u062d\u0631\u0648\u0641 \u06a9\u0648\u0686\u06a9 \u06cc\u0648\u0646\u0627\u0646\u06cc",
"Lower Roman": "\u0627\u0631\u0642\u0627\u0645 \u06a9\u0648\u0686\u06a9 \u0631\u0648\u0645\u06cc",
"Upper Alpha": "\u062d\u0631\u0648\u0641 \u0628\u0632\u0631\u06af",
"Upper Roman": "\u0627\u0631\u0642\u0627\u0645 \u0628\u0632\u0631\u06af \u0631\u0648\u0645\u06cc",
"Anchor...": "\u0642\u0644\u0627\u0628...",
"Name": "\u0646\u0627\u0645",
"Id": "\u0634\u0646\u0627\u0633\u0647",
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u0634\u0646\u0627\u0633\u0647 \u0645\u06cc \u0628\u0627\u06cc\u0633\u062a \u0628\u0627 \u06cc\u06a9 \u062d\u0631\u0641 \u0627\u0644\u0641\u0628\u0627 \u0622\u063a\u0627\u0632 \u0648 \u0628\u0627 \u062f\u0646\u0628\u0627\u0644\u0647 \u0627\u06cc \u0627\u0632 \u062d\u0631\u0648\u0641\u060c \u0627\u0639\u062f\u0627\u062f\u060c \u0639\u0644\u0627\u0645\u062a \u0645\u0650\u0646\u0647\u0627\u060c \u0646\u0642\u0637\u0647\u060c \u062f\u0648 \u0646\u0642\u0637\u0647 \u06cc\u0627 \u062e\u0637 \u062a\u06cc\u0631\u0647 \u0627\u062f\u0627\u0645\u0647 \u06cc\u0627\u0628\u062f.",
"You have unsaved changes are you sure you want to navigate away?": "\u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0634\u0645\u0627 \u0630\u062e\u06cc\u0631\u0647 \u0646\u0634\u062f\u0647 \u0627\u0646\u062f\u060c \u0622\u06cc\u0627 \u062c\u0647\u062a \u062e\u0631\u0648\u062c \u0627\u0637\u0645\u06cc\u0646\u0627\u0646 \u062f\u0627\u0631\u06cc\u062f\u061f",
"Restore last draft": "\u0628\u0627\u0632\u06cc\u0627\u0628\u06cc \u0622\u062e\u0631\u06cc\u0646 \u067e\u06cc\u0634 \u0646\u0648\u06cc\u0633",
"Special characters...": "\u0646\u0648\u06cc\u0633\u0647\u200c\u0647\u0627\u06cc \u0648\u06cc\u0698\u0647...",
"Source code": "\u0645\u062a\u0646 \u06a9\u062f \u0645\u0646\u0628\u0639",
"Insert\/Edit code sample": "\u062f\u0631\u062c\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0646\u0645\u0648\u0646\u0647\u0621 \u06a9\u062f",
"Language": "\u0632\u0628\u0627\u0646",
"Code sample...": "\u0646\u0645\u0648\u0646\u0647 \u06a9\u062f...",
"Color Picker": "\u0627\u0646\u062a\u062e\u0627\u0628\u200c\u06a9\u0646\u0646\u062f\u0647 \u0631\u0646\u06af",
"R": "\u0642\u0631\u0645\u0632",
"G": "\u0633\u0628\u0632",
"B": "\u0622\u0628\u06cc",
"Left to right": "\u0686\u067e \u0628\u0647 \u0631\u0627\u0633\u062a",
"Right to left": "\u0631\u0627\u0633\u062a \u0628\u0647 \u0686\u067e",
"Emoticons...": "\u0635\u0648\u0631\u062a\u06a9\u200c\u0647\u0627...",
"Metadata and Document Properties": "\u0641\u0631\u0627\u062f\u0627\u062f\u0647 \u0648 \u0645\u0634\u062e\u0635\u0627\u062a \u0633\u0646\u062f",
"Title": "\u0639\u0646\u0648\u0627\u0646",
"Keywords": "\u0648\u0627\u0698\u06af\u0627\u0646 \u06a9\u0644\u06cc\u062f\u06cc",
"Description": "\u062a\u0648\u0636\u06cc\u062d",
"Robots": "\u0631\u0648\u0628\u0627\u062a\u0647\u0627",
"Author": "\u0645\u0648\u0644\u0641",
"Encoding": "\u06a9\u062f\u06af\u0632\u0627\u0631\u06cc \u0645\u062a\u0646",
"Fullscreen": "\u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647",
"Action": "\u0639\u0645\u0644",
"Shortcut": "\u0645\u06cc\u0627\u0646\u0628\u064f\u0631",
"Help": "\u0631\u0627\u0647\u0646\u0645\u0627",
"Address": "\u0646\u0634\u0627\u0646\u06cc",
"Focus to menubar": "\u062a\u0645\u0631\u06a9\u0632 \u0628\u0631 \u0646\u0648\u0627\u0631 \u0645\u0646\u0648",
"Focus to toolbar": "\u062a\u0645\u0631\u06a9\u0632 \u0628\u0631 \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631",
"Focus to element path": "\u062a\u0645\u0631\u06a9\u0632 \u0628\u0631 \u0645\u0633\u06cc\u0631 \u0627\u0650\u0644\u0650\u0645\u0627\u0646",
"Focus to contextual toolbar": "\u062a\u0645\u0631\u06a9\u0632 \u0628\u0631 \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631 \u0645\u062a\u0646\u06cc",
"Insert link (if link plugin activated)": "\u062f\u0631\u062c \u067e\u06cc\u0648\u0646\u062f (\u0627\u06af\u0631 \u0627\u0641\u0632\u0648\u0646\u0647\u0621 \u067e\u06cc\u0648\u0646\u062f \u0641\u0639\u0627\u0644 \u0634\u062f)",
"Save (if save plugin activated)": "\u062b\u0628\u062a\u00a0(\u0627\u06af\u0631 \u0627\u0641\u0632\u0648\u0646\u0647\u0621 \u0630\u062e\u06cc\u0631\u0647 \u0633\u0627\u0632\u06cc \u0641\u0639\u0627\u0644 \u0634\u062f)",
"Find (if searchreplace plugin activated)": "\u06cc\u0627\u0641\u062a\u0646 (\u0627\u06af\u0631 \u0627\u0641\u0632\u0648\u0646\u0647\u0621 \u062c\u0633\u062a\u062c\u0648\/\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc \u0641\u0639\u0627\u0644 \u0634\u062f)",
"Plugins installed ({0}):": "\u0627\u0641\u0632\u0648\u0646\u0647 \u0647\u0627\u06cc\u06cc \u06a9\u0647 \u0646\u0635\u0628 \u0634\u062f\u0646\u062f ({0}):",
"Premium plugins:": "\u0627\u0641\u0632\u0648\u0646\u0647 \u0647\u0627\u06cc \u0645\u062e\u0635\u0648\u0635:",
"Learn more...": "\u06cc\u0627\u062f\u06af\u06cc\u0631\u06cc \u0628\u06cc\u0634\u062a\u0631...",
"You are using {0}": "\u0634\u0645\u0627 \u062f\u0631 \u062d\u0627\u0644 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 {0} \u0645\u06cc \u0628\u0627\u0634\u06cc\u062f",
"Plugins": "\u0627\u0641\u0632\u0648\u0646\u0647 \u0647\u0627",
"Handy Shortcuts": "\u0645\u06cc\u0627\u0646\u0628\u064f\u0631\u0647\u0627\u06cc \u0633\u0648\u062f\u0645\u0646\u062f",
"Horizontal line": "\u062e\u0637 \u0627\u0641\u0642\u06cc",
"Insert\/edit image": "\u062f\u0631\u062c\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u062a\u0635\u0648\u06cc\u0631",
"Image description": "\u062a\u0648\u0635\u06cc\u0641 \u062a\u0635\u0648\u06cc\u0631",
"Source": "\u0645\u0646\u0628\u0639",
"Dimensions": "\u0627\u0628\u0639\u0627\u062f",
"Constrain proportions": "\u062d\u0641\u0638 \u062a\u0646\u0627\u0633\u0628",
"General": "\u0639\u0645\u0648\u0645\u06cc",
"Advanced": "\u067e\u06cc\u0634\u0631\u0641\u062a\u0647",
"Style": "\u0633\u0628\u06a9",
"Vertical space": "\u0641\u0636\u0627\u06cc \u0639\u0645\u0648\u062f\u06cc",
"Horizontal space": "\u0641\u0636\u0627\u06cc \u0627\u0641\u0642\u06cc",
"Border": "\u0644\u0628\u0647",
"Insert image": "\u062f\u0631\u062c \u062a\u0635\u0648\u06cc\u0631",
"Image...": "\u062a\u0635\u0648\u06cc\u0631...",
"Image list": "\u0641\u0647\u0631\u0633\u062a \u062a\u0635\u0648\u06cc\u0631\u06cc",
"Rotate counterclockwise": "\u062f\u064e\u0648\u064e\u0631\u0627\u0646 \u067e\u0627\u062f \u0633\u0627\u0639\u062a \u06af\u0631\u062f",
"Rotate clockwise": "\u062f\u064e\u0648\u064e\u0631\u0627\u0646 \u0633\u0627\u0639\u062a \u06af\u0631\u062f",
"Flip vertically": "\u0642\u0631\u06cc\u0646\u0647 \u0639\u0645\u0648\u062f\u06cc",
"Flip horizontally": "\u0642\u0631\u06cc\u0646\u0647 \u0627\u0641\u0642\u06cc",
"Edit image": "\u0648\u06cc\u0631\u0627\u0633\u062a \u062a\u0635\u0648\u06cc\u0631",
"Image options": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u062a\u0635\u0648\u06cc\u0631",
"Zoom in": "\u0628\u0632\u0631\u06af \u0646\u0645\u0627\u06cc\u06cc",
"Zoom out": "\u06a9\u0648\u0686\u06a9 \u0646\u0645\u0627\u06cc\u06cc",
"Crop": "\u0628\u064f\u0631\u0634 \u062f\u064f\u0648\u0631",
"Resize": "\u062a\u063a\u06cc\u06cc\u0631 \u0627\u0646\u062f\u0627\u0632\u0647",
"Orientation": "\u06af\u0650\u0631\u0627",
"Brightness": "\u0631\u0648\u0634\u0646\u0627\u06cc\u06cc",
"Sharpen": "\u0628\u0647\u0628\u0648\u062f \u0644\u0628\u0647",
"Contrast": "\u062a\u0636\u0627\u062f \u0631\u0646\u06af",
"Color levels": "\u0633\u0637\u0648\u062d \u0631\u0646\u06af",
"Gamma": "\u06af\u0627\u0645\u0627",
"Invert": "\u0628\u0631\u06af\u0634\u062a \u0631\u0646\u06af",
"Apply": "\u0627\u0650\u0639\u0645\u0627\u0644",
"Back": "\u0628\u0627\u0632\u06af\u0634\u062a",
"Insert date\/time": "\u062f\u0631\u062c \u062a\u0627\u0631\u06cc\u062e\/\u0632\u0645\u0627\u0646",
"Date\/time": "\u062a\u0627\u0631\u06cc\u062e\/\u0632\u0645\u0627\u0646",
"Insert\/Edit Link": "\u062f\u0631\u062c\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u067e\u06cc\u0648\u0646\u062f",
"Insert\/edit link": "\u062f\u0631\u062c\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u067e\u06cc\u0648\u0646\u062f",
"Text to display": "\u0645\u062a\u0646 \u0646\u0645\u0627\u06cc\u0634\u06cc",
"Url": "\u0622\u062f\u0631\u0633",
"Open link in...": "\u0628\u0627\u0632 \u06a9\u0631\u062f\u0646 \u067e\u06cc\u0648\u0646\u062f \u062f\u0631...",
"Current window": "\u067e\u0646\u062c\u0631\u0647 \u062c\u0627\u0631\u06cc",
"None": "\u0647\u06cc\u0686",
"New window": "\u067e\u0646\u062c\u0631\u0647\u0621 \u062c\u062f\u06cc\u062f",
"Remove link": "\u062d\u0630\u0641 \u067e\u06cc\u0648\u0646\u062f",
"Anchors": "\u0642\u0644\u0627\u0628 \u0647\u0627",
"Link...": "\u067e\u06cc\u0648\u0646\u062f...",
"Paste or type a link": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u06cc\u0627 \u062a\u0627\u06cc\u067e \u067e\u06cc\u0648\u0646\u062f",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u0628\u0647 \u0646\u0638\u0631 \u0645\u06cc \u0631\u0633\u062f \u0622\u062f\u0631\u0633 \u0648\u0631\u0648\u062f\u06cc \u06cc\u06a9 \u0631\u0627\u06cc\u0627\u0646\u0627\u0645\u0647 \u0628\u0627\u0634\u062f. \u0622\u06cc\u0627 \u062a\u0645\u0627\u06cc\u0644 \u0628\u0647 \u0627\u0641\u0632\u0648\u0631\u062f\u0646 \u067e\u06cc\u0634\u0648\u0646\u062f mailto: \u062f\u0627\u0631\u06cc\u062f\u061f",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u0628\u0647 \u0646\u0638\u0631 \u0645\u06cc \u0631\u0633\u062f \u0622\u062f\u0631\u0633 \u0648\u0631\u0648\u062f\u06cc \u0627\u0631\u062c\u0627\u0639\u06cc \u0628\u0647 \u062e\u0627\u0631\u062c \u0627\u0632 \u0627\u06cc\u0646 \u0633\u0627\u06cc\u062a \u0645\u06cc \u0628\u0627\u0634\u062f. \u0622\u06cc\u0627 \u062a\u0645\u0627\u06cc\u0644 \u0628\u0647 \u0627\u0641\u0632\u0648\u0631\u062f\u0646 \u067e\u06cc\u0634\u0648\u0646\u062f http:\/\/ \u062f\u0627\u0631\u06cc\u062f\u061f",
"Link list": "\u0641\u0647\u0631\u0633\u062a \u067e\u06cc\u0648\u0646\u062f",
"Insert video": "\u062f\u0631\u062c \u0648\u06cc\u062f\u06cc\u0648",
"Insert\/edit video": "\u062f\u0631\u062c\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0648\u06cc\u062f\u06cc\u0648",
"Insert\/edit media": "\u062f\u0631\u062c\/\u0648\u06cc\u0631\u0627\u06cc\u0634 \u0631\u0633\u0627\u0646\u0647",
"Alternative source": "\u0645\u0646\u0628\u0639 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646",
"Alternative source URL": "\u0646\u0634\u0627\u0646\u06cc \u0648\u0628 \u0645\u0646\u0628\u0639 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646",
"Media poster (Image URL)": "\u067e\u0648\u0633\u062a\u0631 \u0631\u0633\u0627\u0646\u0647 (\u0646\u0634\u0627\u0646\u06cc \u0648\u0628 \u062a\u0635\u0648\u06cc\u0631)",
"Paste your embed code below:": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u06a9\u062f \u062c\u0627\u0633\u0627\u0632\u06cc \u0634\u0645\u0627 \u062f\u0631 \u0632\u06cc\u0631: ",
"Embed": "\u062c\u0627\u0633\u0627\u0632\u06cc",
"Media...": "\u0631\u0633\u0627\u0646\u0647...",
"Nonbreaking space": "\u0641\u0636\u0627\u06cc \u062e\u0627\u0644\u06cc \u0628\u0631\u0634 \u0646\u0627\u067e\u0630\u06cc\u0631",
"Page break": "\u0628\u0631\u0634 \u0635\u0641\u062d\u0647",
"Paste as text": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0645\u062a\u0646",
"Preview": "\u067e\u06cc\u0634 \u0646\u0645\u0627\u06cc\u0634",
"Print...": "\u0686\u0627\u067e...",
"Save": "\u0630\u062e\u06cc\u0631\u0647",
"Find": "\u062c\u0633\u062a\u062c\u0648",
"Replace with": "\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc \u0628\u0627",
"Replace": "\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc",
"Replace all": "\u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u0647\u0645\u0647",
"Previous": "\u0642\u0628\u0644\u06cc",
"Next": "\u0628\u0639\u062f\u06cc",
"Find and replace...": "\u06cc\u0627\u0641\u062a\u0646 \u0648 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u06a9\u0631\u062f\u0646...",
"Could not find the specified string.": "\u0631\u0634\u062a\u0647\u0621 \u0645\u0648\u0631\u062f \u0646\u0638\u0631 \u06cc\u0627\u0641\u062a \u0646\u06af\u0631\u062f\u06cc\u062f.",
"Match case": "\u062a\u0637\u0627\u0628\u0642 \u062d\u0631\u0648\u0641",
"Find whole words only": "\u06cc\u0627\u0641\u062a\u0646 \u062f\u0642\u06cc\u0642\u0627\u064b \u06a9\u0644 \u0648\u0627\u0698\u0647",
"Spell check": "\u0628\u0631\u0631\u0633\u06cc \u0627\u0645\u0644\u0627",
"Ignore": "\u0628\u06cc \u062e\u06cc\u0627\u0644",
"Ignore all": "\u0628\u06cc \u062e\u06cc\u0627\u0644 \u0647\u0645\u0647",
"Finish": "\u0627\u062a\u0645\u0627\u0645",
"Add to Dictionary": "\u0628\u0647 \u0648\u0627\u0698\u0647 \u0646\u0627\u0645\u0647 \u0628\u06cc \u0627\u0641\u0632\u0627",
"Insert table": "\u062f\u0631\u062c \u062c\u062f\u0648\u0644",
"Table properties": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u062c\u062f\u0648\u0644",
"Delete table": "\u062d\u0630\u0641 \u062c\u062f\u0648\u0644",
"Cell": "\u0633\u0644\u0648\u0644",
"Row": "\u0633\u0637\u0631",
"Column": "\u0633\u062a\u0648\u0646",
"Cell properties": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0633\u0644\u0648\u0644",
"Merge cells": "\u067e\u06cc\u0648\u0646\u062f \u0633\u0644\u0648\u0644 \u0647\u0627",
"Split cell": "\u062c\u062f\u0627 \u0633\u0627\u0632\u06cc \u0633\u0644\u0648\u0644",
"Insert row before": "\u062f\u0631\u062c \u0633\u0637\u0631 \u062f\u0631 \u0628\u0627\u0644\u0627",
"Insert row after": "\u062f\u0631\u062c \u0633\u0637\u0631 \u062f\u0631 \u067e\u0627\u06cc\u06cc\u0646",
"Delete row": "\u062d\u0630\u0641 \u0633\u0637\u0631",
"Row properties": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0633\u0637\u0631",
"Cut row": "\u0628\u0631\u0634 \u0633\u0637\u0631",
"Copy row": "\u0631\u0648\u0646\u0648\u06cc\u0633\u06cc \u0633\u0637\u0631",
"Paste row before": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0633\u0637\u0631 \u062f\u0631 \u0628\u0627\u0644\u0627",
"Paste row after": "\u0686\u0633\u0628\u0627\u0646\u062f\u0646 \u0633\u0637\u0631 \u062f\u0631 \u067e\u0627\u06cc\u06cc\u0646",
"Insert column before": "\u062f\u0631\u062c \u0633\u062a\u0648\u0646 \u0642\u0628\u0644",
"Insert column after": "\u062f\u0631\u062c \u0633\u062a\u0648\u0646 \u0628\u0639\u062f",
"Delete column": "\u062d\u0630\u0641 \u0633\u062a\u0648\u0646",
"Cols": "\u0633\u062a\u0648\u0646 \u0647\u0627",
"Rows": "\u0633\u0637\u0631 \u0647\u0627",
"Width": "\u0639\u0631\u0636",
"Height": "\u0627\u0631\u062a\u0641\u0627\u0639",
"Cell spacing": "\u0641\u0627\u0635\u0644\u0647 \u0645\u06cc\u0627\u0646 \u0633\u0644\u0648\u0644\u06cc",
"Cell padding": "\u062d\u0627\u0634\u06cc\u0647 \u062f\u0631\u0648\u0646 \u0633\u0644\u0648\u0644\u06cc",
"Show caption": "\u0646\u0645\u0627\u06cc\u0634 \u0639\u0646\u0648\u0627\u0646",
"Left": "\u0686\u067e",
"Center": "\u0645\u06cc\u0627\u0646\u0647",
"Right": "\u0631\u0627\u0633\u062a",
"Cell type": "\u0646\u0648\u0639 \u0633\u0644\u0648\u0644",
"Scope": "\u062d\u0648\u0632\u0647",
"Alignment": "\u0647\u0645 \u062a\u0631\u0627\u0632\u06cc",
"H Align": "\u062a\u0631\u0627\u0632 \u0627\u0641\u0642\u06cc",
"V Align": "\u062a\u0631\u0627\u0632 \u0639\u0645\u0648\u062f\u06cc",
"Top": "\u0628\u0627\u0644\u0627",
"Middle": "\u0645\u06cc\u0627\u0646\u0647",
"Bottom": "\u067e\u0627\u06cc\u06cc\u0646",
"Header cell": "\u0633\u0644\u0648\u0644 \u0633\u0631 \u0633\u062a\u0648\u0646",
"Row group": "\u06af\u0631\u0648\u0647 \u0633\u0637\u0631\u06cc",
"Column group": "\u06af\u0631\u0648\u0647 \u0633\u062a\u0648\u0646\u06cc",
"Row type": "\u0646\u0648\u0639 \u0633\u0637\u0631",
"Header": "\u0633\u0631 \u0622\u0645\u062f",
"Body": "\u0628\u062f\u0646\u0647",
"Footer": "\u067e\u0627 \u0646\u0648\u0634\u062a",
"Border color": "\u0631\u0646\u06af \u0644\u0628\u0647",
"Insert template...": "\u062f\u0631\u062c \u0627\u0644\u06af\u0648...",
"Templates": "\u0627\u0644\u06af\u0648\u0647\u0627",
"Template": "\u0627\u0644\u06af\u0648",
"Text color": "\u0631\u0646\u06af \u0645\u062a\u0646",
"Background color": "\u0631\u0646\u06af \u067e\u0633 \u0632\u0645\u06cc\u0646\u0647",
"Custom...": "\u062f\u0644\u062e\u0648\u0627\u0647...",
"Custom color": "\u0631\u0646\u06af \u062f\u0644\u062e\u0648\u0627\u0647",
"No color": "\u0628\u062f\u0648\u0646 \u0631\u0646\u06af",
"Remove color": "\u062d\u0630\u0641 \u0631\u0646\u06af",
"Table of Contents": "\u0641\u0647\u0631\u0633\u062a \u0639\u0646\u0627\u0648\u06cc\u0646",
"Show blocks": "\u0646\u0645\u0627\u06cc\u0634 \u0628\u0644\u0648\u06a9 \u0647\u0627",
"Show invisible characters": "\u0646\u0645\u0627\u06cc\u0634 \u0646\u0648\u06cc\u0633\u0647 \u0647\u0627\u06cc \u0646\u0627\u067e\u06cc\u062f\u0627",
"Word count": "\u062a\u0639\u062f\u0627\u062f \u0648\u0627\u0698\u0647\u200c\u0647\u0627",
"Words: {0}": "\u0648\u0627\u0698\u0647 \u0647\u0627: {0}",
"{0} words": "{0} \u0648\u0627\u0698\u0647",
"File": "\u067e\u0631\u0648\u0646\u062f\u0647",
"Edit": "\u0648\u06cc\u0631\u0627\u06cc\u0634",
"Insert": "\u062f\u0631\u062c",
"View": "\u0646\u0645\u0627\u06cc\u0634",
"Format": "\u0642\u0627\u0644\u0628",
"Table": "\u062c\u062f\u0648\u0644",
"Tools": "\u0627\u0628\u0632\u0627\u0631\u0647\u0627",
"Powered by {0}": "\u062a\u0648\u0627\u0646 \u06af\u0631\u0641\u062a\u0647 \u0627\u0632 {0}",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u0646\u0627\u062d\u06cc\u0647 \u0645\u062a\u0646 \u063a\u0646\u06cc.\n\u062c\u0647\u062a \u0645\u0634\u0627\u0647\u062f\u0647 \u0645\u0646\u0648 \u0627\u0632 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc \u062a\u0631\u06a9\u06cc\u0628\u06cc ALT + F9 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u06cc\u06cc\u062f.\n\u062c\u0647\u062a \u0645\u0634\u0627\u0647\u062f\u0647 \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631 \u0627\u0632 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc \u062a\u0631\u06a9\u06cc\u0628\u06cc ALT + F10 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u06cc\u06cc\u062f.\n\u062c\u0647\u062a \u0645\u0634\u0627\u0647\u062f\u0647 \u0631\u0627\u0647\u0646\u0645\u0627 \u0627\u0632 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc \u062a\u0631\u06a9\u06cc\u0628\u06cc ALT + 0 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0646\u0645\u0627\u06cc\u06cc\u062f.",
"Image title": "\u0639\u0646\u0648\u0627\u0646 \u062a\u0635\u0648\u06cc\u0631",
"Border width": "\u0639\u0631\u0636 \u062d\u0627\u0634\u06cc\u0647",
"Border style": "\u0633\u0628\u06a9 \u062d\u0627\u0634\u06cc\u0647",
"Error": "\u062e\u0637\u0627",
"Warn": "\u0647\u0634\u062f\u0627\u0631",
"Valid": "\u0645\u0639\u062a\u0628\u0631",
"To open the popup, press Shift+Enter": "\u062c\u0647\u062a \u0628\u0627\u0632 \u06a9\u0631\u062f\u0646 \u067e\u0646\u062c\u0631\u0647 \u0628\u0627\u0632\u0634\u0648\u060c \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc Shift + Enter \u0631\u0627 \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f.",
"Rich Text Area. Press ALT-0 for help.": "\u0646\u0627\u062d\u06cc\u0647 \u0645\u062a\u0646 \u063a\u0646\u06cc. \u062c\u0647\u062a \u0645\u0634\u0627\u0647\u062f\u0647\u0654 \u0631\u0627\u0647\u0646\u0645\u0627 \u06a9\u0644\u06cc\u062f\u0647\u0627\u06cc ALT + 0 \u0631\u0627 \u0641\u0634\u0627\u0631 \u062f\u0647\u06cc\u062f.",
"System Font": "\u0641\u0648\u0646\u062a \u0633\u06cc\u0633\u062a\u0645\u06cc",
"Failed to upload image: {0}": "\u0639\u062f\u0645 \u0645\u0648\u0641\u0642\u06cc\u062a \u062f\u0631 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u062a\u0635\u0648\u06cc\u0631: {0}",
"Failed to load plugin: {0} from url {1}": "\u0639\u062f\u0645 \u0645\u0648\u0641\u0642\u06cc\u062a \u062f\u0631 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0627\u0641\u0632\u0648\u0646\u0647: {0} \u0627\u0632 \u0646\u0634\u0627\u0646\u06cc \u0648\u0628 {1}",
"Failed to load plugin url: {0}": "\u0639\u062f\u0645 \u0645\u0648\u0641\u0642\u06cc\u062a \u062f\u0631 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0646\u0634\u0627\u0646\u06cc \u0648\u0628 \u0627\u0641\u0632\u0648\u0646\u0647: {0}",
"Failed to initialize plugin: {0}": "\u0639\u062f\u0645 \u0645\u0648\u0641\u0642\u06cc\u062a \u062f\u0631 \u0631\u0627\u0647\u200c\u0627\u0646\u062f\u0627\u0632\u06cc \u0627\u0641\u0632\u0648\u0646\u0647: {0}",
"example": "\u0645\u062b\u0627\u0644",
"Search": "\u062c\u0633\u062a\u062c\u0648",
"All": "\u0647\u0645\u0647",
"Currency": "\u0627\u0631\u0632",
"Text": "\u0645\u062a\u0646",
"Quotations": "\u0646\u0642\u0644\u200c\u0642\u0648\u0644\u200c\u0647\u0627",
"Mathematical": "\u0631\u06cc\u0627\u0636\u06cc",
"Extended Latin": "\u0644\u0627\u062a\u06cc\u0646 \u06af\u0633\u062a\u0631\u062f\u0647",
"Symbols": "\u0646\u0645\u0627\u062f\u0647\u0627",
"Arrows": "\u067e\u06cc\u06a9\u0627\u0646\u200c\u0647\u0627",
"User Defined": "\u0628\u0647 \u062e\u0648\u0627\u0633\u062a \u06a9\u0627\u0631\u0628\u0631",
"dollar sign": "\u0646\u0645\u0627\u062f \u062f\u0644\u0627\u0631",
"currency sign": "\u0646\u0645\u0627\u062f \u0627\u0631\u0632",
"euro-currency sign": "\u0646\u0645\u0627\u062f \u06cc\u0648\u0631\u0648",
"colon sign": "\u0646\u0645\u0627\u062f \u062f\u0648\u0646\u0642\u0637\u0647",
"cruzeiro sign": "\u0646\u0645\u0627\u062f \u06a9\u0631\u0648\u0632\u06cc\u0631\u0648",
"french franc sign": "\u0646\u0645\u0627\u062f \u0641\u0631\u0627\u0646\u06a9 \u0641\u0631\u0627\u0646\u0633\u0647",
"lira sign": "\u0646\u0645\u0627\u062f \u0644\u06cc\u0631\u0647",
"mill sign": "\u0646\u0645\u0627\u062f \u0645\u06cc\u0644",
"naira sign": "\u0646\u0645\u0627\u062f \u0646\u0627\u06cc\u0631\u0627",
"peseta sign": "\u0646\u0645\u0627\u062f \u067e\u0632\u062a\u0627",
"rupee sign": "\u0646\u0645\u0627\u062f \u0631\u0648\u067e\u06cc\u0647",
"won sign": "\u0646\u0645\u0627\u062f \u0648\u0648\u0646",
"new sheqel sign": "\u0646\u0645\u0627\u062f \u0634\u06a9\u0644 \u062c\u062f\u06cc\u062f",
"dong sign": "\u0646\u0645\u0627\u062f \u062f\u0627\u0646\u06af",
"kip sign": "\u0646\u0645\u0627\u062f \u06a9\u06cc\u067e",
"tugrik sign": "\u0646\u0645\u0627\u062f \u062a\u0648\u06af\u0631\u0648\u06af",
"drachma sign": "\u0646\u0645\u0627\u062f \u062f\u0631\u0627\u062e\u0645\u0627",
"german penny symbol": "\u0646\u0645\u0627\u062f \u067e\u0646\u06cc \u0622\u0644\u0645\u0627\u0646\u06cc",
"peso sign": "\u0646\u0645\u0627\u062f \u067e\u0632\u0648",
"guarani sign": "\u0646\u0645\u0627\u062f \u06af\u0648\u0627\u0631\u0627\u0646\u06cc",
"austral sign": "\u0646\u0645\u0627\u062f \u0622\u0633\u062a\u0631\u0627\u0644",
"hryvnia sign": "\u0646\u0645\u0627\u062f \u06af\u0631\u06cc\u0648\u0646\u0627",
"cedi sign": "\u0646\u0645\u0627\u062f \u0633\u062f\u06cc",
"livre tournois sign": "\u0646\u0645\u0627\u062f \u0644\u06cc\u0648\u0631\u0647 \u062a\u0648\u0631\u0646\u0648\u0627",
"spesmilo sign": "\u0646\u0645\u0627\u062f \u0627\u0633\u067e\u0633\u0645\u06cc\u0644\u0648",
"tenge sign": "\u0646\u0645\u0627\u062f \u062a\u0646\u06af\u0647",
"indian rupee sign": "\u0646\u0645\u0627\u062f \u0631\u0648\u067e\u06cc\u0647 \u0647\u0646\u062f\u06cc",
"turkish lira sign": "\u0646\u0645\u0627\u062f \u0644\u06cc\u0631\u0647 \u062a\u0631\u06a9\u06cc",
"nordic mark sign": "\u0646\u0645\u0627\u062f \u0645\u0627\u0631\u06a9 \u0646\u0631\u0648\u0698",
"manat sign": "\u0646\u0645\u0627\u062f \u0645\u0646\u0627\u062a",
"ruble sign": "\u0646\u0645\u0627\u062f \u0631\u0648\u0628\u0644",
"yen character": "\u0646\u0648\u06cc\u0633\u0647 \u06cc\u0646",
"yuan character": "\u0646\u0648\u06cc\u0633\u0647 \u06cc\u0648\u0627\u0646",
"yuan character, in hong kong and taiwan": "\u0646\u0648\u06cc\u0633\u0647 \u06cc\u0648\u0627\u0646\u060c \u062f\u0631 \u0647\u0646\u06af\u200c\u06a9\u0646\u06af \u0648 \u062a\u0627\u06cc\u0648\u0627\u0646",
"yen\/yuan character variant one": "\u0646\u0648\u06cc\u0633\u0647 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646 \u06cc\u0646\/\u06cc\u0648\u0627\u0646",
"Loading emoticons...": "\u062f\u0631 \u062d\u0627\u0644 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0634\u06a9\u0644\u06a9\u200c\u0647\u0627...",
"Could not load emoticons": "\u0634\u06a9\u0644\u06a9\u200c\u0647\u0627 \u0628\u0627\u0631\u06af\u0630\u0627\u0631\u06cc \u0646\u0634\u062f\u0646\u062f",
"People": "\u0627\u0641\u0631\u0627\u062f",
"Animals and Nature": "\u062d\u06cc\u0648\u0627\u0646\u0627\u062a \u0648 \u0637\u0628\u06cc\u0639\u062a",
"Food and Drink": "\u063a\u0630\u0627 \u0648 \u0646\u0648\u0634\u06cc\u062f\u0646\u06cc",
"Activity": "\u0641\u0639\u0627\u0644\u06cc\u062a",
"Travel and Places": "\u0633\u0641\u0631 \u0648 \u0627\u0645\u0627\u06a9\u0646",
"Objects": "\u0627\u0634\u06cc\u0627",
"Flags": "\u067e\u0631\u0686\u0645\u200c\u0647\u0627",
"Characters": "\u0646\u0648\u06cc\u0633\u0647\u200c\u0647\u0627",
"Characters (no spaces)": "\u0646\u0648\u06cc\u0633\u0647 \u0647\u0627 (\u0628\u062f\u0648\u0646 \u0641\u0627\u0635\u0644\u0647)",
"Error: Form submit field collision.": "\u062e\u0637\u0627: \u062a\u062f\u0627\u062e\u0644 \u062f\u0631 \u062b\u0628\u062a \u0641\u0631\u0645.",
"Error: No form element found.": "\u062e\u0637\u0627: \u0647\u06cc\u0686 \u0627\u0644\u0645\u0627\u0646 \u0641\u0631\u0645\u06cc \u06cc\u0627\u0641\u062a \u0646\u0634\u062f.",
"Update": "\u0628\u0647\u200c\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06cc",
"Color swatch": "\u0646\u0645\u0648\u0646\u0647 \u0631\u0646\u06af",
"Turquoise": "\u0641\u06cc\u0631\u0648\u0632\u0647\u200c\u0627\u06cc",
"Green": "\u0633\u0628\u0632",
"Blue": "\u0622\u0628\u06cc",
"Purple": "\u0628\u0646\u0641\u0634",
"Navy Blue": "\u0633\u0631\u0645\u0647\u200c\u0627\u06cc",
"Dark Turquoise": "\u0641\u06cc\u0631\u0648\u0632\u0647\u200c\u0627\u06cc \u062a\u06cc\u0631\u0647",
"Dark Green": "\u0633\u0628\u0632 \u062a\u06cc\u0631\u0647",
"Medium Blue": "\u0622\u0628\u06cc \u0633\u06cc\u0631",
"Medium Purple": "\u0622\u0628\u06cc \u0628\u0646\u0641\u0634",
"Midnight Blue": "\u0622\u0628\u06cc \u0646\u0641\u062a\u06cc",
"Yellow": "\u0632\u0631\u062f",
"Orange": "\u0646\u0627\u0631\u0646\u062c\u06cc",
"Red": "\u0642\u0631\u0645\u0632",
"Light Gray": "\u062e\u0627\u06a9\u0633\u062a\u0631\u06cc \u0631\u0648\u0634\u0646",
"Gray": "\u062e\u0627\u06a9\u0633\u062a\u0631\u06cc",
"Dark Yellow": "\u0632\u0631\u062f \u062a\u06cc\u0631\u0647",
"Dark Orange": "\u0646\u0627\u0631\u0646\u062c\u06cc \u062a\u06cc\u0631\u0647",
"Dark Red": "\u0642\u0631\u0645\u0632 \u062a\u06cc\u0631\u0647",
"Medium Gray": "\u062e\u0627\u06a9\u0633\u062a\u0631\u06cc \u0646\u06cc\u0645\u0647\u200c\u0631\u0648\u0634\u0646",
"Dark Gray": "\u062e\u0627\u06a9\u0633\u062a\u0631\u06cc \u062a\u06cc\u0631\u0647",
"Black": "\u0633\u06cc\u0627\u0647",
"White": "\u0633\u0641\u06cc\u062f",
"Switch to or from fullscreen mode": "\u062a\u063a\u06cc\u06cc\u0631 \u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645\u200c\u0635\u0641\u062d\u0647 \u06cc\u0627 \u0628\u0647 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645\u200c\u0635\u0641\u062d\u0647",
"Open help dialog": "\u0628\u0627\u0632 \u06a9\u0631\u062f\u0646 \u06a9\u0627\u062f\u0631 \u0631\u0627\u0647\u0646\u0645\u0627",
"history": "\u062a\u0627\u0631\u06cc\u062e\u0686\u0647",
"styles": "\u0633\u0628\u06a9\u200c\u0647\u0627",
"formatting": "\u0642\u0627\u0644\u0628\u200c\u0628\u0646\u062f\u06cc",
"alignment": "\u062a\u0631\u0627\u0632\u0628\u0646\u062f\u06cc",
"indentation": "\u062a\u0648\u0631\u0641\u062a\u06af\u06cc",
"permanent pen": "\u0642\u0644\u0645 \u062f\u0627\u0626\u0645\u06cc",
"comments": "\u0646\u0638\u0631\u0627\u062a",
"Anchor": "\u0642\u0644\u0627\u0628",
"Special character": "\u0646\u0648\u06cc\u0633\u0647 \u0647\u0627\u06cc \u062e\u0627\u0635",
"Code sample": "\u0646\u0645\u0648\u0646\u0647 \u06a9\u064f\u062f",
"Color": "\u0631\u0646\u06af",
"Emoticons": "\u0635\u0648\u0631\u062a\u06a9 \u0647\u0627",
"Document properties": "\u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0633\u0646\u062f",
"Image": "\u062a\u0635\u0648\u06cc\u0631",
"Insert link": "\u062f\u0631\u062c \u067e\u06cc\u0648\u0646\u062f",
"Target": "\u0645\u0642\u0635\u062f",
"Link": "\u067e\u06cc\u0648\u0646\u062f",
"Poster": "\u067e\u0648\u0633\u062a\u0631",
"Media": "\u0631\u0633\u0627\u0646\u0647",
"Print": "\u0686\u0627\u067e",
"Prev": "\u0642\u0628\u0644\u06cc",
"Find and replace": "\u062c\u0633\u062a\u062c\u0648 \u0648 \u062c\u0627\u06cc\u06af\u0632\u06cc\u0646\u06cc",
"Whole words": "\u062a\u0645\u0627\u0645 \u0648\u0627\u0698\u06af\u0627\u0646",
"Spellcheck": "\u0628\u0631\u0631\u0633\u06cc \u0627\u0645\u0644\u0627\u0621",
"Caption": "\u0639\u0646\u0648\u0627\u0646",
"Insert template": "\u062f\u0631\u062c \u0627\u0644\u06af\u0648",
"_dir": "rtl"
});
tinymce.addI18n('fa_IR', {
Redo: '\u0628\u0627\u0632\u0627\u0646\u062C\u0627\u0645',
Undo: '\u0648\u0627\u06AF\u0631\u062F',
Cut: '\u0628\u0631\u0634',
Copy: '\u06A9\u067E\u06CC',
Paste: '\u0686\u0633\u0628\u0627\u0646\u062F\u0646',
'Select all': '\u0627\u0646\u062A\u062E\u0627\u0628 \u0647\u0645\u0647',
'New document': '\u0633\u0646\u062F \u062C\u062F\u06CC\u062F',
Ok: '\u062A\u0623\u06CC\u06CC\u062F',
Cancel: '\u0644\u063A\u0648',
'Visual aids': '\u06A9\u0645\u06A9\u200C\u0647\u0627\u06CC \u0628\u0635\u0631\u06CC',
Bold: '\u067E\u0631\u0631\u0646\u06AF',
Italic: '\u06A9\u062C',
Underline: '\u0632\u06CC\u0631 \u062E\u0637 \u062F\u0627\u0631',
Strikethrough: '\u062E\u0637 \u0632\u062F\u0646',
Superscript: '\u0628\u0627\u0644\u0627\u0646\u06AF\u0627\u0634\u062A',
Subscript: '\u0632\u06CC\u0631\u0646\u06AF\u0627\u0634\u062A',
'Clear formatting':
'\u067E\u0627\u06A9 \u06A9\u0631\u062F\u0646 \u0642\u0627\u0644\u0628\u200C\u0628\u0646\u062F\u06CC',
'Align left': '\u062A\u0631\u0627\u0632\u0628\u0646\u062F\u06CC \u0627\u0632 \u0686\u067E',
'Align center':
'\u062A\u0631\u0627\u0632\u0628\u0646\u062F\u06CC \u0627\u0632 \u0648\u0633\u0637',
'Align right':
'\u062A\u0631\u0627\u0632\u0628\u0646\u062F\u06CC \u0627\u0632 \u0631\u0627\u0633\u062A',
Justify: '\u062A\u0631\u0627\u0632\u0628\u0646\u062F\u06CC \u062F\u0648\u0637\u0631\u0641\u0647',
'Bullet list':
'\u0641\u0647\u0631\u0633\u062A \u0646\u0634\u0627\u0646\u0647\u200C\u062F\u0627\u0631',
'Numbered list':
'\u0641\u0647\u0631\u0633\u062A \u0634\u0645\u0627\u0631\u0647\u200C\u062F\u0627\u0631',
'Decrease indent': '\u06A9\u0627\u0647\u0634 \u062A\u0648\u0631\u0641\u062A\u06AF\u06CC',
'Increase indent':
'\u0627\u0641\u0632\u0627\u06CC\u0634 \u062A\u0648\u0631\u0641\u062A\u06AF\u06CC',
Close: '\u0628\u0633\u062A\u0646',
Formats: '\u0642\u0627\u0644\u0628\u200C\u0628\u0646\u062F\u06CC\u200C\u0647\u0627',
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.":
'\u0645\u0631\u0648\u0631\u06AF\u0631 \u0634\u0645\u0627 \u0627\u0632 \u062F\u0633\u062A\u0631\u0633\u06CC \u0645\u0633\u062A\u0642\u06CC\u0645 \u0628\u0647 \u06A9\u0644\u06CC\u067E\u200C\u0628\u0648\u0631\u062F \u067E\u0634\u062A\u06CC\u0628\u0627\u0646\u06CC \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F\u060C \u0644\u0637\u0641\u0627\u064B \u0627\u0632 \u0645\u06CC\u0627\u0646\u0628\u0631\u0647\u0627\u06CC Ctrl+X/C/V \u0635\u0641\u062D\u0647 \u06A9\u0644\u06CC\u062F \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u06A9\u0646\u06CC\u062F.',
Headers: '\u0633\u0631\u0628\u0631\u06AF\u200C\u0647\u0627',
'Header 1': '\u0633\u0631\u0628\u0631\u06AF 1',
'Header 2': '\u0633\u0631\u0628\u0631\u06AF 2',
'Header 3': '\u0633\u0631\u0628\u0631\u06AF 3',
'Header 4': '\u0633\u0631\u0628\u0631\u06AF 4',
'Header 5': '\u0633\u0631\u0628\u0631\u06AF 5',
'Header 6': '\u0633\u0631\u0628\u0631\u06AF 6',
Headings: '\u0633\u0631\u0641\u0635\u0644\u200C\u0647\u0627',
'Heading 1': '\u0633\u0631\u0641\u0635\u0644\u200C 1',
'Heading 2': '\u0633\u0631\u0641\u0635\u0644 2',
'Heading 3': '\u0633\u0631\u0641\u0635\u0644 3',
'Heading 4': '\u0633\u0631\u0641\u0635\u0644 4',
'Heading 5': '\u0633\u0631\u0641\u0635\u0644 5',
'Heading 6': '\u0633\u0631\u0641\u0635\u0644 6',
Preformatted:
'\u0627\u0632 \u067E\u06CC\u0634 \u0642\u0627\u0644\u0628\u200C\u0628\u0646\u062F\u06CC\u200C\u0634\u062F\u0647',
Div: '\u0628\u062E\u0634',
Pre: '\u067E\u06CC\u0634',
Code: '\u06A9\u062F',
Paragraph: '\u067E\u0627\u0631\u0627\u06AF\u0631\u0627\u0641',
Blockquote: '\u0646\u0642\u0644 \u0642\u0648\u0644 \u0628\u0644\u0648\u06A9\u06CC',
Inline: '\u0647\u0645\u200C\u0631\u0627\u0633\u062A\u0627',
Blocks: '\u0628\u0644\u0648\u06A9\u200C\u0647\u0627',
'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.':
'\u0627\u0645\u06A9\u0627\u0646 \u0686\u0633\u0628\u0627\u0646\u062F\u0646\u060C \u062F\u0631 \u062D\u0627\u0644\u062A \u0645\u062A\u0646 \u062E\u0627\u0644\u0635 \u062A\u0646\u0638\u06CC\u0645 \u06AF\u0634\u062A\u0647. \u062A\u0627 \u0632\u0645\u0627\u0646 \u062A\u063A\u06CC\u06CC\u0631 \u0627\u06CC\u0646 \u062D\u0627\u0644\u062A\u060C \u0645\u062D\u062A\u0648\u0627\u06CC \u0645\u0648\u0631\u062F \u0686\u0633\u0628\u0627\u0646\u062F\u0646\u060C \u0628\u0647 \u0635\u0648\u0631\u062A \u0645\u062A\u0646 \u062E\u0627\u0644\u0635 \u062E\u0648\u0627\u0647\u062F \u0686\u0633\u0628\u06CC\u062F.',
Fonts: '\u0641\u0648\u0646\u062A\u200C\u200C\u0647\u0627',
'Font Sizes': '\u0627\u0646\u062F\u0627\u0632\u0647\u0654 \u0641\u0648\u0646\u062A',
Class: '\u0637\u0628\u0642\u0647',
'Browse for an image':
'\u06AF\u0634\u062A\u0646 \u0628\u0631\u0627\u06CC \u0639\u06A9\u0633 \u0645\u0648\u0631\u062F \u0646\u0638\u0631',
OR: '\u06CC\u0627',
'Drop an image here':
'\u062A\u0635\u0648\u06CC\u0631 \u0645\u0648\u0631\u062F \u0646\u0638\u0631 \u0631\u0627 \u0627\u06CC\u0646\u062C\u0627 \u0631\u0647\u0627 \u06A9\u0646\u06CC\u062F',
Upload: '\u0622\u067E\u0644\u0648\u062F',
Block: '\u0628\u0644\u0648\u06A9',
Align: '\u062A\u0631\u0627\u0632\u0628\u0646\u062F\u06CC',
Default: '\u067E\u06CC\u0634 \u0641\u0631\u0636',
Circle: '\u062F\u0627\u06CC\u0631\u0647',
Disc: '\u062F\u0627\u06CC\u0631\u0647\u0621 \u062A\u0648\u067E\u0631',
Square: '\u0686\u0647\u0627\u0631 \u06AF\u0648\u0634',
'Lower Alpha': '\u062D\u0631\u0648\u0641 \u06A9\u0648\u0686\u06A9',
'Lower Greek':
'\u062D\u0631\u0648\u0641 \u06A9\u0648\u0686\u06A9 \u06CC\u0648\u0646\u0627\u0646\u06CC',
'Lower Roman': '\u0627\u0631\u0642\u0627\u0645 \u06A9\u0648\u0686\u06A9 \u0631\u0648\u0645\u06CC',
'Upper Alpha': '\u062D\u0631\u0648\u0641 \u0628\u0632\u0631\u06AF',
'Upper Roman': '\u0627\u0631\u0642\u0627\u0645 \u0628\u0632\u0631\u06AF \u0631\u0648\u0645\u06CC',
'Anchor...': '\u0642\u0644\u0627\u0628...',
Name: '\u0646\u0627\u0645',
Id: '\u0634\u0646\u0627\u0633\u0647',
'Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.':
'\u0634\u0646\u0627\u0633\u0647 \u0645\u06CC \u0628\u0627\u06CC\u0633\u062A \u0628\u0627 \u06CC\u06A9 \u062D\u0631\u0641 \u0627\u0644\u0641\u0628\u0627 \u0622\u063A\u0627\u0632 \u0648 \u0628\u0627 \u062F\u0646\u0628\u0627\u0644\u0647 \u0627\u06CC \u0627\u0632 \u062D\u0631\u0648\u0641\u060C \u0627\u0639\u062F\u0627\u062F\u060C \u0639\u0644\u0627\u0645\u062A \u0645\u0650\u0646\u0647\u0627\u060C \u0646\u0642\u0637\u0647\u060C \u062F\u0648 \u0646\u0642\u0637\u0647 \u06CC\u0627 \u062E\u0637 \u062A\u06CC\u0631\u0647 \u0627\u062F\u0627\u0645\u0647 \u06CC\u0627\u0628\u062F.',
'You have unsaved changes are you sure you want to navigate away?':
'\u062A\u063A\u06CC\u06CC\u0631\u0627\u062A \u0634\u0645\u0627 \u0630\u062E\u06CC\u0631\u0647 \u0646\u0634\u062F\u0647 \u0627\u0646\u062F\u060C \u0622\u06CC\u0627 \u062C\u0647\u062A \u062E\u0631\u0648\u062C \u0627\u0637\u0645\u06CC\u0646\u0627\u0646 \u062F\u0627\u0631\u06CC\u062F\u061F',
'Restore last draft':
'\u0628\u0627\u0632\u06CC\u0627\u0628\u06CC \u0622\u062E\u0631\u06CC\u0646 \u067E\u06CC\u0634 \u0646\u0648\u06CC\u0633',
'Special characters...':
'\u0646\u0648\u06CC\u0633\u0647\u200C\u0647\u0627\u06CC \u0648\u06CC\u0698\u0647...',
'Source code': '\u0645\u062A\u0646 \u06A9\u062F \u0645\u0646\u0628\u0639',
'Insert/Edit code sample':
'\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0646\u0645\u0648\u0646\u0647\u0621 \u06A9\u062F',
Language: '\u0632\u0628\u0627\u0646',
'Code sample...': '\u0646\u0645\u0648\u0646\u0647 \u06A9\u062F...',
'Color Picker':
'\u0627\u0646\u062A\u062E\u0627\u0628\u200C\u06A9\u0646\u0646\u062F\u0647 \u0631\u0646\u06AF',
R: '\u0642\u0631\u0645\u0632',
G: '\u0633\u0628\u0632',
B: '\u0622\u0628\u06CC',
'Left to right': '\u0686\u067E \u0628\u0647 \u0631\u0627\u0633\u062A',
'Right to left': '\u0631\u0627\u0633\u062A \u0628\u0647 \u0686\u067E',
'Emoticons...': '\u0635\u0648\u0631\u062A\u06A9\u200C\u0647\u0627...',
'Metadata and Document Properties':
'\u0641\u0631\u0627\u062F\u0627\u062F\u0647 \u0648 \u0645\u0634\u062E\u0635\u0627\u062A \u0633\u0646\u062F',
Title: '\u0639\u0646\u0648\u0627\u0646',
Keywords: '\u0648\u0627\u0698\u06AF\u0627\u0646 \u06A9\u0644\u06CC\u062F\u06CC',
Description: '\u062A\u0648\u0636\u06CC\u062D',
Robots: '\u0631\u0648\u0628\u0627\u062A\u0647\u0627',
Author: '\u0645\u0648\u0644\u0641',
Encoding: '\u06A9\u062F\u06AF\u0632\u0627\u0631\u06CC \u0645\u062A\u0646',
Fullscreen: '\u062A\u0645\u0627\u0645 \u0635\u0641\u062D\u0647',
Action: '\u0639\u0645\u0644',
Shortcut: '\u0645\u06CC\u0627\u0646\u0628\u064F\u0631',
Help: '\u0631\u0627\u0647\u0646\u0645\u0627',
Address: '\u0646\u0634\u0627\u0646\u06CC',
'Focus to menubar':
'\u062A\u0645\u0631\u06A9\u0632 \u0628\u0631 \u0646\u0648\u0627\u0631 \u0645\u0646\u0648',
'Focus to toolbar':
'\u062A\u0645\u0631\u06A9\u0632 \u0628\u0631 \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631',
'Focus to element path':
'\u062A\u0645\u0631\u06A9\u0632 \u0628\u0631 \u0645\u0633\u06CC\u0631 \u0627\u0650\u0644\u0650\u0645\u0627\u0646',
'Focus to contextual toolbar':
'\u062A\u0645\u0631\u06A9\u0632 \u0628\u0631 \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631 \u0645\u062A\u0646\u06CC',
'Insert link (if link plugin activated)':
'\u062F\u0631\u062C \u067E\u06CC\u0648\u0646\u062F (\u0627\u06AF\u0631 \u0627\u0641\u0632\u0648\u0646\u0647\u0621 \u067E\u06CC\u0648\u0646\u062F \u0641\u0639\u0627\u0644 \u0634\u062F)',
'Save (if save plugin activated)':
'\u062B\u0628\u062A\u00A0(\u0627\u06AF\u0631 \u0627\u0641\u0632\u0648\u0646\u0647\u0621 \u0630\u062E\u06CC\u0631\u0647 \u0633\u0627\u0632\u06CC \u0641\u0639\u0627\u0644 \u0634\u062F)',
'Find (if searchreplace plugin activated)':
'\u06CC\u0627\u0641\u062A\u0646 (\u0627\u06AF\u0631 \u0627\u0641\u0632\u0648\u0646\u0647\u0621 \u062C\u0633\u062A\u062C\u0648/\u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646\u06CC \u0641\u0639\u0627\u0644 \u0634\u062F)',
'Plugins installed ({0}):':
'\u0627\u0641\u0632\u0648\u0646\u0647 \u0647\u0627\u06CC\u06CC \u06A9\u0647 \u0646\u0635\u0628 \u0634\u062F\u0646\u062F ({0}):',
'Premium plugins:':
'\u0627\u0641\u0632\u0648\u0646\u0647 \u0647\u0627\u06CC \u0645\u062E\u0635\u0648\u0635:',
'Learn more...': '\u06CC\u0627\u062F\u06AF\u06CC\u0631\u06CC \u0628\u06CC\u0634\u062A\u0631...',
'You are using {0}':
'\u0634\u0645\u0627 \u062F\u0631 \u062D\u0627\u0644 \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u0627\u0632 {0} \u0645\u06CC \u0628\u0627\u0634\u06CC\u062F',
Plugins: '\u0627\u0641\u0632\u0648\u0646\u0647 \u0647\u0627',
'Handy Shortcuts':
'\u0645\u06CC\u0627\u0646\u0628\u064F\u0631\u0647\u0627\u06CC \u0633\u0648\u062F\u0645\u0646\u062F',
'Horizontal line': '\u062E\u0637 \u0627\u0641\u0642\u06CC',
'Insert/edit image':
'\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u062A\u0635\u0648\u06CC\u0631',
'Image description': '\u062A\u0648\u0635\u06CC\u0641 \u062A\u0635\u0648\u06CC\u0631',
Source: '\u0645\u0646\u0628\u0639',
Dimensions: '\u0627\u0628\u0639\u0627\u062F',
'Constrain proportions': '\u062D\u0641\u0638 \u062A\u0646\u0627\u0633\u0628',
General: '\u0639\u0645\u0648\u0645\u06CC',
Advanced: '\u067E\u06CC\u0634\u0631\u0641\u062A\u0647',
Style: '\u0633\u0628\u06A9',
'Vertical space': '\u0641\u0636\u0627\u06CC \u0639\u0645\u0648\u062F\u06CC',
'Horizontal space': '\u0641\u0636\u0627\u06CC \u0627\u0641\u0642\u06CC',
Border: '\u0644\u0628\u0647',
'Insert image': '\u062F\u0631\u062C \u062A\u0635\u0648\u06CC\u0631',
'Image...': '\u062A\u0635\u0648\u06CC\u0631...',
'Image list': '\u0641\u0647\u0631\u0633\u062A \u062A\u0635\u0648\u06CC\u0631\u06CC',
'Rotate counterclockwise':
'\u062F\u064E\u0648\u064E\u0631\u0627\u0646 \u067E\u0627\u062F \u0633\u0627\u0639\u062A \u06AF\u0631\u062F',
'Rotate clockwise':
'\u062F\u064E\u0648\u064E\u0631\u0627\u0646 \u0633\u0627\u0639\u062A \u06AF\u0631\u062F',
'Flip vertically': '\u0642\u0631\u06CC\u0646\u0647 \u0639\u0645\u0648\u062F\u06CC',
'Flip horizontally': '\u0642\u0631\u06CC\u0646\u0647 \u0627\u0641\u0642\u06CC',
'Edit image': '\u0648\u06CC\u0631\u0627\u0633\u062A \u062A\u0635\u0648\u06CC\u0631',
'Image options': '\u062A\u0646\u0638\u06CC\u0645\u0627\u062A \u062A\u0635\u0648\u06CC\u0631',
'Zoom in': '\u0628\u0632\u0631\u06AF \u0646\u0645\u0627\u06CC\u06CC',
'Zoom out': '\u06A9\u0648\u0686\u06A9 \u0646\u0645\u0627\u06CC\u06CC',
Crop: '\u0628\u064F\u0631\u0634 \u062F\u064F\u0648\u0631',
Resize: '\u062A\u063A\u06CC\u06CC\u0631 \u0627\u0646\u062F\u0627\u0632\u0647',
Orientation: '\u06AF\u0650\u0631\u0627',
Brightness: '\u0631\u0648\u0634\u0646\u0627\u06CC\u06CC',
Sharpen: '\u0628\u0647\u0628\u0648\u062F \u0644\u0628\u0647',
Contrast: '\u062A\u0636\u0627\u062F \u0631\u0646\u06AF',
'Color levels': '\u0633\u0637\u0648\u062D \u0631\u0646\u06AF',
Gamma: '\u06AF\u0627\u0645\u0627',
Invert: '\u0628\u0631\u06AF\u0634\u062A \u0631\u0646\u06AF',
Apply: '\u0627\u0650\u0639\u0645\u0627\u0644',
Back: '\u0628\u0627\u0632\u06AF\u0634\u062A',
'Insert date/time': '\u062F\u0631\u062C \u062A\u0627\u0631\u06CC\u062E/\u0632\u0645\u0627\u0646',
'Date/time': '\u062A\u0627\u0631\u06CC\u062E/\u0632\u0645\u0627\u0646',
'Insert/Edit Link':
'\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u067E\u06CC\u0648\u0646\u062F',
'Insert/edit link':
'\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u067E\u06CC\u0648\u0646\u062F',
'Text to display': '\u0645\u062A\u0646 \u0646\u0645\u0627\u06CC\u0634\u06CC',
Url: '\u0622\u062F\u0631\u0633',
'Open link in...':
'\u0628\u0627\u0632 \u06A9\u0631\u062F\u0646 \u067E\u06CC\u0648\u0646\u062F \u062F\u0631...',
'Current window': '\u067E\u0646\u062C\u0631\u0647 \u062C\u0627\u0631\u06CC',
None: '\u0647\u06CC\u0686',
'New window': '\u067E\u0646\u062C\u0631\u0647\u0621 \u062C\u062F\u06CC\u062F',
'Remove link': '\u062D\u0630\u0641 \u067E\u06CC\u0648\u0646\u062F',
Anchors: '\u0642\u0644\u0627\u0628 \u0647\u0627',
'Link...': '\u067E\u06CC\u0648\u0646\u062F...',
'Paste or type a link':
'\u0686\u0633\u0628\u0627\u0646\u062F\u0646 \u06CC\u0627 \u062A\u0627\u06CC\u067E \u067E\u06CC\u0648\u0646\u062F',
'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?':
'\u0628\u0647 \u0646\u0638\u0631 \u0645\u06CC \u0631\u0633\u062F \u0622\u062F\u0631\u0633 \u0648\u0631\u0648\u062F\u06CC \u06CC\u06A9 \u0631\u0627\u06CC\u0627\u0646\u0627\u0645\u0647 \u0628\u0627\u0634\u062F. \u0622\u06CC\u0627 \u062A\u0645\u0627\u06CC\u0644 \u0628\u0647 \u0627\u0641\u0632\u0648\u0631\u062F\u0646 \u067E\u06CC\u0634\u0648\u0646\u062F mailto: \u062F\u0627\u0631\u06CC\u062F\u061F',
'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?':
'\u0628\u0647 \u0646\u0638\u0631 \u0645\u06CC \u0631\u0633\u062F \u0622\u062F\u0631\u0633 \u0648\u0631\u0648\u062F\u06CC \u0627\u0631\u062C\u0627\u0639\u06CC \u0628\u0647 \u062E\u0627\u0631\u062C \u0627\u0632 \u0627\u06CC\u0646 \u0633\u0627\u06CC\u062A \u0645\u06CC \u0628\u0627\u0634\u062F. \u0622\u06CC\u0627 \u062A\u0645\u0627\u06CC\u0644 \u0628\u0647 \u0627\u0641\u0632\u0648\u0631\u062F\u0646 \u067E\u06CC\u0634\u0648\u0646\u062F http:// \u062F\u0627\u0631\u06CC\u062F\u061F',
'Link list': '\u0641\u0647\u0631\u0633\u062A \u067E\u06CC\u0648\u0646\u062F',
'Insert video': '\u062F\u0631\u062C \u0648\u06CC\u062F\u06CC\u0648',
'Insert/edit video':
'\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0648\u06CC\u062F\u06CC\u0648',
'Insert/edit media':
'\u062F\u0631\u062C/\u0648\u06CC\u0631\u0627\u06CC\u0634 \u0631\u0633\u0627\u0646\u0647',
'Alternative source': '\u0645\u0646\u0628\u0639 \u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646',
'Alternative source URL':
'\u0646\u0634\u0627\u0646\u06CC \u0648\u0628 \u0645\u0646\u0628\u0639 \u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646',
'Media poster (Image URL)':
'\u067E\u0648\u0633\u062A\u0631 \u0631\u0633\u0627\u0646\u0647 (\u0646\u0634\u0627\u0646\u06CC \u0648\u0628 \u062A\u0635\u0648\u06CC\u0631)',
'Paste your embed code below:':
'\u0686\u0633\u0628\u0627\u0646\u062F\u0646 \u06A9\u062F \u062C\u0627\u0633\u0627\u0632\u06CC \u0634\u0645\u0627 \u062F\u0631 \u0632\u06CC\u0631: ',
Embed: '\u062C\u0627\u0633\u0627\u0632\u06CC',
'Media...': '\u0631\u0633\u0627\u0646\u0647...',
'Nonbreaking space':
'\u0641\u0636\u0627\u06CC \u062E\u0627\u0644\u06CC \u0628\u0631\u0634 \u0646\u0627\u067E\u0630\u06CC\u0631',
'Page break': '\u0628\u0631\u0634 \u0635\u0641\u062D\u0647',
'Paste as text': '\u0686\u0633\u0628\u0627\u0646\u062F\u0646 \u0645\u062A\u0646',
Preview: '\u067E\u06CC\u0634 \u0646\u0645\u0627\u06CC\u0634',
'Print...': '\u0686\u0627\u067E...',
Save: '\u0630\u062E\u06CC\u0631\u0647',
Find: '\u062C\u0633\u062A\u062C\u0648',
'Replace with': '\u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646\u06CC \u0628\u0627',
Replace: '\u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646\u06CC',
'Replace all': '\u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646 \u0647\u0645\u0647',
Previous: '\u0642\u0628\u0644\u06CC',
Next: '\u0628\u0639\u062F\u06CC',
'Find and replace...':
'\u06CC\u0627\u0641\u062A\u0646 \u0648 \u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646 \u06A9\u0631\u062F\u0646...',
'Could not find the specified string.':
'\u0631\u0634\u062A\u0647\u0621 \u0645\u0648\u0631\u062F \u0646\u0638\u0631 \u06CC\u0627\u0641\u062A \u0646\u06AF\u0631\u062F\u06CC\u062F.',
'Match case': '\u062A\u0637\u0627\u0628\u0642 \u062D\u0631\u0648\u0641',
'Find whole words only':
'\u06CC\u0627\u0641\u062A\u0646 \u062F\u0642\u06CC\u0642\u0627\u064B \u06A9\u0644 \u0648\u0627\u0698\u0647',
'Spell check': '\u0628\u0631\u0631\u0633\u06CC \u0627\u0645\u0644\u0627',
Ignore: '\u0628\u06CC \u062E\u06CC\u0627\u0644',
'Ignore all': '\u0628\u06CC \u062E\u06CC\u0627\u0644 \u0647\u0645\u0647',
Finish: '\u0627\u062A\u0645\u0627\u0645',
'Add to Dictionary':
'\u0628\u0647 \u0648\u0627\u0698\u0647 \u0646\u0627\u0645\u0647 \u0628\u06CC \u0627\u0641\u0632\u0627',
'Insert table': '\u062F\u0631\u062C \u062C\u062F\u0648\u0644',
'Table properties': '\u062A\u0646\u0638\u06CC\u0645\u0627\u062A \u062C\u062F\u0648\u0644',
'Delete table': '\u062D\u0630\u0641 \u062C\u062F\u0648\u0644',
Cell: '\u0633\u0644\u0648\u0644',
Row: '\u0633\u0637\u0631',
Column: '\u0633\u062A\u0648\u0646',
'Cell properties': '\u062A\u0646\u0638\u06CC\u0645\u0627\u062A \u0633\u0644\u0648\u0644',
'Merge cells': '\u067E\u06CC\u0648\u0646\u062F \u0633\u0644\u0648\u0644 \u0647\u0627',
'Split cell': '\u062C\u062F\u0627 \u0633\u0627\u0632\u06CC \u0633\u0644\u0648\u0644',
'Insert row before':
'\u062F\u0631\u062C \u0633\u0637\u0631 \u062F\u0631 \u0628\u0627\u0644\u0627',
'Insert row after':
'\u062F\u0631\u062C \u0633\u0637\u0631 \u062F\u0631 \u067E\u0627\u06CC\u06CC\u0646',
'Delete row': '\u062D\u0630\u0641 \u0633\u0637\u0631',
'Row properties': '\u062A\u0646\u0638\u06CC\u0645\u0627\u062A \u0633\u0637\u0631',
'Cut row': '\u0628\u0631\u0634 \u0633\u0637\u0631',
'Copy row': '\u0631\u0648\u0646\u0648\u06CC\u0633\u06CC \u0633\u0637\u0631',
'Paste row before':
'\u0686\u0633\u0628\u0627\u0646\u062F\u0646 \u0633\u0637\u0631 \u062F\u0631 \u0628\u0627\u0644\u0627',
'Paste row after':
'\u0686\u0633\u0628\u0627\u0646\u062F\u0646 \u0633\u0637\u0631 \u062F\u0631 \u067E\u0627\u06CC\u06CC\u0646',
'Insert column before': '\u062F\u0631\u062C \u0633\u062A\u0648\u0646 \u0642\u0628\u0644',
'Insert column after': '\u062F\u0631\u062C \u0633\u062A\u0648\u0646 \u0628\u0639\u062F',
'Delete column': '\u062D\u0630\u0641 \u0633\u062A\u0648\u0646',
Cols: '\u0633\u062A\u0648\u0646 \u0647\u0627',
Rows: '\u0633\u0637\u0631 \u0647\u0627',
Width: '\u0639\u0631\u0636',
Height: '\u0627\u0631\u062A\u0641\u0627\u0639',
'Cell spacing':
'\u0641\u0627\u0635\u0644\u0647 \u0645\u06CC\u0627\u0646 \u0633\u0644\u0648\u0644\u06CC',
'Cell padding':
'\u062D\u0627\u0634\u06CC\u0647 \u062F\u0631\u0648\u0646 \u0633\u0644\u0648\u0644\u06CC',
'Show caption': '\u0646\u0645\u0627\u06CC\u0634 \u0639\u0646\u0648\u0627\u0646',
Left: '\u0686\u067E',
Center: '\u0645\u06CC\u0627\u0646\u0647',
Right: '\u0631\u0627\u0633\u062A',
'Cell type': '\u0646\u0648\u0639 \u0633\u0644\u0648\u0644',
Scope: '\u062D\u0648\u0632\u0647',
Alignment: '\u0647\u0645 \u062A\u0631\u0627\u0632\u06CC',
'H Align': '\u062A\u0631\u0627\u0632 \u0627\u0641\u0642\u06CC',
'V Align': '\u062A\u0631\u0627\u0632 \u0639\u0645\u0648\u062F\u06CC',
Top: '\u0628\u0627\u0644\u0627',
Middle: '\u0645\u06CC\u0627\u0646\u0647',
Bottom: '\u067E\u0627\u06CC\u06CC\u0646',
'Header cell': '\u0633\u0644\u0648\u0644 \u0633\u0631 \u0633\u062A\u0648\u0646',
'Row group': '\u06AF\u0631\u0648\u0647 \u0633\u0637\u0631\u06CC',
'Column group': '\u06AF\u0631\u0648\u0647 \u0633\u062A\u0648\u0646\u06CC',
'Row type': '\u0646\u0648\u0639 \u0633\u0637\u0631',
Header: '\u0633\u0631 \u0622\u0645\u062F',
Body: '\u0628\u062F\u0646\u0647',
Footer: '\u067E\u0627 \u0646\u0648\u0634\u062A',
'Border color': '\u0631\u0646\u06AF \u0644\u0628\u0647',
'Insert template...': '\u062F\u0631\u062C \u0627\u0644\u06AF\u0648...',
Templates: '\u0627\u0644\u06AF\u0648\u0647\u0627',
Template: '\u0627\u0644\u06AF\u0648',
'Text color': '\u0631\u0646\u06AF \u0645\u062A\u0646',
'Background color': '\u0631\u0646\u06AF \u067E\u0633 \u0632\u0645\u06CC\u0646\u0647',
'Custom...': '\u062F\u0644\u062E\u0648\u0627\u0647...',
'Custom color': '\u0631\u0646\u06AF \u062F\u0644\u062E\u0648\u0627\u0647',
'No color': '\u0628\u062F\u0648\u0646 \u0631\u0646\u06AF',
'Remove color': '\u062D\u0630\u0641 \u0631\u0646\u06AF',
'Table of Contents': '\u0641\u0647\u0631\u0633\u062A \u0639\u0646\u0627\u0648\u06CC\u0646',
'Show blocks': '\u0646\u0645\u0627\u06CC\u0634 \u0628\u0644\u0648\u06A9 \u0647\u0627',
'Show invisible characters':
'\u0646\u0645\u0627\u06CC\u0634 \u0646\u0648\u06CC\u0633\u0647 \u0647\u0627\u06CC \u0646\u0627\u067E\u06CC\u062F\u0627',
'Word count': '\u062A\u0639\u062F\u0627\u062F \u0648\u0627\u0698\u0647\u200C\u0647\u0627',
'Words: {0}': '\u0648\u0627\u0698\u0647 \u0647\u0627: {0}',
'{0} words': '{0} \u0648\u0627\u0698\u0647',
File: '\u067E\u0631\u0648\u0646\u062F\u0647',
Edit: '\u0648\u06CC\u0631\u0627\u06CC\u0634',
Insert: '\u062F\u0631\u062C',
View: '\u0646\u0645\u0627\u06CC\u0634',
Format: '\u0642\u0627\u0644\u0628',
Table: '\u062C\u062F\u0648\u0644',
Tools: '\u0627\u0628\u0632\u0627\u0631\u0647\u0627',
'Powered by {0}': '\u062A\u0648\u0627\u0646 \u06AF\u0631\u0641\u062A\u0647 \u0627\u0632 {0}',
'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help':
'\u0646\u0627\u062D\u06CC\u0647 \u0645\u062A\u0646 \u063A\u0646\u06CC.\n\u062C\u0647\u062A \u0645\u0634\u0627\u0647\u062F\u0647 \u0645\u0646\u0648 \u0627\u0632 \u06A9\u0644\u06CC\u062F\u0647\u0627\u06CC \u062A\u0631\u06A9\u06CC\u0628\u06CC ALT + F9 \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u0646\u0645\u0627\u06CC\u06CC\u062F.\n\u062C\u0647\u062A \u0645\u0634\u0627\u0647\u062F\u0647 \u0646\u0648\u0627\u0631 \u0627\u0628\u0632\u0627\u0631 \u0627\u0632 \u06A9\u0644\u06CC\u062F\u0647\u0627\u06CC \u062A\u0631\u06A9\u06CC\u0628\u06CC ALT + F10 \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u0646\u0645\u0627\u06CC\u06CC\u062F.\n\u062C\u0647\u062A \u0645\u0634\u0627\u0647\u062F\u0647 \u0631\u0627\u0647\u0646\u0645\u0627 \u0627\u0632 \u06A9\u0644\u06CC\u062F\u0647\u0627\u06CC \u062A\u0631\u06A9\u06CC\u0628\u06CC ALT + 0 \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u0646\u0645\u0627\u06CC\u06CC\u062F.',
'Image title': '\u0639\u0646\u0648\u0627\u0646 \u062A\u0635\u0648\u06CC\u0631',
'Border width': '\u0639\u0631\u0636 \u062D\u0627\u0634\u06CC\u0647',
'Border style': '\u0633\u0628\u06A9 \u062D\u0627\u0634\u06CC\u0647',
Error: '\u062E\u0637\u0627',
Warn: '\u0647\u0634\u062F\u0627\u0631',
Valid: '\u0645\u0639\u062A\u0628\u0631',
'To open the popup, press Shift+Enter':
'\u062C\u0647\u062A \u0628\u0627\u0632 \u06A9\u0631\u062F\u0646 \u067E\u0646\u062C\u0631\u0647 \u0628\u0627\u0632\u0634\u0648\u060C \u06A9\u0644\u06CC\u062F\u0647\u0627\u06CC Shift + Enter \u0631\u0627 \u0641\u0634\u0627\u0631 \u062F\u0647\u06CC\u062F.',
'Rich Text Area. Press ALT-0 for help.':
'\u0646\u0627\u062D\u06CC\u0647 \u0645\u062A\u0646 \u063A\u0646\u06CC. \u062C\u0647\u062A \u0645\u0634\u0627\u0647\u062F\u0647\u0654 \u0631\u0627\u0647\u0646\u0645\u0627 \u06A9\u0644\u06CC\u062F\u0647\u0627\u06CC ALT + 0 \u0631\u0627 \u0641\u0634\u0627\u0631 \u062F\u0647\u06CC\u062F.',
'System Font': '\u0641\u0648\u0646\u062A \u0633\u06CC\u0633\u062A\u0645\u06CC',
'Failed to upload image: {0}':
'\u0639\u062F\u0645 \u0645\u0648\u0641\u0642\u06CC\u062A \u062F\u0631 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u062A\u0635\u0648\u06CC\u0631: {0}',
'Failed to load plugin: {0} from url {1}':
'\u0639\u062F\u0645 \u0645\u0648\u0641\u0642\u06CC\u062A \u062F\u0631 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0627\u0641\u0632\u0648\u0646\u0647: {0} \u0627\u0632 \u0646\u0634\u0627\u0646\u06CC \u0648\u0628 {1}',
'Failed to load plugin url: {0}':
'\u0639\u062F\u0645 \u0645\u0648\u0641\u0642\u06CC\u062A \u062F\u0631 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0646\u0634\u0627\u0646\u06CC \u0648\u0628 \u0627\u0641\u0632\u0648\u0646\u0647: {0}',
'Failed to initialize plugin: {0}':
'\u0639\u062F\u0645 \u0645\u0648\u0641\u0642\u06CC\u062A \u062F\u0631 \u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u0627\u0641\u0632\u0648\u0646\u0647: {0}',
example: '\u0645\u062B\u0627\u0644',
Search: '\u062C\u0633\u062A\u062C\u0648',
All: '\u0647\u0645\u0647',
Currency: '\u0627\u0631\u0632',
Text: '\u0645\u062A\u0646',
Quotations: '\u0646\u0642\u0644\u200C\u0642\u0648\u0644\u200C\u0647\u0627',
Mathematical: '\u0631\u06CC\u0627\u0636\u06CC',
'Extended Latin': '\u0644\u0627\u062A\u06CC\u0646 \u06AF\u0633\u062A\u0631\u062F\u0647',
Symbols: '\u0646\u0645\u0627\u062F\u0647\u0627',
Arrows: '\u067E\u06CC\u06A9\u0627\u0646\u200C\u0647\u0627',
'User Defined': '\u0628\u0647 \u062E\u0648\u0627\u0633\u062A \u06A9\u0627\u0631\u0628\u0631',
'dollar sign': '\u0646\u0645\u0627\u062F \u062F\u0644\u0627\u0631',
'currency sign': '\u0646\u0645\u0627\u062F \u0627\u0631\u0632',
'euro-currency sign': '\u0646\u0645\u0627\u062F \u06CC\u0648\u0631\u0648',
'colon sign': '\u0646\u0645\u0627\u062F \u062F\u0648\u0646\u0642\u0637\u0647',
'cruzeiro sign': '\u0646\u0645\u0627\u062F \u06A9\u0631\u0648\u0632\u06CC\u0631\u0648',
'french franc sign':
'\u0646\u0645\u0627\u062F \u0641\u0631\u0627\u0646\u06A9 \u0641\u0631\u0627\u0646\u0633\u0647',
'lira sign': '\u0646\u0645\u0627\u062F \u0644\u06CC\u0631\u0647',
'mill sign': '\u0646\u0645\u0627\u062F \u0645\u06CC\u0644',
'naira sign': '\u0646\u0645\u0627\u062F \u0646\u0627\u06CC\u0631\u0627',
'peseta sign': '\u0646\u0645\u0627\u062F \u067E\u0632\u062A\u0627',
'rupee sign': '\u0646\u0645\u0627\u062F \u0631\u0648\u067E\u06CC\u0647',
'won sign': '\u0646\u0645\u0627\u062F \u0648\u0648\u0646',
'new sheqel sign': '\u0646\u0645\u0627\u062F \u0634\u06A9\u0644 \u062C\u062F\u06CC\u062F',
'dong sign': '\u0646\u0645\u0627\u062F \u062F\u0627\u0646\u06AF',
'kip sign': '\u0646\u0645\u0627\u062F \u06A9\u06CC\u067E',
'tugrik sign': '\u0646\u0645\u0627\u062F \u062A\u0648\u06AF\u0631\u0648\u06AF',
'drachma sign': '\u0646\u0645\u0627\u062F \u062F\u0631\u0627\u062E\u0645\u0627',
'german penny symbol':
'\u0646\u0645\u0627\u062F \u067E\u0646\u06CC \u0622\u0644\u0645\u0627\u0646\u06CC',
'peso sign': '\u0646\u0645\u0627\u062F \u067E\u0632\u0648',
'guarani sign': '\u0646\u0645\u0627\u062F \u06AF\u0648\u0627\u0631\u0627\u0646\u06CC',
'austral sign': '\u0646\u0645\u0627\u062F \u0622\u0633\u062A\u0631\u0627\u0644',
'hryvnia sign': '\u0646\u0645\u0627\u062F \u06AF\u0631\u06CC\u0648\u0646\u0627',
'cedi sign': '\u0646\u0645\u0627\u062F \u0633\u062F\u06CC',
'livre tournois sign':
'\u0646\u0645\u0627\u062F \u0644\u06CC\u0648\u0631\u0647 \u062A\u0648\u0631\u0646\u0648\u0627',
'spesmilo sign': '\u0646\u0645\u0627\u062F \u0627\u0633\u067E\u0633\u0645\u06CC\u0644\u0648',
'tenge sign': '\u0646\u0645\u0627\u062F \u062A\u0646\u06AF\u0647',
'indian rupee sign':
'\u0646\u0645\u0627\u062F \u0631\u0648\u067E\u06CC\u0647 \u0647\u0646\u062F\u06CC',
'turkish lira sign': '\u0646\u0645\u0627\u062F \u0644\u06CC\u0631\u0647 \u062A\u0631\u06A9\u06CC',
'nordic mark sign': '\u0646\u0645\u0627\u062F \u0645\u0627\u0631\u06A9 \u0646\u0631\u0648\u0698',
'manat sign': '\u0646\u0645\u0627\u062F \u0645\u0646\u0627\u062A',
'ruble sign': '\u0646\u0645\u0627\u062F \u0631\u0648\u0628\u0644',
'yen character': '\u0646\u0648\u06CC\u0633\u0647 \u06CC\u0646',
'yuan character': '\u0646\u0648\u06CC\u0633\u0647 \u06CC\u0648\u0627\u0646',
'yuan character, in hong kong and taiwan':
'\u0646\u0648\u06CC\u0633\u0647 \u06CC\u0648\u0627\u0646\u060C \u062F\u0631 \u0647\u0646\u06AF\u200C\u06A9\u0646\u06AF \u0648 \u062A\u0627\u06CC\u0648\u0627\u0646',
'yen/yuan character variant one':
'\u0646\u0648\u06CC\u0633\u0647 \u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646 \u06CC\u0646/\u06CC\u0648\u0627\u0646',
'Loading emoticons...':
'\u062F\u0631 \u062D\u0627\u0644 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0634\u06A9\u0644\u06A9\u200C\u0647\u0627...',
'Could not load emoticons':
'\u0634\u06A9\u0644\u06A9\u200C\u0647\u0627 \u0628\u0627\u0631\u06AF\u0630\u0627\u0631\u06CC \u0646\u0634\u062F\u0646\u062F',
People: '\u0627\u0641\u0631\u0627\u062F',
'Animals and Nature':
'\u062D\u06CC\u0648\u0627\u0646\u0627\u062A \u0648 \u0637\u0628\u06CC\u0639\u062A',
'Food and Drink': '\u063A\u0630\u0627 \u0648 \u0646\u0648\u0634\u06CC\u062F\u0646\u06CC',
Activity: '\u0641\u0639\u0627\u0644\u06CC\u062A',
'Travel and Places': '\u0633\u0641\u0631 \u0648 \u0627\u0645\u0627\u06A9\u0646',
Objects: '\u0627\u0634\u06CC\u0627',
Flags: '\u067E\u0631\u0686\u0645\u200C\u0647\u0627',
Characters: '\u0646\u0648\u06CC\u0633\u0647\u200C\u0647\u0627',
'Characters (no spaces)':
'\u0646\u0648\u06CC\u0633\u0647 \u0647\u0627 (\u0628\u062F\u0648\u0646 \u0641\u0627\u0635\u0644\u0647)',
'Error: Form submit field collision.':
'\u062E\u0637\u0627: \u062A\u062F\u0627\u062E\u0644 \u062F\u0631 \u062B\u0628\u062A \u0641\u0631\u0645.',
'Error: No form element found.':
'\u062E\u0637\u0627: \u0647\u06CC\u0686 \u0627\u0644\u0645\u0627\u0646 \u0641\u0631\u0645\u06CC \u06CC\u0627\u0641\u062A \u0646\u0634\u062F.',
Update: '\u0628\u0647\u200C\u0631\u0648\u0632\u0631\u0633\u0627\u0646\u06CC',
'Color swatch': '\u0646\u0645\u0648\u0646\u0647 \u0631\u0646\u06AF',
Turquoise: '\u0641\u06CC\u0631\u0648\u0632\u0647\u200C\u0627\u06CC',
Green: '\u0633\u0628\u0632',
Blue: '\u0622\u0628\u06CC',
Purple: '\u0628\u0646\u0641\u0634',
'Navy Blue': '\u0633\u0631\u0645\u0647\u200C\u0627\u06CC',
'Dark Turquoise':
'\u0641\u06CC\u0631\u0648\u0632\u0647\u200C\u0627\u06CC \u062A\u06CC\u0631\u0647',
'Dark Green': '\u0633\u0628\u0632 \u062A\u06CC\u0631\u0647',
'Medium Blue': '\u0622\u0628\u06CC \u0633\u06CC\u0631',
'Medium Purple': '\u0622\u0628\u06CC \u0628\u0646\u0641\u0634',
'Midnight Blue': '\u0622\u0628\u06CC \u0646\u0641\u062A\u06CC',
Yellow: '\u0632\u0631\u062F',
Orange: '\u0646\u0627\u0631\u0646\u062C\u06CC',
Red: '\u0642\u0631\u0645\u0632',
'Light Gray': '\u062E\u0627\u06A9\u0633\u062A\u0631\u06CC \u0631\u0648\u0634\u0646',
Gray: '\u062E\u0627\u06A9\u0633\u062A\u0631\u06CC',
'Dark Yellow': '\u0632\u0631\u062F \u062A\u06CC\u0631\u0647',
'Dark Orange': '\u0646\u0627\u0631\u0646\u062C\u06CC \u062A\u06CC\u0631\u0647',
'Dark Red': '\u0642\u0631\u0645\u0632 \u062A\u06CC\u0631\u0647',
'Medium Gray':
'\u062E\u0627\u06A9\u0633\u062A\u0631\u06CC \u0646\u06CC\u0645\u0647\u200C\u0631\u0648\u0634\u0646',
'Dark Gray': '\u062E\u0627\u06A9\u0633\u062A\u0631\u06CC \u062A\u06CC\u0631\u0647',
Black: '\u0633\u06CC\u0627\u0647',
White: '\u0633\u0641\u06CC\u062F',
'Switch to or from fullscreen mode':
'\u062A\u063A\u06CC\u06CC\u0631 \u0627\u0632 \u062D\u0627\u0644\u062A \u062A\u0645\u0627\u0645\u200C\u0635\u0641\u062D\u0647 \u06CC\u0627 \u0628\u0647 \u062D\u0627\u0644\u062A \u062A\u0645\u0627\u0645\u200C\u0635\u0641\u062D\u0647',
'Open help dialog':
'\u0628\u0627\u0632 \u06A9\u0631\u062F\u0646 \u06A9\u0627\u062F\u0631 \u0631\u0627\u0647\u0646\u0645\u0627',
history: '\u062A\u0627\u0631\u06CC\u062E\u0686\u0647',
styles: '\u0633\u0628\u06A9\u200C\u0647\u0627',
formatting: '\u0642\u0627\u0644\u0628\u200C\u0628\u0646\u062F\u06CC',
alignment: '\u062A\u0631\u0627\u0632\u0628\u0646\u062F\u06CC',
indentation: '\u062A\u0648\u0631\u0641\u062A\u06AF\u06CC',
'permanent pen': '\u0642\u0644\u0645 \u062F\u0627\u0626\u0645\u06CC',
comments: '\u0646\u0638\u0631\u0627\u062A',
Anchor: '\u0642\u0644\u0627\u0628',
'Special character': '\u0646\u0648\u06CC\u0633\u0647 \u0647\u0627\u06CC \u062E\u0627\u0635',
'Code sample': '\u0646\u0645\u0648\u0646\u0647 \u06A9\u064F\u062F',
Color: '\u0631\u0646\u06AF',
Emoticons: '\u0635\u0648\u0631\u062A\u06A9 \u0647\u0627',
'Document properties': '\u062A\u0646\u0638\u06CC\u0645\u0627\u062A \u0633\u0646\u062F',
Image: '\u062A\u0635\u0648\u06CC\u0631',
'Insert link': '\u062F\u0631\u062C \u067E\u06CC\u0648\u0646\u062F',
Target: '\u0645\u0642\u0635\u062F',
Link: '\u067E\u06CC\u0648\u0646\u062F',
Poster: '\u067E\u0648\u0633\u062A\u0631',
Media: '\u0631\u0633\u0627\u0646\u0647',
Print: '\u0686\u0627\u067E',
Prev: '\u0642\u0628\u0644\u06CC',
'Find and replace':
'\u062C\u0633\u062A\u062C\u0648 \u0648 \u062C\u0627\u06CC\u06AF\u0632\u06CC\u0646\u06CC',
'Whole words': '\u062A\u0645\u0627\u0645 \u0648\u0627\u0698\u06AF\u0627\u0646',
Spellcheck: '\u0628\u0631\u0631\u0633\u06CC \u0627\u0645\u0644\u0627\u0621',
Caption: '\u0639\u0646\u0648\u0627\u0646',
'Insert template': '\u062F\u0631\u062C \u0627\u0644\u06AF\u0648',
_dir: 'rtl',
})
+2 -4
View File
@@ -1,6 +1,4 @@
import axios from 'axios'
export const initTiny = (batch_id) => ({
export const initTiny = (_batchId) => ({
skin: false,
height: 500,
menubar: 'tools',
@@ -26,5 +24,5 @@ export const initTiny = (batch_id) => ({
automatic_uploads: false,
file_picker_types: 'file image media',
content_style: 'body { font-family: "IranYekan-Regular", "Montserrat-Regular" !important; }',
images_upload_handler: (blobInfo, success, failure) => {},
images_upload_handler: (_blobInfo, _success, _failure) => {},
})
+2 -5
View File
@@ -84,10 +84,7 @@ export const endpoints = {
deleteSession: '/sessions/:id',
// ─── Backend-aligned: Exams ────────────────────────────────────────────────
// `getExamsList` is not yet in the backend Postman doc, but per the user
// the backend will add it at /exams — wired up now so the FE doesn't need
// to change when the endpoint lands.
getExamsList: '/exams',
getExamsList: '/admin/exams',
showExam: '/exams/:id',
addNewExam: '/exams',
updateExam: '/exams/:id',
@@ -134,7 +131,7 @@ export const endpoints = {
// backend Postman doc currently exposes only create/update/delete/submit/review;
// list + show + submissions list + show-submission stay mock-only until backend
// adds them, but URL shape is locked in.
getAssignmentsList: '/homeworks',
getAssignmentsList: '/admin/homeworks',
showAssignment: '/homeworks/:id',
getAssignmentSubmissions: '/homeworks/:homeworkId/submissions',
showAssignmentSubmission: '/homework-submissions/:submissionId',
+2 -2
View File
@@ -61,7 +61,7 @@ const addCamelizeInterceptor = (instance) => {
)
}
const addUnauthorizeInterceptor = (instance) => {
const _addUnauthorizeInterceptor = (instance) => {
instance.interceptors.response.use(
(res) => res,
async (e) => {
@@ -89,7 +89,7 @@ const createInstance = (baseUrl, { headers = {}, ...configs } = {}) => {
addResponseUnwrapInterceptor(instance)
addCamelizeInterceptor(instance)
addSnakizeInterceptor(instance)
// addUnauthorizeInterceptor(instance)
// _addUnauthorizeInterceptor(instance)
return instance
}
@@ -20,11 +20,18 @@ const computeDurationDays = (start, end) => {
return diff >= 0 ? diff : null
}
const courseTermId = (courseId) => {
if (courseId == null) return null
const course = adminCourses.find((c) => c.id === Number(courseId))
return course?.termId ?? course?.term?.id ?? null
}
register('GET', endpoints.getAssignmentsList, ({ query }) => {
let list = filterItems(adminAssignments, query, {
title: 'includes',
courseId: (item, v) => String(item.course?.id) === String(v),
sessionId: (item, v) => String(item.session?.id) === String(v),
termId: (item, v) => String(courseTermId(item.course?.id)) === String(v),
})
list = filterDateRange(list, query)
return paginate(list, query)
+5
View File
@@ -29,6 +29,11 @@ register('GET', endpoints.getExamsList, ({ query }) => {
title: 'includes',
courseId: (item, v) => String(item.course?.id) === String(v),
sessionId: (item, v) => String(item.sessionId) === String(v),
termId: (item, v) => {
const course = adminCourses.find((c) => c.id === Number(item.course?.id))
const termId = course?.termId ?? course?.term?.id ?? null
return String(termId) === String(v)
},
})
list = filterDateRange(list, query)
const { data: items, meta } = paginate(list, query)
+5 -7
View File
@@ -134,14 +134,12 @@ register('PATCH', endpoints.updateUserRole, ({ params, data }) => {
const nextRoleNames = Array.isArray(data.roles)
? data.roles.filter(Boolean)
: data.role
? [data.role]
: data.roleId
? [roles.find((r) => r.id === Number(data.roleId))?.name].filter(Boolean)
: []
? [data.role]
: data.roleId
? [roles.find((r) => r.id === Number(data.roleId))?.name].filter(Boolean)
: []
const primary = nextRoleNames[0] ? byName(nextRoleNames[0]) : null
const patch = nextRoleNames.length
? { roles: nextRoleNames, roleId: primary?.id }
: {}
const patch = nextRoleNames.length > 0 ? { roles: nextRoleNames, roleId: primary?.id } : {}
const updated = updateById(adminUsers, params.id, patch)
return {
success: true,
+8
View File
@@ -41,6 +41,10 @@ export const useAdminAssignmentsListQuery = (filtersRef, paginationRef, options
...cleanFilters(filtersRef.value),
...paginationRef.value,
}),
select: (response) => ({
data: response?.data?.items ?? response?.data ?? [],
meta: response?.data?.meta ?? response?.meta,
}),
...options,
})
@@ -65,6 +69,10 @@ export const useAdminAssignmentSubmissionsQuery = (
...cleanFilters(filtersRef?.value || {}),
...paginationRef?.value,
}),
select: (response) => ({
data: response?.data?.items ?? response?.data ?? [],
meta: response?.data?.meta ?? response?.meta,
}),
...options,
})
+1 -2
View File
@@ -80,5 +80,4 @@ export const useGetRegisterDataQuery = (options = {}) =>
...options,
})
export const useSaveRegisterDataMutation = () =>
useMutation({ mutationFn: apiSaveRegisterData })
export const useSaveRegisterDataMutation = () => useMutation({ mutationFn: apiSaveRegisterData })
+1 -1
View File
@@ -10,7 +10,7 @@ export const useAuthStore = defineStore('auth', () => {
const role = computed(() => {
const u = user.value
if (!u) return null
if (Array.isArray(u.roles) && u.roles.length) return u.roles[0]
if (Array.isArray(u.roles) && u.roles.length > 0) return u.roles[0]
return u.role || u.roleName || null
})
+8 -4
View File
@@ -1,7 +1,11 @@
.mce-container,
.mce-container *,
.mce-widget,
.mce-widget *,
.mce-reset {
font-family: iranyekan, Montserrat, tinymce !important;
}
.mce-container,.mce-container *,.mce-widget,.mce-widget *,.mce-reset {
font-family:"iranyekan", "Montserrat", "tinymce"!important;
}
.mce-monospace {
font-family:"iranyekan", "Montserrat", "tinymce"!important;
font-family: iranyekan, Montserrat, tinymce !important;
}