Merge branch 'master' of https://github.com/nextcloud/forms
This commit is contained in:
commit
15e35f51c2
|
@ -1,6 +1,11 @@
|
|||
OC.L10N.register(
|
||||
"forms",
|
||||
{
|
||||
"Anonymous response" : "익명 답변",
|
||||
"Shared by %s" : "%s에 의해 공유됨",
|
||||
"New form" : "새로운 형식",
|
||||
"Loading forms …" : "형식 로딩중 ...",
|
||||
"Create a form" : "형식 생성",
|
||||
"Create new form" : "새로운 양식 생성",
|
||||
"An error occurred while loading the forms list" : "양식 리스트를 가져오는데 문제가 발생하였습니다.",
|
||||
"Unable to create a new form" : "새 양식 생성할 수 없음",
|
||||
|
@ -9,8 +14,11 @@ OC.L10N.register(
|
|||
"Are you sure you want to delete {title}?" : "정말로 {title}을 삭제할 것입니까?",
|
||||
"Error while deleting {title}" : "{title} 삭제 실패",
|
||||
"Answer number {index}" : "응답 번호 {index}",
|
||||
"Delete answer" : "답변 지우기",
|
||||
"Error while saving the answer" : "응답 저장 실패",
|
||||
"Question title" : "질문 제목",
|
||||
"Delete question" : "질문 삭제",
|
||||
"Delete this response" : "이 응답 지우기",
|
||||
"Searching …" : "검색 ...",
|
||||
"Group" : "그룹",
|
||||
"Description" : "설명",
|
||||
|
@ -21,6 +29,7 @@ OC.L10N.register(
|
|||
"Expiration date" : "만료 일자",
|
||||
"Sharing" : "공유",
|
||||
"Share link" : "링크 공유",
|
||||
"Select expiration date" : "만료일자를 고르시오.",
|
||||
"Submit" : "제출",
|
||||
"Thank you for completing the form!" : "양식을 작성해주셔서 감사합니다!",
|
||||
"There was an error submitting the form" : "양식 제출 실패",
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
{ "translations": {
|
||||
"Anonymous response" : "익명 답변",
|
||||
"Shared by %s" : "%s에 의해 공유됨",
|
||||
"New form" : "새로운 형식",
|
||||
"Loading forms …" : "형식 로딩중 ...",
|
||||
"Create a form" : "형식 생성",
|
||||
"Create new form" : "새로운 양식 생성",
|
||||
"An error occurred while loading the forms list" : "양식 리스트를 가져오는데 문제가 발생하였습니다.",
|
||||
"Unable to create a new form" : "새 양식 생성할 수 없음",
|
||||
|
@ -7,8 +12,11 @@
|
|||
"Are you sure you want to delete {title}?" : "정말로 {title}을 삭제할 것입니까?",
|
||||
"Error while deleting {title}" : "{title} 삭제 실패",
|
||||
"Answer number {index}" : "응답 번호 {index}",
|
||||
"Delete answer" : "답변 지우기",
|
||||
"Error while saving the answer" : "응답 저장 실패",
|
||||
"Question title" : "질문 제목",
|
||||
"Delete question" : "질문 삭제",
|
||||
"Delete this response" : "이 응답 지우기",
|
||||
"Searching …" : "검색 ...",
|
||||
"Group" : "그룹",
|
||||
"Description" : "설명",
|
||||
|
@ -19,6 +27,7 @@
|
|||
"Expiration date" : "만료 일자",
|
||||
"Sharing" : "공유",
|
||||
"Share link" : "링크 공유",
|
||||
"Select expiration date" : "만료일자를 고르시오.",
|
||||
"Submit" : "제출",
|
||||
"Thank you for completing the form!" : "양식을 작성해주셔서 감사합니다!",
|
||||
"There was an error submitting the form" : "양식 제출 실패",
|
||||
|
|
58
l10n/sl.js
58
l10n/sl.js
|
@ -1,20 +1,76 @@
|
|||
OC.L10N.register(
|
||||
"forms",
|
||||
{
|
||||
"Anonymous response" : "Anonimni odziv",
|
||||
"Forms" : "Vprašalniki",
|
||||
"📝 Simple surveys and questionnaires, self-hosted" : "Enostavni vprašalnik in ankete na domačem strežniku",
|
||||
"New form" : "Nov vprašalnik",
|
||||
"Loading forms …" : "Poteka nalaganje vprašalnikov …",
|
||||
"No forms created yet" : "Ni še ustvarjenih vprašalnikov",
|
||||
"Create a form" : "Ustvarite vprašalnik",
|
||||
"Select a form or create a new one" : "Izberite vprašalnik oziroma ustvarite novega",
|
||||
"Create new form" : "Ustvari nov vprašalnik",
|
||||
"An error occurred while loading the forms list" : "Med nalaganjem seznama vprašalnikov je prišlo do napake",
|
||||
"Unable to create a new form" : "Novega vprašalnika ni mogoče ustvariti",
|
||||
"Responses" : "Odzivi",
|
||||
"Clone form" : "Kloniraj vprašalnik",
|
||||
"Delete form" : "Izbriši vprašalnik",
|
||||
"Form link copied" : "Povezava vprašalnika je kopirana",
|
||||
"Cannot copy, please copy the link manually" : "Povezave ni mogoče kopirati. Storite to ročno.",
|
||||
"Copy share link" : "Kopiraj povezavo souporabe",
|
||||
"Are you sure you want to delete {title}?" : "Ali ste prepričani, da želite izbrisati vprašalnik {title}?",
|
||||
"Delete answer" : "Izbriši odgovor",
|
||||
"There was an issue deleting this option" : "Prišlo je do napake med brisanjem možnosti",
|
||||
"Error while saving the answer" : "Prišlo je do napake med shranjevanjem odgovora",
|
||||
"Question number {index}" : "Vprašanje številka {index}",
|
||||
"Drag to reorder the questions" : "Potegnite vprašanja in jih preuredite",
|
||||
"Question title" : "Naslov vprašanja",
|
||||
"Title of question number {index}" : "Naslov vprašanja številka {index}",
|
||||
"Mandatory" : "Obvezno",
|
||||
"Delete question" : "Izbriši vprašanje",
|
||||
"A long answer for the question “{text}”" : "Dolg odgovor na vprašanje »{text}«",
|
||||
"Long answer text" : "Besedilo dolgega odgovora",
|
||||
"Add a new answer" : "Dodaj nov odgovor",
|
||||
"A short answer for the question “{text}”" : "Kratek odgovor na vprašanje »{text}«",
|
||||
"Short answer text" : "Besedilo kratkega odgovora",
|
||||
"Delete this response" : "Izbriši ta odziv",
|
||||
"User or group name …" : "Ime uporabnika oziroma skupine ...",
|
||||
"No recommendations. Start typing." : "Ni priporočil; začnite vpisovati",
|
||||
"Searching …" : "Poteka iskanje ...",
|
||||
"No elements found." : "Ni najdenih predmetov",
|
||||
"Group" : "Skupina",
|
||||
"Loading {title} …" : "Poteka nalaganje {title} …",
|
||||
"Toggle settings" : "Preklopi nastavitve",
|
||||
"Form title" : "Naslov vprašalnika",
|
||||
"Description" : "Opis",
|
||||
"Mandatory questions" : "Obvezna vprašanja",
|
||||
"Add a question" : "Dodaj vprašanje",
|
||||
"There was an error while adding the new question" : "Prišlo je do napake med dodajanjem novega vprašanja",
|
||||
"There was an error while removing the question" : "Prišlo je do napake med odstranjevanjem vprašanja",
|
||||
"Error while saving form" : "Prišlo je do napake med shranjevanjem vprašalnika",
|
||||
"Loading responses …" : "Poteka nalaganje odzivov ...",
|
||||
"Back to questions" : "Nazaj na vprašanja",
|
||||
"Responses for {title}" : "Odzivi za vprašalnik {title}",
|
||||
"Export to CSV" : "Izvozi v datoteko CSV",
|
||||
"Options" : "Možnosti",
|
||||
"Delete all responses" : "Izbriši vse odzive",
|
||||
"No responses yet" : "Ni še odzivov",
|
||||
"Settings" : "Nastavitve",
|
||||
"Anonymous responses" : "Anonimni odzivi",
|
||||
"Set expiration date" : "Nastavi datum preteka",
|
||||
"Expiration date" : "Datum preteka",
|
||||
"Sharing" : "Souporaba",
|
||||
"Share link" : "Povezava za souporabo",
|
||||
"Submit" : "Pošlji"
|
||||
"Submit" : "Pošlji",
|
||||
"Submit form" : "Objavi obrazec",
|
||||
"Submitting form …" : "Poteka objavljanje obrazca ...",
|
||||
"Error while saving question" : "Prišlo je do napake med shranjevanjem vprašanja",
|
||||
"Multiple choice" : "Izbirno vprašanje",
|
||||
"Checkboxes" : "Izbirna polja",
|
||||
"Short answer" : "Kratek odgovor",
|
||||
"Long text" : "Dolg odgovor",
|
||||
"Form expired" : "Vprašalnik je potekel",
|
||||
"Form not found" : "Vprašalnika ni mogoče najti",
|
||||
"This form does not exist" : "Ta vprašalnik ne obstaja"
|
||||
},
|
||||
"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);");
|
||||
|
|
58
l10n/sl.json
58
l10n/sl.json
|
@ -1,18 +1,74 @@
|
|||
{ "translations": {
|
||||
"Anonymous response" : "Anonimni odziv",
|
||||
"Forms" : "Vprašalniki",
|
||||
"📝 Simple surveys and questionnaires, self-hosted" : "Enostavni vprašalnik in ankete na domačem strežniku",
|
||||
"New form" : "Nov vprašalnik",
|
||||
"Loading forms …" : "Poteka nalaganje vprašalnikov …",
|
||||
"No forms created yet" : "Ni še ustvarjenih vprašalnikov",
|
||||
"Create a form" : "Ustvarite vprašalnik",
|
||||
"Select a form or create a new one" : "Izberite vprašalnik oziroma ustvarite novega",
|
||||
"Create new form" : "Ustvari nov vprašalnik",
|
||||
"An error occurred while loading the forms list" : "Med nalaganjem seznama vprašalnikov je prišlo do napake",
|
||||
"Unable to create a new form" : "Novega vprašalnika ni mogoče ustvariti",
|
||||
"Responses" : "Odzivi",
|
||||
"Clone form" : "Kloniraj vprašalnik",
|
||||
"Delete form" : "Izbriši vprašalnik",
|
||||
"Form link copied" : "Povezava vprašalnika je kopirana",
|
||||
"Cannot copy, please copy the link manually" : "Povezave ni mogoče kopirati. Storite to ročno.",
|
||||
"Copy share link" : "Kopiraj povezavo souporabe",
|
||||
"Are you sure you want to delete {title}?" : "Ali ste prepričani, da želite izbrisati vprašalnik {title}?",
|
||||
"Delete answer" : "Izbriši odgovor",
|
||||
"There was an issue deleting this option" : "Prišlo je do napake med brisanjem možnosti",
|
||||
"Error while saving the answer" : "Prišlo je do napake med shranjevanjem odgovora",
|
||||
"Question number {index}" : "Vprašanje številka {index}",
|
||||
"Drag to reorder the questions" : "Potegnite vprašanja in jih preuredite",
|
||||
"Question title" : "Naslov vprašanja",
|
||||
"Title of question number {index}" : "Naslov vprašanja številka {index}",
|
||||
"Mandatory" : "Obvezno",
|
||||
"Delete question" : "Izbriši vprašanje",
|
||||
"A long answer for the question “{text}”" : "Dolg odgovor na vprašanje »{text}«",
|
||||
"Long answer text" : "Besedilo dolgega odgovora",
|
||||
"Add a new answer" : "Dodaj nov odgovor",
|
||||
"A short answer for the question “{text}”" : "Kratek odgovor na vprašanje »{text}«",
|
||||
"Short answer text" : "Besedilo kratkega odgovora",
|
||||
"Delete this response" : "Izbriši ta odziv",
|
||||
"User or group name …" : "Ime uporabnika oziroma skupine ...",
|
||||
"No recommendations. Start typing." : "Ni priporočil; začnite vpisovati",
|
||||
"Searching …" : "Poteka iskanje ...",
|
||||
"No elements found." : "Ni najdenih predmetov",
|
||||
"Group" : "Skupina",
|
||||
"Loading {title} …" : "Poteka nalaganje {title} …",
|
||||
"Toggle settings" : "Preklopi nastavitve",
|
||||
"Form title" : "Naslov vprašalnika",
|
||||
"Description" : "Opis",
|
||||
"Mandatory questions" : "Obvezna vprašanja",
|
||||
"Add a question" : "Dodaj vprašanje",
|
||||
"There was an error while adding the new question" : "Prišlo je do napake med dodajanjem novega vprašanja",
|
||||
"There was an error while removing the question" : "Prišlo je do napake med odstranjevanjem vprašanja",
|
||||
"Error while saving form" : "Prišlo je do napake med shranjevanjem vprašalnika",
|
||||
"Loading responses …" : "Poteka nalaganje odzivov ...",
|
||||
"Back to questions" : "Nazaj na vprašanja",
|
||||
"Responses for {title}" : "Odzivi za vprašalnik {title}",
|
||||
"Export to CSV" : "Izvozi v datoteko CSV",
|
||||
"Options" : "Možnosti",
|
||||
"Delete all responses" : "Izbriši vse odzive",
|
||||
"No responses yet" : "Ni še odzivov",
|
||||
"Settings" : "Nastavitve",
|
||||
"Anonymous responses" : "Anonimni odzivi",
|
||||
"Set expiration date" : "Nastavi datum preteka",
|
||||
"Expiration date" : "Datum preteka",
|
||||
"Sharing" : "Souporaba",
|
||||
"Share link" : "Povezava za souporabo",
|
||||
"Submit" : "Pošlji"
|
||||
"Submit" : "Pošlji",
|
||||
"Submit form" : "Objavi obrazec",
|
||||
"Submitting form …" : "Poteka objavljanje obrazca ...",
|
||||
"Error while saving question" : "Prišlo je do napake med shranjevanjem vprašanja",
|
||||
"Multiple choice" : "Izbirno vprašanje",
|
||||
"Checkboxes" : "Izbirna polja",
|
||||
"Short answer" : "Kratek odgovor",
|
||||
"Long text" : "Dolg odgovor",
|
||||
"Form expired" : "Vprašalnik je potekel",
|
||||
"Form not found" : "Vprašalnika ni mogoče najti",
|
||||
"This form does not exist" : "Ta vprašalnik ne obstaja"
|
||||
},"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"
|
||||
}
|
|
@ -7,4 +7,4 @@ OC.L10N.register(
|
|||
"Sharing" : "ھەمبەھىر",
|
||||
"Share link" : "Share link"
|
||||
},
|
||||
"nplurals=1; plural=0;");
|
||||
"nplurals=2; plural=(n != 1);");
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
"Settings" : "تەڭشەكلەر",
|
||||
"Sharing" : "ھەمبەھىر",
|
||||
"Share link" : "Share link"
|
||||
},"pluralForm" :"nplurals=1; plural=0;"
|
||||
},"pluralForm" :"nplurals=2; plural=(n != 1);"
|
||||
}
|
|
@ -12,6 +12,7 @@ OC.L10N.register(
|
|||
"Set expiration date" : "Встановити термін дії",
|
||||
"Expiration date" : "Термін дії",
|
||||
"Sharing" : "Поділитись",
|
||||
"Share link" : "Поширити посилання"
|
||||
"Share link" : "Поширити посилання",
|
||||
"Submit" : "Гаразд"
|
||||
},
|
||||
"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);");
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"Set expiration date" : "Встановити термін дії",
|
||||
"Expiration date" : "Термін дії",
|
||||
"Sharing" : "Поділитись",
|
||||
"Share link" : "Поширити посилання"
|
||||
"Share link" : "Поширити посилання",
|
||||
"Submit" : "Гаразд"
|
||||
},"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"
|
||||
}
|
|
@ -648,16 +648,8 @@ class ApiController extends Controller {
|
|||
$submissions[] = $submission;
|
||||
}
|
||||
|
||||
// Load question-texts, including deleted ones.
|
||||
try {
|
||||
$questionEntities = $this->questionMapper->findByForm($form->getId());
|
||||
} catch (DoesNotExistException $e) {
|
||||
//handle silently
|
||||
}
|
||||
$questions = [];
|
||||
foreach ($questionEntities as $questionEntity) {
|
||||
$questions[] = $questionEntity->read();
|
||||
}
|
||||
// Load currently active questions
|
||||
$questions = $this->formsService->getQuestions($form->getId());
|
||||
|
||||
$response = [
|
||||
'submissions' => $submissions,
|
||||
|
|
|
@ -85,7 +85,12 @@ class FormsService {
|
|||
$this->currentUser = $userSession->getUser();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load options corresponding to question
|
||||
*
|
||||
* @param integer $questionId
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions(int $questionId): array {
|
||||
$optionList = [];
|
||||
try {
|
||||
|
@ -100,6 +105,12 @@ class FormsService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load questions corresponding to form
|
||||
*
|
||||
* @param integer $formId
|
||||
* @return array
|
||||
*/
|
||||
public function getQuestions(int $formId): array {
|
||||
$questionList = [];
|
||||
try {
|
||||
|
|
172
package-lock.json
generated
172
package-lock.json
generated
|
@ -2772,11 +2772,12 @@
|
|||
}
|
||||
},
|
||||
"@nextcloud/auth": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.2.3.tgz",
|
||||
"integrity": "sha512-SN0g1nyflt2H34zkCFflOky/h0r9DNHb7T8l/JILyFTCoL8f+f67V2Q4jLLfyapEXgq0b3xG7p8FtrBX5/JhWA==",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/auth/-/auth-1.3.0.tgz",
|
||||
"integrity": "sha512-GfwRM9W7hat4psNdAt74UHEV+drEXQ53klCVp6JpON66ZLPeK5eJ1LQuiQDkpUxZpqNeaumXjiB98h5cug/uQw==",
|
||||
"requires": {
|
||||
"@nextcloud/event-bus": "^1.1.3",
|
||||
"@nextcloud/typings": "^0.2.2",
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
|
@ -2808,9 +2809,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@nextcloud/dialogs": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-1.3.1.tgz",
|
||||
"integrity": "sha512-7mr47trvaqWPcI4agSbfapbBdcSlG/2VJ0cW4MB6HXpgzHUQFpEpHRKTpucR1sU0FJTlOVb7irmJ4aH4jZJ8pg==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-1.4.0.tgz",
|
||||
"integrity": "sha512-Rx4x+al/sy+vXu2p3qvEuVeeUDm5JVwa84S21Hxa+pDV3Pd93E2dJGWlZ6h++5fSXbee1sDX9t957B20kYiP3Q==",
|
||||
"requires": {
|
||||
"core-js": "^3.6.4",
|
||||
"toastify-js": "^1.7.0"
|
||||
|
@ -2832,19 +2833,27 @@
|
|||
}
|
||||
},
|
||||
"@nextcloud/event-bus": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-1.1.4.tgz",
|
||||
"integrity": "sha512-It27KzmUaSQ7w22nHFwOn8XgeVG0HYYOSNG9gs4UkP5VqcZ16m4ydt3GkMpWcyFec4OUjJc+yf7omRc3pNxsSw==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-1.2.0.tgz",
|
||||
"integrity": "sha512-pNS0R6Mvgj4WnbJQ8LYjxRjCbRndpwjHNyZYm0zl8U71gbHsUvQIIzTdW7WYg6Nz/FjAlrdmDXJDFLh1DDcIFA==",
|
||||
"requires": {
|
||||
"@types/semver": "^6.2.1",
|
||||
"@types/semver": "^7.1.0",
|
||||
"core-js": "^3.6.2",
|
||||
"semver": "^6.3.0"
|
||||
"semver": "^7.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/semver": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.2.0.tgz",
|
||||
"integrity": "sha512-TbB0A8ACUWZt3Y6bQPstW9QNbhNeebdgLX4T/ZfkrswAfUzRiXrgd9seol+X379Wa589Pu4UEx9Uok0D4RjRCQ==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
|
||||
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -2857,9 +2866,9 @@
|
|||
}
|
||||
},
|
||||
"@nextcloud/l10n": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.2.3.tgz",
|
||||
"integrity": "sha512-bd/bp/pk24Sl/Fjj3KJhDsGhc5EI1tIs34+sl4eaBNrj7SHl79K9bAzarxtABx6LSXn6pl6K/YYkKCidqPzuDQ==",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-1.3.0.tgz",
|
||||
"integrity": "sha512-hGk3ag9TU4cb0+ld/wziEsE+CWaS7Rpj6Y6dPv0QVfnqQ7jFCKQ62VHnuk8pFQHkmKMg3HGxkHuojumbukm42w==",
|
||||
"requires": {
|
||||
"core-js": "^3.6.4",
|
||||
"node-gettext": "^3.0.0"
|
||||
|
@ -2912,18 +2921,19 @@
|
|||
}
|
||||
},
|
||||
"@nextcloud/router": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.0.2.tgz",
|
||||
"integrity": "sha512-9cGPGZx9P3G/piM3vD8/W37DFcjj4UDUIb9BiKdAG3Ir+7+iI0O/kv7SzvVrEU74a1ohp+wmDUiEQjM02cSFRQ==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-1.1.0.tgz",
|
||||
"integrity": "sha512-iPHpMG9kajw8D+niR4x/d8s/R9RyUNveDsNURgcZryIjIXhAzSZZra55+Y3yInDmLhCFwboj9ZcC/2S6CzoKYA==",
|
||||
"requires": {
|
||||
"core-js": "3.6.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "3.6.4",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
|
||||
"integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw=="
|
||||
}
|
||||
"core-js": "^3.6.4"
|
||||
}
|
||||
},
|
||||
"@nextcloud/typings": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/typings/-/typings-0.2.2.tgz",
|
||||
"integrity": "sha512-LZrv1VV3vyDaKw4UKMcGM9dvLMpdI2tfMexHf/ixVn6OrsRDsRTbxByWMMdRF2ArHD5Q8RsICa72p6BcG9b80Q==",
|
||||
"requires": {
|
||||
"@types/jquery": "2.0.54"
|
||||
}
|
||||
},
|
||||
"@nextcloud/vue": {
|
||||
|
@ -3023,12 +3033,22 @@
|
|||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jquery": {
|
||||
"version": "2.0.54",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-2.0.54.tgz",
|
||||
"integrity": "sha512-D/PomKwNkDfSKD13DEVQT/pq2TUjN54c6uB341fEZanIzkjfGe7UaFuuaLZbpEiS5j7Wk2MUHAZqZIoECw29lg=="
|
||||
},
|
||||
"@types/minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.11.tgz",
|
||||
"integrity": "sha512-lCvvI24L21ZVeIiyIUHZ5Oflv1hhHQ5E1S25IRlKIXaRkVgmXpJMI3wUJkmym2bTbCe+WoIibQnMVAU3FguaOg=="
|
||||
},
|
||||
"@types/normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
|
@ -3794,22 +3814,10 @@
|
|||
"postcss-value-parser": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"browserslist": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz",
|
||||
"integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"caniuse-lite": "^1.0.30001043",
|
||||
"electron-to-chromium": "^1.3.413",
|
||||
"node-releases": "^1.1.53",
|
||||
"pkg-up": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.30",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.30.tgz",
|
||||
"integrity": "sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ==",
|
||||
"version": "7.0.32",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
|
||||
"integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
|
@ -5194,9 +5202,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"entities": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.2.tgz",
|
||||
"integrity": "sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
|
||||
"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
@ -7305,9 +7313,9 @@
|
|||
"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
|
||||
},
|
||||
"globby": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz",
|
||||
"integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==",
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
|
||||
"integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
|
@ -7319,9 +7327,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"ignore": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.6.tgz",
|
||||
"integrity": "sha512-cgXgkypZBcCnOgSihyeqbo6gjIaIyDqPQB7Ra4vhE9m6kigdGoQDMHjviFhRZo3IMlRy6yElosoviMs5YxZXUA==",
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
@ -8716,9 +8724,9 @@
|
|||
}
|
||||
},
|
||||
"merge2": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz",
|
||||
"integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==",
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true
|
||||
},
|
||||
"micromatch": {
|
||||
|
@ -8763,9 +8771,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"min-indent": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz",
|
||||
"integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
|
||||
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
|
||||
"dev": true
|
||||
},
|
||||
"minimalistic-assert": {
|
||||
|
@ -9750,9 +9758,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"postcss": {
|
||||
"version": "7.0.30",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.30.tgz",
|
||||
"integrity": "sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ==",
|
||||
"version": "7.0.32",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
|
||||
"integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
|
@ -9788,9 +9796,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"postcss": {
|
||||
"version": "7.0.30",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.30.tgz",
|
||||
"integrity": "sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ==",
|
||||
"version": "7.0.32",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
|
||||
"integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
|
@ -11338,14 +11346,14 @@
|
|||
"dev": true
|
||||
},
|
||||
"stylelint": {
|
||||
"version": "13.5.0",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.5.0.tgz",
|
||||
"integrity": "sha512-+Jy7ieKAWKTf2tmcAE7jgScxH39Urb87i0bjK/enScFaGWWaFn4kAPwepGOSk2b7CLUDVt/O6kwA0x0p/V7moQ==",
|
||||
"version": "13.6.0",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.6.0.tgz",
|
||||
"integrity": "sha512-55gG2pNjVr183JJM/tlr3KAua6vTVX7Ho/lgKKuCIWszTZ1gmrXjX4Wok53SI8wRYFPbwKAcJGULQ77OJxTcNw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@stylelint/postcss-css-in-js": "^0.37.1",
|
||||
"@stylelint/postcss-markdown": "^0.36.1",
|
||||
"autoprefixer": "^9.7.6",
|
||||
"autoprefixer": "^9.8.0",
|
||||
"balanced-match": "^1.0.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
|
@ -11354,10 +11362,10 @@
|
|||
"file-entry-cache": "^5.0.1",
|
||||
"get-stdin": "^8.0.0",
|
||||
"global-modules": "^2.0.0",
|
||||
"globby": "^11.0.0",
|
||||
"globby": "^11.0.1",
|
||||
"globjoin": "^0.1.4",
|
||||
"html-tags": "^3.1.0",
|
||||
"ignore": "^5.1.4",
|
||||
"ignore": "^5.1.8",
|
||||
"import-lazy": "^4.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"known-css-properties": "^0.19.0",
|
||||
|
@ -11368,7 +11376,7 @@
|
|||
"meow": "^7.0.1",
|
||||
"micromatch": "^4.0.2",
|
||||
"normalize-selector": "^0.2.0",
|
||||
"postcss": "^7.0.30",
|
||||
"postcss": "^7.0.32",
|
||||
"postcss-html": "^0.36.0",
|
||||
"postcss-less": "^3.1.4",
|
||||
"postcss-media-query-parser": "^0.2.3",
|
||||
|
@ -11376,7 +11384,7 @@
|
|||
"postcss-resolve-nested-selector": "^0.1.1",
|
||||
"postcss-safe-parser": "^4.0.2",
|
||||
"postcss-sass": "^0.4.4",
|
||||
"postcss-scss": "^2.0.0",
|
||||
"postcss-scss": "^2.1.1",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
"postcss-syntax": "^0.36.2",
|
||||
"postcss-value-parser": "^4.1.0",
|
||||
|
@ -11389,7 +11397,7 @@
|
|||
"sugarss": "^2.0.0",
|
||||
"svg-tags": "^1.0.0",
|
||||
"table": "^5.4.6",
|
||||
"v8-compile-cache": "^2.1.0",
|
||||
"v8-compile-cache": "^2.1.1",
|
||||
"write-file-atomic": "^3.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -11497,9 +11505,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.6.tgz",
|
||||
"integrity": "sha512-cgXgkypZBcCnOgSihyeqbo6gjIaIyDqPQB7Ra4vhE9m6kigdGoQDMHjviFhRZo3IMlRy6yElosoviMs5YxZXUA==",
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"indent-string": {
|
||||
|
@ -11584,9 +11592,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.30",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.30.tgz",
|
||||
"integrity": "sha512-nu/0m+NtIzoubO+xdAlwZl/u5S5vi/y6BCsoL8D+8IxsD3XvBS8X4YEADNIVXKVuQvduiucnRv+vPIqj56EGMQ==",
|
||||
"version": "7.0.32",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
|
||||
"integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
|
@ -11775,9 +11783,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
|
||||
"integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
|
||||
"integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
|
||||
"dev": true
|
||||
},
|
||||
"yargs-parser": {
|
||||
|
|
12
package.json
12
package.json
|
@ -22,14 +22,14 @@
|
|||
"stylelint:fix": "stylelint css/*.css css/*.scss src/**/*.vue --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": "^1.2.3",
|
||||
"@nextcloud/auth": "^1.3.0",
|
||||
"@nextcloud/axios": "^1.3.2",
|
||||
"@nextcloud/dialogs": "^1.3.1",
|
||||
"@nextcloud/event-bus": "^1.1.4",
|
||||
"@nextcloud/dialogs": "^1.4.0",
|
||||
"@nextcloud/event-bus": "^1.2.0",
|
||||
"@nextcloud/initial-state": "^1.1.2",
|
||||
"@nextcloud/l10n": "^1.2.3",
|
||||
"@nextcloud/l10n": "^1.3.0",
|
||||
"@nextcloud/moment": "^1.1.1",
|
||||
"@nextcloud/router": "^1.0.2",
|
||||
"@nextcloud/router": "^1.1.0",
|
||||
"@nextcloud/vue": "^2.0.0",
|
||||
"core-js": "^3.6.5",
|
||||
"crypto-js": "^4.0.0",
|
||||
|
@ -72,7 +72,7 @@
|
|||
"file-loader": "^6.0.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"stylelint": "^13.5.0",
|
||||
"stylelint": "^13.6.0",
|
||||
"stylelint-config-recommended-scss": "^4.2.0",
|
||||
"stylelint-scss": "^3.17.2",
|
||||
"stylelint-webpack-plugin": "^2.0.0",
|
||||
|
|
|
@ -184,7 +184,7 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
async copyLink() {
|
||||
async copyLink(event) {
|
||||
if (this.$clipboard(this.formLink)) {
|
||||
this.copySuccess = true
|
||||
this.copied = true
|
||||
|
@ -193,6 +193,9 @@ export default {
|
|||
this.copied = true
|
||||
console.debug('Not possible to copy share link')
|
||||
}
|
||||
// Set back focus as clipboard removes focus
|
||||
event.target.focus()
|
||||
|
||||
setTimeout(() => {
|
||||
this.copySuccess = false
|
||||
this.copied = false
|
||||
|
|
|
@ -118,21 +118,8 @@ export default {
|
|||
|
||||
// Dismiss delete key action
|
||||
e.preventDefault()
|
||||
const answer = Object.assign({}, this.answer)
|
||||
const index = this.index
|
||||
|
||||
if (!answer.local) {
|
||||
// let's not await, deleting in background
|
||||
axios.delete(generateUrl('/apps/forms/api/v1/option/{id}', { id: this.answer.id }))
|
||||
.catch(error => {
|
||||
showError(t('forms', 'There was an issue deleting this option'))
|
||||
console.error(error)
|
||||
// restore option
|
||||
this.$emit('restore', answer, index)
|
||||
})
|
||||
}
|
||||
|
||||
this.$emit('delete', answer.id, index)
|
||||
this.$emit('delete', this.answer.id)
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
:maxlength="maxStringLengths.answerText"
|
||||
minlength="1"
|
||||
@input="onInput"
|
||||
@keydown="autoSizeText" />
|
||||
@keypress="autoSizeText"
|
||||
@keydown.ctrl.enter="onKeydownCtrlEnter" />
|
||||
</div>
|
||||
</Question>
|
||||
</template>
|
||||
|
@ -74,6 +75,9 @@ export default {
|
|||
textarea.style.cssText = 'height:auto; padding:0'
|
||||
textarea.style.cssText = `height: ${textarea.scrollHeight + 20}px`
|
||||
},
|
||||
onKeydownCtrlEnter(event) {
|
||||
this.$emit('keydown', event)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -46,7 +46,8 @@
|
|||
:name="`${id}-answer`"
|
||||
:required="isRequired(answer.id)"
|
||||
:type="isUnique ? 'radio' : 'checkbox'"
|
||||
@change="onChange($event, answer.id)">
|
||||
@change="onChange($event, answer.id)"
|
||||
@keydown.enter.exact.prevent="onKeydownEnter">
|
||||
<label v-if="!edit"
|
||||
ref="label"
|
||||
:for="`${id}-answer-${answer.id}`"
|
||||
|
@ -61,9 +62,8 @@
|
|||
:index="index"
|
||||
:max-option-length="maxStringLengths.optionText"
|
||||
@add="addNewEntry"
|
||||
@delete="deleteAnswer"
|
||||
@update:answer="updateAnswer"
|
||||
@restore="restoreAnswer" />
|
||||
@delete="deleteOption"
|
||||
@update:answer="updateAnswer" />
|
||||
</template>
|
||||
|
||||
<li v-if="(edit && !isLastEmpty) || hasNoAnswer" class="question__item">
|
||||
|
@ -81,6 +81,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
import AnswerInput from './AnswerInput'
|
||||
import QuestionMixin from '../../mixins/QuestionMixin'
|
||||
import GenRandomId from '../../utils/GenRandomId'
|
||||
|
@ -118,9 +122,18 @@ export default {
|
|||
|
||||
watch: {
|
||||
edit(edit) {
|
||||
// When leaving edit mode, filter and delete empty options
|
||||
if (!edit) {
|
||||
// Filter out empty options and update question
|
||||
this.$emit('update:options', this.options.filter(answer => !!answer.text))
|
||||
const options = this.options.filter(option => {
|
||||
if (!option.text) {
|
||||
this.deleteOptionFromDatabase(option)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
// update parent
|
||||
this.updateOptions(options)
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -224,39 +237,65 @@ export default {
|
|||
},
|
||||
|
||||
/**
|
||||
* Restore an answer locally
|
||||
* Restore an option locally
|
||||
*
|
||||
* @param {Object} answer the answer
|
||||
* @param {number} index the answer index in this.options
|
||||
* @param {Object} option the option
|
||||
* @param {number} index the options index in this.options
|
||||
*/
|
||||
restoreAnswer(answer, index) {
|
||||
restoreOption(option, index) {
|
||||
const options = this.options.slice()
|
||||
options.splice(index, 0, answer)
|
||||
options.splice(index, 0, option)
|
||||
|
||||
this.updateOptions(options)
|
||||
this.focusIndex(index)
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete an answer locally
|
||||
* Delete an option
|
||||
*
|
||||
* @param {number} id the answer is
|
||||
* @param {number} index the answer index in this.options
|
||||
* @param {number} id the options id
|
||||
*/
|
||||
deleteAnswer(id, index) {
|
||||
deleteOption(id) {
|
||||
// Remove entry
|
||||
const options = this.options.slice()
|
||||
const optionIndex = options.findIndex(option => option.id === id)
|
||||
const option = Object.assign({}, this.options[optionIndex])
|
||||
|
||||
// delete locally
|
||||
options.splice(optionIndex, 1)
|
||||
|
||||
// delete from Db
|
||||
this.deleteOptionFromDatabase(option)
|
||||
|
||||
// Update question
|
||||
this.updateOptions(options)
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.focusIndex(index + 1)
|
||||
this.focusIndex(optionIndex)
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Delete the option from Db in background.
|
||||
* Restore option if delete not possible
|
||||
*
|
||||
* @param {Object} option The option to delete
|
||||
*/
|
||||
deleteOptionFromDatabase(option) {
|
||||
const optionIndex = this.options.findIndex(opt => opt.id === option.id)
|
||||
|
||||
if (!option.local) {
|
||||
// let's not await, deleting in background
|
||||
axios.delete(generateUrl('/apps/forms/api/v1/option/{id}', { id: option.id }))
|
||||
.catch(error => {
|
||||
showError(t('forms', 'There was an issue deleting this option'))
|
||||
console.error(error)
|
||||
// restore option
|
||||
this.restoreOption(option, optionIndex)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Focus the input matching the index
|
||||
*
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
:maxlength="maxStringLengths.answerText"
|
||||
minlength="1"
|
||||
type="text"
|
||||
@input="onInput">
|
||||
@input="onInput"
|
||||
@keydown.enter.exact.prevent="onKeydownEnter">
|
||||
</div>
|
||||
</Question>
|
||||
</template>
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
<template>
|
||||
<div class="answer">
|
||||
<h4 class="question-text">
|
||||
{{ question.text }}
|
||||
{{ questionText }}
|
||||
</h4>
|
||||
<p>{{ answer.text }}</p>
|
||||
<p>{{ answerText }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -34,12 +34,12 @@ export default {
|
|||
name: 'Answer',
|
||||
|
||||
props: {
|
||||
answer: {
|
||||
type: Object,
|
||||
answerText: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
question: {
|
||||
type: Object,
|
||||
questionText: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
|
|
@ -35,10 +35,10 @@
|
|||
</p>
|
||||
|
||||
<Answer
|
||||
v-for="answer in squashedAnswers"
|
||||
:key="answer.questionId"
|
||||
:answer="answer"
|
||||
:question="questionToAnswer(answer.questionId)" />
|
||||
v-for="question in answeredQuestions"
|
||||
:key="question.id"
|
||||
:answer-text="question.squashedAnswers"
|
||||
:question-text="question.text" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -70,30 +70,37 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
// Format submission-timestamp to DateTime
|
||||
submissionDateTime() {
|
||||
return moment(this.submission.timestamp, 'X').format('LLLL')
|
||||
},
|
||||
squashedAnswers() {
|
||||
const squashedArray = []
|
||||
|
||||
this.submission.answers.forEach(answer => {
|
||||
const index = squashedArray.findIndex(ansSq => ansSq.questionId === answer.questionId)
|
||||
if (index > -1) {
|
||||
squashedArray[index].text = squashedArray[index].text.concat('; ' + answer.text)
|
||||
} else {
|
||||
squashedArray.push(answer)
|
||||
/**
|
||||
* Join answered Questions with corresponding answers.
|
||||
* Multiple answers to a question are squashed into one string.
|
||||
* @returns {Array}
|
||||
*/
|
||||
answeredQuestions() {
|
||||
const answeredQuestionsArray = []
|
||||
|
||||
this.questions.forEach(question => {
|
||||
const answers = this.submission.answers.filter(answer => answer.questionId === question.id)
|
||||
if (!answers.length) {
|
||||
return // no answers, go to next question
|
||||
}
|
||||
})
|
||||
const squashedAnswers = answers.map(answer => answer.text).join('; ')
|
||||
|
||||
return squashedArray
|
||||
answeredQuestionsArray.push({
|
||||
'id': question.id,
|
||||
'text': question.text,
|
||||
'squashedAnswers': squashedAnswers,
|
||||
})
|
||||
})
|
||||
return answeredQuestionsArray
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
questionToAnswer(questionId) {
|
||||
return this.questions.find(question => question.id === questionId)
|
||||
},
|
||||
|
||||
onDelete() {
|
||||
this.$emit('delete')
|
||||
},
|
||||
|
|
|
@ -136,6 +136,15 @@ export default {
|
|||
this.$emit('delete')
|
||||
},
|
||||
|
||||
/**
|
||||
* Don't automatically submit form on Enter, parent will handle that
|
||||
* To be called with prevent: @keydown.enter.prevent="onKeydownEnter"
|
||||
* @param {Object} event The fired event
|
||||
*/
|
||||
onKeydownEnter(event) {
|
||||
this.$emit('keydown', event)
|
||||
},
|
||||
|
||||
/**
|
||||
* Focus the first focusable element
|
||||
*/
|
||||
|
|
|
@ -71,10 +71,10 @@
|
|||
|
||||
<section v-else>
|
||||
<Submission
|
||||
v-for="submission in submissions"
|
||||
v-for="submission in form.submissions"
|
||||
:key="submission.id"
|
||||
:submission="submission"
|
||||
:questions="questions"
|
||||
:questions="form.questions"
|
||||
@delete="deleteSubmission(submission.id)" />
|
||||
</section>
|
||||
</AppContent>
|
||||
|
@ -117,14 +117,12 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
loadingResults: true,
|
||||
submissions: [],
|
||||
questions: [],
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
noSubmissions() {
|
||||
return this.submissions && this.submissions.length === 0
|
||||
return this.form.submissions?.length === 0
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -161,13 +159,15 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
copyShareLink() {
|
||||
copyShareLink(event) {
|
||||
const $formLink = window.location.protocol + '//' + window.location.host + generateUrl(`/apps/forms/${this.form.hash}`)
|
||||
if (this.$clipboard($formLink)) {
|
||||
showSuccess(t('forms', 'Form link copied'))
|
||||
} else {
|
||||
showError(t('forms', 'Cannot copy, please copy the link manually'))
|
||||
}
|
||||
// Set back focus as clipboard removes focus
|
||||
event.target.focus()
|
||||
},
|
||||
|
||||
async loadFormResults() {
|
||||
|
@ -178,9 +178,8 @@ export default {
|
|||
const response = await axios.get(generateUrl('/apps/forms/api/v1/submissions/{hash}', {
|
||||
hash: this.form.hash,
|
||||
}))
|
||||
this.submissions = response.data.submissions
|
||||
this.questions = response.data.questions
|
||||
console.debug(this.submissions)
|
||||
this.form.submissions = response.data.submissions
|
||||
this.form.questions = response.data.questions
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
showError(t('forms', 'There was an error while loading results'))
|
||||
|
@ -194,8 +193,8 @@ export default {
|
|||
|
||||
try {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/submission/{id}', { id }))
|
||||
const index = this.submissions.findIndex(search => search.id === id)
|
||||
this.submissions.splice(index, 1)
|
||||
const index = this.form.submissions.findIndex(search => search.id === id)
|
||||
this.form.submissions.splice(index, 1)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
showError(t('forms', 'There was an error while removing this response'))
|
||||
|
@ -212,7 +211,7 @@ export default {
|
|||
this.loadingResults = true
|
||||
try {
|
||||
await axios.delete(generateUrl('/apps/forms/api/v1/submissions/{formId}', { formId: this.form.id }))
|
||||
this.submissions = []
|
||||
this.form.submissions = []
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
showError(t('forms', 'There was an error while removing responses'))
|
||||
|
@ -229,19 +228,20 @@ export default {
|
|||
})
|
||||
|
||||
const formattedSubmissions = []
|
||||
this.submissions.forEach(submission => {
|
||||
this.form.submissions.forEach(submission => {
|
||||
const formattedSubmission = {
|
||||
userDisplayName: submission.userDisplayName,
|
||||
timestamp: moment(submission.timestamp, 'X').format('L LT'),
|
||||
}
|
||||
|
||||
submission.answers.forEach(answer => {
|
||||
const questionText = this.questions.find(question => question.id === answer.questionId).text
|
||||
if (questionText in formattedSubmission) {
|
||||
formattedSubmission[questionText] = formattedSubmission[questionText].concat('; ').concat(answer.text)
|
||||
} else {
|
||||
formattedSubmission[questionText] = answer.text
|
||||
this.form.questions.forEach(question => {
|
||||
const questionText = question.text
|
||||
const answers = submission.answers.filter(answer => answer.questionId === question.id)
|
||||
if (!answers.length) {
|
||||
return // no answers, go to next question
|
||||
}
|
||||
const squashedAnswers = answers.map(answer => answer.text).join('; ')
|
||||
formattedSubmission[questionText] = squashedAnswers
|
||||
})
|
||||
formattedSubmissions.push(formattedSubmission)
|
||||
})
|
||||
|
|
|
@ -323,12 +323,14 @@ export default {
|
|||
return datetime < moment().add(1, 'hour').toDate()
|
||||
},
|
||||
|
||||
copyShareLink() {
|
||||
copyShareLink(event) {
|
||||
if (this.$clipboard(this.shareLink)) {
|
||||
showSuccess(t('forms', 'Form link copied'))
|
||||
} else {
|
||||
showError(t('forms', 'Cannot copy, please copy the link manually'))
|
||||
}
|
||||
// Set back focus as clipboard removes focus
|
||||
event.target.focus()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -38,7 +38,9 @@
|
|||
</header>
|
||||
|
||||
<!-- Questions list -->
|
||||
<form v-if="!loading && !success" @submit.prevent="onSubmit">
|
||||
<form v-if="!loading && !success"
|
||||
ref="form"
|
||||
@submit.prevent="onSubmit">
|
||||
<ul>
|
||||
<Questions
|
||||
:is="answerTypes[question.type].component"
|
||||
|
@ -50,9 +52,12 @@
|
|||
:index="index + 1"
|
||||
:max-string-lengths="maxStringLengths"
|
||||
v-bind="question"
|
||||
:values.sync="answers[question.id]" />
|
||||
:values.sync="answers[question.id]"
|
||||
@keydown.enter="onKeydownEnter"
|
||||
@keydown.ctrl.enter="onKeydownCtrlEnter" />
|
||||
</ul>
|
||||
<input class="primary"
|
||||
<input ref="submitButton"
|
||||
class="primary"
|
||||
type="submit"
|
||||
:value="t('forms', 'Submit')"
|
||||
:disabled="loading"
|
||||
|
@ -154,6 +159,27 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* On Enter, focus next form-element
|
||||
* Last form element is the submit button, the form submits on enter then
|
||||
* @param {Object} event The fired event.
|
||||
*/
|
||||
onKeydownEnter(event) {
|
||||
const formInputs = Array.from(this.$refs.form)
|
||||
const sourceInputIndex = formInputs.findIndex(input => input === event.originalTarget)
|
||||
// Focus next form element
|
||||
formInputs[sourceInputIndex + 1].focus()
|
||||
},
|
||||
|
||||
/**
|
||||
* Ctrl+Enter typically fires submit on forms.
|
||||
* Some inputs do automatically, while some need explicit handling
|
||||
*/
|
||||
onKeydownCtrlEnter() {
|
||||
// Using button-click event to not bypass validity-checks and use our specified behaviour
|
||||
this.$refs.submitButton.click()
|
||||
},
|
||||
|
||||
/**
|
||||
* Submit the form after the browser validated it 🚀
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue