Глобальные объекты, функции и переменные

Любому скрипту, кроме набора средств языка JavaScript, доступен набор объектов, функций и переменных, используемых для работы с SURVEYSTUDIO. Например, для доступа к вопросам, созданным в редакторе анкеты, можно использовать глобальные переменные вида Q1, Q5, Q34 и т.д. Также для доступа к любому вопросу, можно использовать объект questions, и, например, вопрос Q34 можно так же получить вызовом questions[34].

Объект questions

Используется для доступа к любому вопросу анкеты по его номеру, а также для добавления, удаления и изменения порядка вопросов (рандомизация, ротация). Например, для получения доступа к вопросу по номеру можно написать так:

var q = questions[34];

Также объект questions содержит различные методы и свойства:

count

Возвращает количество вопросов. Например:

var x = questions.count;

getNumbers()

Возвращает массив номеров вопросов. Например:

var numbers = questions.getNumbers();

getAll()

Возвращает все вопросы в виде массива. Например:

questions.getAll().forEach(function (q) {
    q.comment = 'Тут комментарий для вопроса Q' + q.number;
});
Важно! При работе анкеты вопросы подгружаются постепенно при первом к ним обращении, а проход в цикле по всем вопросам вынуждает систему загрузить все вопросы сразу, что может замедлить, например, запуск анкеты, если такой скрипт будет в Подготовке.

randomize()
randomize(numbers)
randomizeFromTo(fromCode, toCode)

Перемешивает случайным образом либо все вопросы, либо указанные, если в качестве параметра передан массив номеров вопросов, либо все вопросы в указанном диапазоне.

questions.randomize();
questions.randomize([1,3,5,7]);
questions.randomizeFromTo(10, 20);

randomizeGroups(groupSize, firstNumbers)

Перемешивает случайным образом группы вопросов. Количество вопросов в группе задается первым параметром groupSize, а во втором параметре передается массив номеров первых вопросов в каждой группе. При этом внутри группы порядок вопросов не изменяется. Например есть вопросы: Q1,Q2,Q3, Q4,Q5,Q6, Q7,Q8,Q9. Необходимо перемешать группы вопросов 1-3, 4-6, 7-9. Сделать это можно так:

questions.randomizeGroups(3, [1,4,7]);

rotate()
rotate(shift)
rotate(numbers)
rotate(numbers, shift)
rotateFromTo(fromCode, toCode)
rotateFromTo(fromCode, toCode, shift)

Производит ротацию вопросов (циклический сдвиг на определенный шаг). Если не переданы никакие параметры - ротируются все вопросы. Также можно передать шаг сдвига в параметре shift, при этом если шаг не передается - используется внутренний шаг, который автоматически увеличивается на 1 для каждого следующего интервью, что дает правильное равномерное распределение. Для ротации определённых вопросов нужно передать массив numbers с номерами этих вопросов. Также в параметрах from и to можно указать диапазон вопросов, подлежащих ротации. Примеры:

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(groupSize, firstNumbers)
rotateGroups(groupSize, firstNumbers, shift)

Ротация групп вопросов. Работает по аналогии с функцией randomizeGroups. Примеры:

questions.rotateGroups(3, [1,4,7]);
questions.rotateGroups(3, [1,4,7], 2);

add(number, text, comment, type)

Функция добавляет новый вопрос в конец анкеты и возвращает его в качестве результата. В параметрах функции передаются номер вопроса, текст, комментарий (может быть пустым) и тип вопроса. Для указания типа вопроса можно использовать одно из значений: 'info', 'text', 'numeric', 'singlechoice', 'multiplechoice', 'table_text', 'table_numeric', 'table_singlechoice', 'table_multiplechoice'. Пример:

// создаем новый текстовый вопрос Q56 и добавляем его в конец анкеты
var q = questions.add(56, 'Как Вас зовут?', 'Записать', 'text');
// включаем в созданном вопросе флаг "Исключить вопрос при выгрузке"
q.flags |= 0x00008;

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)
repeat(qnFrom, qnTo, qnSrc, codes)

Создание цикла по вопросу, т.е. один блок существующих вопросов (с номерами от qnFrom до qnTo) будет задан для каждого выбранного ответа в вопросе с номером qnSrc в том же порядке, в котором эти ответы расположены во время запуска анкеты. Коды вариантов ответа, которые необходимо проверять в вопросе qnSrc, задаются параметром codes (массив номеров), но если он не задан - используются все варианты ответа qnSrc. Ответ не используется в цикле, если у него установлен флаг «Запрещено использовать в циклах».

