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

Любому скрипту, кроме набора средств языка 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/get.php';

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

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

// POST
var url = 'https://example.com/post.php';
var data = 'some data';

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 через нашу учётную запись в СМС-центре - имя отправителя при этом будет SURVEY. Второй метод можно использовать, если у вас есть свой договор с СМС-центром. В необязательном параметре sender можно указать желаемое имя отправителя, если вы зарегистрировали их несколько. О требованиях к формату телефона можно почитать на сайте сервиса.

Узнать стоимость отправки SMS можно в тарифах. При составлении текста сообщения помните об ограничениях длины одного сообщения. Длинные тексты автоматически разбиваются на несколько 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, если анкета работает в режиме контроля (сохранённое интервью открыто повторно для контроля работы интервьюера).

isExport()

Возвращает значение 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)');

Комментарии