Глобальные объекты, функции и переменные
Любому скрипту, кроме набора средств языка JavaScript, доступен набор объектов, функций и переменных, используемых для работы с SURVEYSTUDIO. Например, для доступа к вопросам, созданным в редакторе анкеты, можно использовать глобальные переменные вида Q1, Q5, Q34 и т.д. Также для доступа к любому вопросу, можно использовать объект questions, и, например, вопрос Q34 можно так же получить вызовом questions[34].
Объект questions
Используется для доступа к любому вопросу анкеты по его номеру, а также для добавления, удаления и изменения порядка вопросов (рандомизация, ротация). Например, для получения доступа к вопросу по номеру можно написать так:
var q = questions[34];
Также объект questions содержит различные методы и свойства:
count
Возвращает количество вопросов. Например:
var x = questions.count;
getNumbers()
getNumbers(qnFrom, qnTo)
Возвращает массив номеров вопросов. Может принимать параметры начала и конца диапазона.
Получить номера всех вопросов:
var numbers = questions.getNumbers();
Получить номера вопросов, которые находятся между 23 и 115 включительно:
var numbers = questions.getNumbers(23, 115);
getAll()
Возвращает все вопросы в виде массива. Например:
questions.getAll().forEach(function (q) {
q.comment = 'Тут комментарий для вопроса Q' + q.number;
});
Важно! При работе анкеты вопросы подгружаются постепенно при первом к ним обращении, а проход в цикле по всем вопросам вынуждает систему загрузить все вопросы сразу, что может замедлить, например, запуск анкеты, если такой скрипт будет в Подготовке.
randomize()
randomize([numbers])
randomizeFromTo(qnFrom, qnTo)
Перемешивает случайным образом либо все вопросы, либо указанные, если в качестве параметра передан массив номеров вопросов, либо все вопросы в указанном диапазоне.
questions.randomize();
questions.randomize([1,3,5,7]);
questions.randomizeFromTo(10, 20);
randomizeGroups(groups)
randomizeGroups(groupSize, firstNumbers)
Перемешивает случайным образом группы вопросов.
В параметре groups передаётся массив с массивами номеров первого и последнего вопроса в группе. Если группы вопросов одинакового размера, то в первом параметре (groupSize) можно указать количество вопросов в группе, а во втором — массив номеров первых вопросов в каждой группе.
Порядок вопросов внутри группы не изменяется.
Примеры.
- Есть вопросы: Q1,Q2, Q3,Q4,Q5,Q6,Q7,Q8, Q9. Необходимо перемешать между собой группы вопросов 1-2, 3-8, и 9. Сделать это можно так:
questions.randomizeGroups([[1,2], [3,8], [9,9]]);
- Есть вопросы: Q1,Q2,Q3, Q4,Q5,Q6, Q7,Q8,Q9. Необходимо перемешать между собой группы вопросов 1-3, 4-6, 7-9. Сделать это можно так:
questions.randomizeGroups(3, [1,4,7]);
// или
questions.randomizeGroups([[1,3], [4,6], [7,9]]);
rotate()
rotate([numbers [, shift]])
rotateFromTo(qnFrom, qnTo [, shift])
Производит ротацию вопросов (циклический сдвиг на определенный шаг). Если не переданы никакие параметры - ротируются все вопросы. Также можно передать шаг сдвига в параметре shift, при этом если шаг не передается - используется внутренний шаг, который автоматически увеличивается на 1 для каждого следующего интервью, что дает правильное равномерное распределение. Для ротации определённых вопросов нужно передать массив numbers с номерами этих вопросов. Также в параметрах qnFrom и qnTo можно указать диапазон вопросов, подлежащих ротации. Примеры:
questions.rotate();
questions.rotate(5);
questions.rotate([1,2,3,4,5,6]);
questions.rotate([1,2,3,4,5,6], 5);
questions.rotateFromTo(1, 6);
questions.rotateFromTo(1, 6, 5);
rotateGroups(groups [, shift])
rotateGroups(groupSize, firstNumbers [, shift])
Ротация групп вопросов. Работает по аналогии с функцией randomizeGroups. Примеры:
questions.rotateGroups([[1,3], [4,6], [7,9]]);
questions.rotateGroups([[1,3], [4,6], [7,9]], 2);
questions.rotateGroups(3, [1,4,7]);
questions.rotateGroups(3, [1,4,7], 2);
setOrder(orderedCodes)
Устанавливает необходимый порядок следования вопросов. В параметре orderedCodes передается массив номеров в необходимом порядке.
Например, есть вопросы Q1,Q2,Q3,Q4,Q5.
- Задать вопросы в обратном порядке можно так:
questions.setOrder([5,4,3,2,1]);
- Поменять местами Q2 и Q4 можно так:
questions.setOrder([4,2]);
setOrderGroups(groups)
setOrderGroups(groupSize, firstNumbers)
Устанавливает порядок для групп вопросов. Синтаксис аналогичен randomizeGroups.
moveAfter(qnAfter, qn [, qnEnd])
Ставит вопрос или группу вопросов после указанного. Можно применять только на этапе Подготовки анкеты.
- Поставить Q2 после Q4:
questions.moveAfter(4, 2);
- Поставить блок вопросов с Q64 по Q12 (нумерация внутри блока значения не имеет) после Q35:
questions.moveAfter(35, 64, 12);
add(number, text, comment, type)
Функция добавляет новый вопрос в конец анкеты и возвращает его в качестве результата. В параметрах функции передаются номер вопроса, текст, комментарий (может быть пустым) и тип вопроса. Для указания типа вопроса можно использовать одно из значений:
- welcomescreen,
- info,
- text,
- numeric,
- singlechoice,
- multiplechoice,
- table_text,
- table_numeric,
- table_singlechoice,
- table_multiplechoice,
- dropdown_singlechoice,
- dropdown_multiplechoice.
Пример:
// создаем новый текстовый вопрос Q56 и добавляем его в конец анкеты
var q = questions.add(56, 'Как Вас зовут?', 'Записать', 'text');
// включаем в созданном вопросе флаг "Исключить вопрос при выгрузке"
q.settings.skipExport = true;
insert(refNumber, number, text, comment, type)
Так же, как и функция add(), создает новый вопрос и вставляет его перед вопросом, номер которого указан в параметре refNumber. Пример:
// создаем новый текстовый вопрос Q56 и вставляем его перед вопросом Q57
var q = questions.insert(57, 56, 'Как Вас зовут?', 'Записать', 'text');
insertAfter(refNumber, number, text, comment, type)
Аналогично функции insert() создает новый вопрос, только вставляет его после вопроса, номер которого указан в параметре refNumber. Пример:
// создаем новый текстовый вопрос Q56 и вставляем его после вопроса Q55
var q = questions.insertAfter(55, 56, 'Как Вас зовут?', 'Записать', 'text');
remove(number)
Удаляет вопрос с указанным номером. Пример:
// удаляем вопрос Q56 из анкеты
questions.remove(56);
repeat(qnFrom, qnTo, qnSrc [, codes])
Создание цикла по вопросу, т.е. один блок существующих вопросов (с номерами от qnFrom до qnTo) будет задан для каждого выбранного ответа в вопросе с номером qnSrc в том же порядке, в котором эти ответы расположены во время запуска анкеты. Ответ не используется в цикле, если у него установлен флаг Запрещено использовать в циклах. Также коды вариантов ответа, которые необходимо проверять в вопросе qnSrc, можно задать в необязательном параметре codes (массив номеров). Если он не задан - используются все варианты ответа qnSrc.
Существующее условие показа в вопросах, если оно было прописано, не замещается, а дополняется через and (Q… = …).
В тексте вопроса, комментарии или ответе внутри цикла можно использовать макросы {answerText} и {answerCode}, которые при запуске анкеты заменятся на соответствующие значения ответов qnSrc. {answerText} - текст ответа, {answerCode} - код ответа.
Примеры использования:
// повтор вопросов с Q4 по Q6 для каждого выбранного в Q1 ответа
questions.repeat(4, 6, 1);
// повтор вопросов с Q4 по Q6 для ответов 1,3,5, если они выбраны в Q1
questions.repeat(4, 6, 1, [1,3,5]);
О создании циклов и работе с ними читайте здесь.
repeatIfNot(qnFrom, qnTo, qnSrc [, codes])
Этот метод работает аналогично предыдущему (см. описание выше), но наоборот: вопросы в цикле будут задаваться для невыбранных в qnSrc ответов. Примеры использования:
// повтор вопросов с Q4 по Q6 для каждого невыбранного в Q1 ответа
questions.repeatIfNot(4, 6, 1);
// повтор вопросов с Q4 по Q6 для ответов 1,3,5, если они не выбраны в Q1
questions.repeatIfNot(4, 6, 1, [1,3,5]);
Объект parameters
Используется для доступа к параметрам, переданным в ссылке (url) для запуска проекта. Например, если ссылка для запуска проекта была:
https://do.surveystudio.ru/s/ef87c2da?phone=78121234567&code=678
то получить значения параметров phone и code можно следующим образом:
var phone = parameters['phone'];
var code = parameters['code'];
// или можно проще
var phone = parameters.phone;
var code = parameters.code;
Параметры extId и extPhone, передаваемые в ссылке, являются системными и недоступны через объект parameters. Для получения значений этих параметров воспользуйтесь объектами respondent и contact соответственно.
Объект variables
Используется как хранилище глобальных переменных, значения которых будут сохраняться на протяжении всей анкеты. Обычно используется для автоматической подстановки необходимого значения в текст вопроса (а также комментарий или текст варианта ответа) с помощью макросов. Например, если в тексте вопроса написать Здравствуйте, {ФИО}!, то макрос {ФИО} будет заменен на значение переменной ФИО в объекте variables. Также этот объект можно использовать для передачи значений из скрипта одного вопроса в скрипт другого. Для удобства у объекта variables есть псевдоним V.
Важные замечания:
- объект может хранить значения только простого типа (строка, число, true/false),
- не стоит использовать глобальные переменные в скрипте Подготовка, если от них зависит логика анкеты, так как при пост-обработке глобальные переменные из этого скрипта всегда пусты.
Примеры:
variables['ФИО'] = 'Иванов И.И.';
variables.name = 'Пётр';
V['age'] = 21;
V.title = 'Hello, World!';
if (V.age < 18) {
// Что-то сделать
}
Объект project
Используется для доступа к информации о проекте. У этого объекта есть следующие свойства:
- id - идентификатор проекта (доступен в ссылке на проект: …/project?pId=1962),
- name - наименование проекта.
Пример:
if (project.name.indexOf('Москва') > -1) Q.show(77);
Объект interview
Используется для доступа к информации о текущей версии интервью. У этого объекта есть следующие свойства:
- id - идентификатор версии интервью,
- result - результат интервью,
- resultDetails - наименование счётчика, если сработала квота,
- ipAddress - IP-адрес устройства респондента/интервьюера,
- userAgent - User Agent на устройстве респондента/интервьюера,
- referer - источник перехода по ссылке на анкету,
- latitude - координаты широты (определяются при включенной опции Записи координат)
- longitude - координаты долготы (определяются при включенной опции Записи координат)
- clientLoginName - идентификатор клиента в SURVEYSTUDIO,
- clientName - имя клиента,
- contractor - информация о подрядчике:
- clientLoginName - идентификатор клиента в SURVEYSTUDIO,
- clientName - имя клиента,
- contractorName - название подрядчика,
- contractorCode - код (если указан),
- contractorRegionName - название региона (если указан).
Примеры:
informationTextAdd(interview.userAgent);
informationTextAdd(interview.contractor.clientLoginName);
Объект respondent
Используется для доступа к данным респондента.
extId
Идентификатор респондента из внешней системы (из параметра extid рабочей ссылки).
let url = 'http://example.com/?rid=' + respondent.extId;
return exitAndRedirect(url);
Если у респондента отсутствует внешний идентификатор (respondent.extId === undefined), вы можете установить его в скриптах Подготовка или Обработка в анкете. Это позволяет, например, начать опрос по общей ссылке, а затем продолжить его по индивидуальной.
if (isTesting() || isValidation()) return ok;
if (respondent.extId === undefined) {
respondent.extId = '12345'; // установить extId респонденту
}
Установка extId доступна только для веб-опросов.
Нельзя установить extId, если с респондентом уже связан контакт.
getLastInterviewAnswers([qn])
Возвращает массив ответов из предыдущей версии интервью. Обычно этот метод используется в телефонных опросах, когда у одного респондента может быть несколько версий интервью: интервьюер начал опрашивать респондента, но тот попросил перезвонить позже - сохранится первая версия. После перезвона начнётся вторая версия, во время которой можно получить предыдущие ответы.
Каждый элемент массива содержит следующие свойства:
- questionNumber - номер вопроса,
- rowCode - код строки,
- answerCode - код ответа,
- openValueNum - числовое значение,
- openValueTxt - текстовое значение.
Если в параметре передать номер вопроса, то метод вернёт ответ на этот вопрос, а не на все. Примеры:
// Получить ответ на вопрос Q5 из предыдущей версии интервью
var q5answers = respondent.getLastInterviewAnswers(5);
// Если в полученном массиве есть элементы, то вывести
// на экран содержимое текстового поля нулевого элемента массива
if (q5answers.length) informationText(q5answers[0].openValueTxt);
Объект contact
Используется для доступа к базе контактов. У этого объекта есть следующие свойства и объект:
- id - id контакта,
- tag - метка базы контактов,
- phone - номер телефона контакта,
- email - электронная почта контакта (может быть в рассылочной базе),
- data[name] - содержит данные из дополнительных полей контакта,
- contactPoolName - название базы контактов,
- contactPoolTimeZoneId - часовой пояс базы контактов.
- validUntilDate - дата указанна в поле Срок действия контакта
- validUntilTime - время указанное в поле Срок действия контакта (в часовом поясе базы контактов)
Примеры:
var phone = contact.phone;
V.fio = contact.data['ФИО'];
Объект user
Используется для доступа к данным пользователя SURVEYSTUDIO. У этого объекта есть следующие свойства:
- id - числовой идентификатор пользователя,
- loginName - логин пользователя,
- name - имя пользователя.
Пример:
// Поместить в глобальную переменную interviewer имя пользователя
V.interviewer = user.name;
Объект webClient
Позволяет взаимодействовать с внешними сервисами по URL. У этого объекта есть два метода:
- downloadString(url [, timeout, {headers}]) — выполняет GET-запрос,
- uploadString(url, string [, timeout, {headers}]) — POST-запрос.
После завершения работы оба метода возвращают содержимое ответа сервера. Если сервер не ответил статусом 200 OK — будет выброшено исключение, которое прервёт интервью, поэтому такую ситуацию необходимо предусмотреть в скрипте.
Запрос с одним и тем же URL будет выполнен только один раз за интервью. Это ограничение необходимо для защиты от повторного выполнения из-за ошибки в логике анкеты или при постобработке перед сохранением интервью.
Время работы любого скрипта анкеты ограничено 30-ю секундами, поэтому внешний сервер должен ответить как можно быстрее. Если он будет долго думать — интервью может прерваться с ошибкой в скрипте The operation has timed out или Превышено максимально допустимое время выполнения скрипта 30 сек. Многократное завершение с такой ошибкой может привести к блокировке анкеты на несколько минут. Поэтому, если время работы скрипта превышается, то можно попробовать уменьшить время ожидания ответа сервера, указав необходимое значение (в миллисекундах) в необязательном аргументе timeout. По умолчанию оно равно 25000 (25 секунд). Если указать null, будет использоваться значение по умолчанию.
Пример:
// GET
let url = 'https://example.com/get.php';
try {
var result = webClient.downloadString(url, null, {"String-Header": "value", "Int-Header": 11});
} catch (e) {
informationText('Не удалось выполнить запрос к внешнему серверу: {0}', e.message);
return ok;
}
informationText('Ответ сервера: {0}', result);
// POST
let url = 'https://example.com/post.php';
let data = 'some data';
let headers = {
"String-Header": "value",
"Int-Header": 11
}
try {
var result = webClient.uploadString(url, data, null, headers);
} catch (e) {
informationText('Не удалось выполнить запрос к внешнему серверу: {0}', e.message);
return ok;
}
informationText('Ответ сервера: {0}', result);
Объект images
Позволяет получить изображение, загруженное через редактор вопросов анкеты, по его названию. С помощью свойства url можно получить ссылку на файл. Примеры:
Q.image = images['Название изображения'];
V['Картинка'] = `<img src="${images['Название изображения'].url}">`;
Объект InterviewResult
Содержит результаты интервью:
- Completed - Полное
- Screening - Скрининг
- Overquoting - Квота
- Defect - Брак
- Interrupted - Прервано
- Postponed - Перенесено
- Exited - Завершено
- Unknown - Неизвестно
Примеры:
if (interview.result == InterviewResult.Overquoting) {
// …
}
return exitWithResult(InterviewResult.Completed);
Объект CallResult
Содержит результаты звонка системы автодозвона:
- Answered_Success – Успешно
- Answered_Interrupted – Прервано
- Answered_WrongNumber – Неверный номер
- Answered_CommunicationError – Ошибка связи
- Answered_Refused – Отказ
- Answered_Refused_Soft – Мягкий отказ
- Answered_Refused_Hard – Жёсткий отказ
- Answered_Screener – Не подходит
- Answered_Screener_Under18 – Младше 18 лет
- Answered_Screener_DisabledPerson – Физические или ментальные сложности
- Answered_Screener_Language – Языковые проблемы
- Answered_Screener_Office – Офис / Организация
- Answered_Screener_Apartment – Квартира
- Answered_Screener_AlreadyInterviewed – Уже опрашивали
- Answered_Screener_WrongRegion – Не тот регион
- Answered_AMD – Автоответчик (AMD)
- Answered_VoiceMail – Автоответчик (Определил оператор)
- Answered_IVR – Автоответчик (Интеллектуальный робот)
- Answered_Overquota – Квота
Пример:
return exitWithCallResult(InterviewResult.Screening, CallResult.Answered_Screener);
Объект Language
Содержит языки веб-интерфейса анкеты. В качестве свойства может быть как полное название языка с большой буквы (English), так и сокращённое с маленькой (en).
- az / Azerbaijani — азербайджанский
- en / English — английский
- ar / Arabic — арабский
- hy / Armenian — армянский
- hu / Hungarian — венгерский
- vi / Vietnamese — вьетнамский
- ka / Georgian – грузинский
- id / Indonesian — индонезийский
- es / Spanish — испанский
- it / Italian — итальянский
- kk / Kazakh — казахский
- ky / Kyrgyz — киргизский
- zh / Chinese — китайский
- ms / Malay — малайский
- de / German — немецкий
- nl / Dutch — нидерландский (голландский)
- fa / Persian — персидский (фарси)
- pt / Portuguese — португальский
- ro / Romanian — румынский
- ru / Russian — русский
- th / Thai — тайский
- tr / Turkish — турецкий
- uz-cyrl / UzbekCyrillic — узбекский (кириллица)
- uz-latn / UzbekLatin — узбекский (латиница)
- fr / French — французский
- sv / Swedish — шведский
- ja / Japanese — японский
Примеры:
Language.en
Language['uz-cyrl']
Language.UzbekLatin
Функции и переменные
rotationCounter
Возвращает текущее значение счетчика ротации для анкеты, который будет использоваться в функциях questions.rotate() и questions.rotateGroups(), если не задано явно значение сдвига (в параметре shift).
informationText(string)
Выводит на экран переданный в первом параметре текст, который будет отображаться в нижней левой части экрана на протяжении всего интервью. Поддерживается HTML. При повторном вызове этой функции существующий текст заменяется новым. В тексте можно использовать подстановки {0}, {1}, {2}…, которые будут заменяться значениями из остальных параметров функции. Примеры:
informationText('Имя респондента: ' + Q.openValueTxt);
informationText('Цена была {0} руб., а стала <font color="red">{1} руб.</font>', oldPrice, newPrice);
informationTextAdd(string)
Делает то же самое, что и предыдущая функция, но при повторном вызове этой функции к существующему тексту добавляется новая строка. Пример:
informationTextAdd('В траве');
informationTextAdd('сидел <b>кузнечик</b>.');
informationTextClear()
Удаляет весь текст, добавленный функциями informationText() и informationTextAdd().
isTesting()
Возвращает значение true, если анкета работает в режиме тестирования (без проекта, т.е. без сохранения интервью в базу).
isPreProcessing()
Возвращает значение true, если анкета работает в режиме подготовки запуска (исполняется глобальный скрипт Подготовка).
isPostProcessing()
Возвращает значение true, если исполняется глобальный скрипт Обработка или производится повторный проход анкеты для нормализации ответов - очистка интервью от ответов, не соответствующих заданным в анкете условиям и переходам.
isQuotaReached()
Возвращает значение true, если сработала квота.
isRedial()
Возвращает значение true, если анкета запущена повторно для продолжения ввода с места, на котором остановились, например при перезвоне в телефонном опросе или возобновлении отложенного на планшете интервью.
isValidation()
Возвращает значение true, если анкета работает в режиме контроля (сохранённое интервью открыто повторно для контроля работы интервьюера).
isExport()
Возвращает значение true, если производится выгрузка массива.
isTablet()
Возвращает значение true, если анкета запущена в мобильном приложении SURVEYSTUDIO.
disableQuotaChecking()
Отключает автоматическую проверку квот.
enableQuotaChecking()
Включает автоматическую проверку квот.
enableSaveWhenQuotaReached()
Включает запись интервью в базу, даже если сработала квота. По умолчанию если квота сработала - интервью завершается и в базу не записывается.
disableSaveWhenQuotaReached()
Отключает запись интервью в базу, когда сработала квота, т.е. включает поведение по умолчанию.
getCounter(name)
Производит поиск в проекте счётчика с указанным именем, и если он будет найден - возвращает объект со следующими свойствами:
- name - имя счётчика,
- quota - значение квоты (или undefined, если квота не задана),
- value - текущее значение счётчика,
- tag - метка счётчика.
Примеры использования:
var counter = getCounter('Москва: М 18-24');
if (counter) {
Q.comment = 'Значение счетчика = ' + counter.value;
}
var counter = getCounter('Полные интервью');
if (counter && counter.quota >= 0 && counter.value + 1 > counter.quota) {
return exit('Спасибо, больше не надо.');
}
getCounterByTag(tag)
Производит поиск в проекте счётчика с указанной меткой, и если он будет найден - возвращает объект с такими же свойствами, как у getCounter(). Если в нескольких счётчиках прописана одна и та же метка, то функция возвратит первый найденный.
Пример:
var counter = getCounterByTag('51');
if (counter && counter.quota >= 0 && counter.value + 1 > counter.quota) {
return exit('Спасибо, больше не надо.');
}
getCountersByTag(tag)
Как и предыдущая, эта функция так же производит поиск счётчика с указанной меткой, но если он будет найден - возвращает массив объектов с такими же свойствами, как у getCounter(). То есть если в нескольких счётчиках прописана одна и та же метка, то функция возвратит их все в виде массива.
Пример:
for (let counter of getCountersByTag('51')) {
if (counter.quota >= 0 && counter.value + 1 > counter.quota) {
return exit('Спасибо, больше не надо.');
}
}
lockKey(string)
Помещает переданную в параметре строку в хранилище проекта. Обычно используется совместно с функцией isKeyLocked(). Пример:
lockKey(interview.ipAddress + interview.userAgent);
isKeyLocked(string)
Возвращает true, если переданная в параметре строка содержится в хранилище проекта. Обычно используется для запрета повторного заполнения анкеты в веб-опросе. Пример:
var id = interview.ipAddress + interview.userAgent;
if (isKeyLocked(id)) return exit();
calc(expression)
Возвращает true, если переданное в параметре выражение выполняется. В выражении нельзя использовать Q без номера вопроса. Пример:
Q[2].checked = calc('Q1(code = 1 or code = 3 or code = 5)');
randomizeArray(array)
Перемешивает случайным образом элементы массива. Пример:
informationText(randomizeArray([1,2,3,4,5,6,7,8,9,10]));
setCurrentLanguage(lang)
Принудительное изменение языка интерфейса опроса на указанный с помощью объекта Language.
Пример переключения на арабский:
setCurrentLanguage(Language.Arabic);
getCurrentLanguage()
Возвращает текущий язык интерфейса опроса. Возможные варианты:
- az — азербайджанский
- en — английский
- ar — арабский
- hy — армянский
- hu — венгерский
- vi — вьетнамский
- ka – грузинский
- id — индонезийский
- es — испанский
- it — итальянский
- kk — казахский
- ky — киргизский
- zh — китайский
- ms — малайский
- de — немецкий
- nl — нидерландский (голландский)
- fa — персидский (фарси)
- pt — португальский
- ro — румынский
- ru — русский
- th — тайский
- tr — турецкий
- uz-cyrl — узбекский (кириллица)
- uz-latn — узбекский (латиница)
- fr — французский
- sv — шведский
- ja — японский
getSurveyUrl()
Получает ссылку на анкету: тестовую, если анкета запущена в режиме тестирования, или рабочую, если анкета запущена из проекта.
let url = getSurveyUrl() + '?extid=' + respondent.extId;