Фактически, этот метод удаляет исходные вопросы с номерами от qnFrom до qnTo (согласно порядка следования вопросов в анкете, а не их номерам) и вместо них создает копии вопросов (свою для каждого кода варианта ответа из qnSrc), добавляя им условие показа, проверяющее, отмечен ли код в вопросе с номером qnSrc. При этом номера вопросов формируются в зависимости от кодов ответов qnSrc. Например, если коды ответов 1,2,3, а вопрос для цикла имел номер Q24, то вместо него будут созданы вопросы Q241, Q242, Q243. Если коды были 1,2,15, то создадутся вопросы Q2401, Q2402, Q2415, т.е. так, чтобы с помощью арифметического деления можно было определить номер исходного вопроса, а по остатку от деления - код варианта ответа, для которого он задается: 2401 / 100 = 24,01 - т.е. 24 - номер вопроса, а 1 - код ответа.
Существующее условие показа в вопросах, если оно было задано - не замещается, а добавляется через and (Q... = ...). Примеры использования:

// повтор вопросов с Q4 по Q6 для каждого выбранного в Q1 ответа
questions.repeat(4, 6, 1);
// повтор вопросов с Q4 по Q6 для ответов 1,3,5, если они выбранны в Q1
questions.repeat(4, 6, 1, [1,3,5]);
Пример: есть вопрос Q1, в нем варианты ответа с кодами 1-10. По всем выбранным в Q1 ответам необходимо задать вопросы Q4,Q5,Q6. Вызываем в скрипте Подготовка questions.repeat(4, 6, 1); и после запуска анкеты получаем вместо вопросов Q4,Q5,Q6, на их же местах: Q401,Q501,Q601, Q402,Q502,Q602, Q403,Q503,Q603... У каждого из них будет прописано условие показа: у Q401, Q501 и Q601 - Q1 = 1, у Q402, Q502 и Q602 - Q1 = 2 и т.д. Таким образом, будут заданы только те вопросы Q4XX-Q6XX, у которых выполнится условие показа.

В тексте вопроса, комментарии или ответе внутри цикла можно использовать макросы {answerText} и {answerCode}, которые при запуске анкеты заменятся на соответствующие значения ответов qnSrc. {answerText} - текст ответа, {answerCode} - код ответа.

Скрипты перед показом и после ответа в вопросах, находящихся внутри цикла, не выполняются. Вместо них нужно использовать глобальные скрипты (пример).

repeatIfNot(qnFrom, qnTo, qnSrc)
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.survey-studio.com/survey?pkey=ef87c2da&phone=78121234567&code=678
то получить значения параметров phone и code можно следующим образом:

var phone = parameters['phone'];
var code = parameters['code'];
// или можно написать проще
var phone = parameters.phone;
var code = parameters.code;

Объект variables

Используется как хранилище глобальных переменных, значения которых будут сохраняться на протяжении всей анкеты. Обычно используется для автоматической подстановки необходимого значения в текст вопроса (а также комментарий или текст варианта ответа) с помощью макросов. Например, если в тексте вопроса написать Здравствуйте, {ФИО}!, то макрос {ФИО} будет заменен на значение переменной ФИО в объекте variables. Также объект variables можно использовать для передачи значений из скрипта одного вопроса в скрипт другого. Для удобства у объекта variables есть псевдоним V.
Важные замечания: 1 – значение в объекте variables должно быть простого типа (строка, число, true/false), и 2 – не стоит использовать эти переменные в скрипте Подготовка, если от них зависит логика анкеты, так как при пост-обработке глобальные переменные из этого скрипта всегда пусты. Примеры:

variables['ФИО'] = 'Иванов И.И.';
variables.name = 'Пётр';
V['age'] = 21;
V.title = 'Hello, World!';
if (V.age < 18) {
    // Что-то сделать
}

Объект contact

Используется для доступа к базе контактов, а также к информации о проекте. У этого объекта есть следующие свойства и объект:

  • tag - метка базы контактов,
  • extId - идентификатор контакта из внешней системы дозвона (из параметра extid рабочей ссылки),
  • phone - номер телефона контакта,
  • data[name] - содержит данные из дополнительных полей контакта,
  • contactPoolName - название базы контактов,
  • projectId - идентификатор проекта (доступен в ссылке на проект: .../project?pId=1962),
  • projectName - наименование проекта.
Примеры:
var phone = contact.phone;
V.fio = contact.data['ФИО'];
return exitAndRedirect('http://example.com/?rid=' + contact.extId + '&status=1');
if (contact.projectName.indexOf('Москва') > -1) Q.show(77);

Объект respondent

Используется для доступа к данным респондента. У этого объекта есть два свойства и один метод: ipAddress, userAgent и getLastInterviewAnswers(). Свойства возращают IP-адрес и User Agent респондента/интервьюера соответственно. getLastInterviewAnswers() возвращает массив ответов из предыдущей версии интервью. Обычно этот метод используется в телефонных опросах, когда у одного респондента может быть несколько версий интервью: интервьюер начал опрашивать респондента, но тот попросил перезвонить позже - сохранится первая версия. После перезвона начнётся вторая версия, во время которой можно получить предыдущие ответы.
Каждый элемент массива содержит следующие свойства:

  • questionNumber - номер вопроса,
  • rowCode - код строки,
  • answerCode - код ответа,
  • openValueNum - числовое значение,
  • openValueTxt - текстовое значение.
Если в параметре передать номер вопроса, то метод вернёт ответ на этот вопрос, а не на все.
Примеры:
// Получить текущий IP-адрес респондента/интервьюера
var ip = respondent.ipAddress;
// Получить информацию о браузере
// и операционной системе респондента/интервьюера
var ua = respondent.userAgent;
// Получить ответ на вопрос Q5 из предыдущей версии интервью
var q5answers = respondent.getLastInterviewAnswers(5);
// Если в полученном массиве есть элементы, то вывести
// на экран содержимое текстового поля нулевого элемента массива
if (q5answers.length) informationText(q5answers[0].openValueTxt);

Объект user

Используется для доступа к данным пользователя SURVEYSTUDIO. У этого объекта есть следующие свойства:

  • id - числовой идентификатор пользователя,
  • loginName - логин пользователя,
  • name - имя пользователя.
Пример:
// Поместить в глобальную переменную interviewer имя пользователя
V.interviewer = user.name;

Объект webClient

Позволяет взаимодействовать с внешними сервисами по URL. У этого объекта есть два метода: downloadString(url), который выполняет GET-запрос, и uploadString(url, string) - POST-запрос. После завершения работы оба метода возвращают содержимое ответа сервера. Если сервер не ответил статусом 200 OK – будет выброшено исключение, которое прервёт интервью и оно не сохранится, поэтому такую ситуацию необходимо предусмотреть в скрипте. Для одного и того же URL эти методы можно выполнять только один раз за работу анкеты. Это ограничение необходимо для защиты от повторного выполнения из-за ошибки в логике анкеты или при пост-обработке интервью.
Важно! Внешний сервер должен ответить как можно быстрее. Если он не ответит в течение 15 секунд, анкета с этим объектом может быть заблокирована на несколько минут.
Пример:

// GET
var url = 'https://example.com/api/sendSms?format=json&phone=79998887766&' +
          'sender=MyCompany&text=Hello,+World!';

try {
    var result = webClient.downloadString(url);
} catch (e) {
    informationText('Не удалось выполнить запрос к внешнему серверу: {0}', e.message);
    return ok;
}

informationText('Ответ сервера: {0}', result);

// POST
var url = 'https://example.com/api/sendSms?format=json&phone=79998887766&' +
          'sender=MyCompany';
var data = 'Hello, World!';

try {
    var result = webClient.uploadString(url, data);
} catch (e) {
    informationText('Не удалось выполнить запрос к внешнему серверу: {0}', e.message);
    return ok;
}

informationText('Ответ сервера: {0}', result);

Объект images

Позволяет получить изображение, загруженное через редактор вопросов анкеты, по его названию:

Q.image = images['Название изображения'];

Объект smscClient

Используется для отправки SMS через СМС-центр в любом типе проекта, кроме планшетного (временно). Сообщение отправляется один раз одному респонденту после успешного сохранения интервью в проект.
У объекта есть 2 метода: send(phone, text) и sendWithCredentials(phone, text, login, password [, sender]).
Первый метод отправляет SMS через нашу учётную запись в СМС-центре – с вашего счёта SURVEYSTUDIO будет списано 3 рубля за одно сообщение. Имя отправителя при этом будет SURVEY. Второй метод можно использовать, если у вас есть свой договор с СМС-центром – в этом случае стоимость одного сообщения 1 рубль. В необязательном параметре sender можно указать желаемое имя отправителя, если вы зарегистрировали их несколько. О требованиях к формату телефона можно почитать на сайте сервиса.
При составлении текста сообщения помните об ограничениях длины одного сообщения. Длинные тексты автоматически разбиваются на несколько SMS, которые оплачиваются соответственно. Примеры:

smscClient.send('89991112233', 'Спасибо за участие в опросе!');

smscClient.sendWithCredentials(contact.phone, Q.text, 'mylogin', 'mypassword', 'MYCOMPANY');

Функции и переменные

rotationCounter

Возвращает текущее значение счетчика ротации для анкеты, который будет использоваться в функциях questions.rotate() и questions.rotateGroups(), если не задано явно значение сдвига (в параметре shift).

informationText(text)

Выводит на экран переданный в первом параметре текст, который будет отображаться в нижней левой части экрана на протяжении всего интервью. При повторном вызове этой функции существующий текст заменяется новым. В тексте можно использовать подстановки {0}, {1}, {2}..., которые будут заменяться значениями из остальных параметров функции. Примеры:

informationText('Имя респондента: ' + Q.openValueTxt);
informationText('Цена была {0} руб., а стала {1} руб.', oldPrice, newPrice);

informationTextAdd(text)

Делает то же самое, что и предыдущая функция, но при повторном вызове этой функции к существующему тексту добавляется новая строка. Пример:

informationTextAdd('В траве');
informationTextAdd('сидел кузнечик.');

informationTextClear()

Удаляет весь текст, добавленный функциями informationText() и informationTextAdd().

isTesting()

Возвращает значение true, если анкета работает в режиме тестирования (без проекта, т.е. без сохранения интервью в базу).

isPreProcessing()

Возвращает значение true, если анкета работает в режиме подготовки запуска (исполняется глобальный скрипт Подготовка).

isPostProcessing()

Возвращает значение true, если исполняется глобальный скрипт Обработка или производится повторный проход анкеты для нормализации ответов - очистка интервью от ответов, не соответствующих заданным в анкете условиям и переходам.

isQuotaReached()

Возвращает значение true, если сработала квота.

isRedial()

Возвращает значение true, если анкета запущена повторно для продолжения ввода с места, на котором остановились, например при перезвоне в телефонном опросе или возобновлении отложенного на планшете интервью.

isValidation()

Возвращает значение true, если анкета работает в режиме контроля (сохранённое интервью открыто повторно для контроля работы интервьюера).

disableQuotaChecking()

Отключает автоматическую проверку квот.

enableQuotaChecking()

Включает автоматическую проверку квот.

enableSaveWhenQuotaReached()

Включает запись интервью в базу, даже если сработала квота. По умолчанию если квота сработала - интервью завершается и в базу не записывается.

disableSaveWhenQuotaReached()

Отключает запись интервью в базу, когда сработала квота, т.е. включает поведение по умолчанию.

getCounter(name)

Производит поиск счётчика с указанным именем в проекте, и если он будет найден - возвращает объект со следующими свойствами:

  • name - имя счётчика
  • quota - значение квоты (или undefined, если квота не задана)
  • value - текущее значение счётчика
Примеры использования:
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('Спасибо, больше не надо.');
}

lockKey(text)

Помещает переданную в параметре строку в глобальное хранилище. Обычно используется совместно с функцией isKeyLocked(). Пример:

lockKey(respondent.ipAddress + respondent.userAgent);

isKeyLocked(text)

Возвращает true, если переданная в параметре строка содержится в глобальном хранилище. Обычно используется для запрета повторного заполнения анкеты в веб-опросе. Пример:

var id = respondent.ipAddress + respondent.userAgent;
if ( isKeyLocked(id) ) return exit();

calc(expression)

Возвращает true, если переданное в параметре выражение выполняется. В выражении нельзя использовать Q без номера вопроса. Пример:

Q[2].checked = calc('Q1(code = 1 or code = 3 or code = 5)');


Читайте далее: свойства и функции вопроса.