5use Bitrix\Crm\Integration\UserConsent;
6use Bitrix\Crm\Settings\LeadSettings;
7use Bitrix\Crm\UI\Webpack;
52 private static array $errors = [];
64 return self::replaceFormMarkers($content);
76 $content = self::replaceFormMarkers($content);
89 $replace = preg_replace_callback(
90 '/(?<pre><a[^>]+href=|data-b24form=)["\'](form:)?#crmForm(?<type>Inline|Popup)(?<id>[\d]+)["\']/i',
91 static function ($matches)
93 $id = (int)$matches[
'id'];
99 $form = self::getFormById($id);
100 if (!$form || !$form[
'URL'])
105 if (strtolower($matches[
'type']) ===
'inline')
107 $param =
"{$form['ID']}|{$form['SECURITY_CODE']}|{$form['URL']}";
109 return $matches[
'pre'] .
"\"{$param}\"";
112 if (strtolower($matches[
'type']) ===
'popup')
114 $script =
"<script data-b24-form=\"click/{$id}/{$form['SECURITY_CODE']}\" data-skip-moving=\"true\">
116 var s=d.createElement('script');s.async=true;s.src=u+'?'+(Date.now()/180000|0);
117 var h=d.getElementsByTagName('script')[0];h.parentNode.insertBefore(s,h);
118 })(window,document,'{$form['URL']}');
121 return $script . $matches[
'pre'] .
"\"#\" onclick=\"BX.PreventDefault();\"";
129 $replace = $replace ?? $content;
132 $replace = preg_replace_callback(
133 '/(?<pre><img|<i.*)data-pseudo-url="{.*(form:)?#crmForm(?<type>Inline|Popup)(?<id>[\d]+).*}"(?<pre2>.*>)/i',
134 static function ($matches)
138 || !($form = self::getFormById((
int)$matches[
'id']))
144 if (strtolower($matches[
'type']) ===
'popup')
146 $script =
"<script data-b24-form=\"click/{$matches['id']}/{$form['SECURITY_CODE']}\" data-skip-moving=\"true\">
148 var s=d.createElement('script');s.async=true;s.src=u+'?'+(Date.now()/180000|0);
149 var h=d.getElementsByTagName('script')[0];h.parentNode.insertBefore(s,h);
150 })(window,document,'{$form['URL']}');
154 preg_match_all(
'/(class="[^"]*)/i', $matches[
'pre'], $matchesPre);
155 $matches[
'pre'] = str_replace($matchesPre[1][0], $matchesPre[1][0].
' g-cursor-pointer', $matches[
'pre']);
157 return $script . $matches[
'pre'] .
' '. $matches[
'pre2'];
165 return $replace ?? $content;
175 $res = BlockTable::getList(
178 'SITE_ID' =>
'LANDING.SITE_ID',
181 '=LANDING.ACTIVE' =>
'Y',
182 '=LANDING.SITE.ACTIVE' =>
'Y',
185 'CONTENT' =>
'%bitrix24forms%',
192 while ($row = $res->fetch())
194 if (!in_array($row[
'SITE_ID'], $sites))
196 $sites[] = $row[
'SITE_ID'];
200 foreach ($sites as $site)
202 Site::update($site, [
203 'DATE_MODIFY' =>
false
215 public static function getForms(
bool $force =
false): array
218 if ($forms && !$force)
225 $forms = self::getFormsForPortal();
229 $forms = self::getFormsViaConnector();
239 protected static function isCrm(): bool
241 return Loader::includeModule(
'crm');
246 $res = Webform\Internals\FormTable::getDefaultTypeList(
248 'select' => self::AVAILABLE_FORM_FIELDS,
257 while ($form = $res->fetch())
259 $form[
'ID'] = (int)$form[
'ID'];
260 $webpack = Webpack\Form::instance($form[
'ID']);
261 if (!$webpack->isBuilt())
264 $webpack = Webpack\Form::instance($form[
'ID']);
266 $form[
'URL'] = $webpack->getEmbeddedFileUrl();
267 $forms[$form[
'ID']] = $form;
276 $client = ApClient::init();
279 $res = $client->call(
'crm.webform.list', [
'GET_INACTIVE' =>
'Y']);
280 if (isset($res[
'result']) && is_array($res[
'result']))
282 foreach ($res[
'result'] as $form)
284 $form[
'ID'] = (int)$form[
'ID'];
285 $forms[$form[
'ID']] = $form;
288 else if (isset($res[
'error']))
291 'code' => $res[
'error'],
292 'message' => $res[
'error_description'] ?? $res[
'error'],
306 $forms = self::getFormsByFilter([
'ID' => $id]);
308 return !empty($forms) ? array_shift($forms) : [];
317 return self::getFormsByFilter([
'IS_CALLBACK_FORM' =>
'Y',
'ACTIVE' =>
'Y']);
322 $filter = array_filter(
324 static function ($key)
326 return in_array($key, self::AVAILABLE_FORM_FIELDS,
true);
334 $forms = self::getFormsForPortal($filter);
338 foreach (self::getFormsViaConnector() as $form)
341 foreach ($filter as $key => $value)
343 if (!$form[$key] || $form[$key] !== $value)
351 $forms[$form[
'ID']] = $form;
372 if (!isset($manifest[
'assets']) || !is_array($manifest[
'assets']))
374 $manifest[
'assets'] = [];
376 if (!isset($manifest[
'assets'][
'ext']))
378 $manifest[
'assets'][
'ext'] = [];
380 if (!is_array($manifest[
'assets'][
'ext']))
382 $manifest[
'assets'][
'ext'] = [$manifest[
'assets'][
'ext']];
384 if (!in_array(
'landing_form', $manifest[
'assets'][
'ext'],
true))
386 $manifest[
'assets'][
'ext'][] =
'landing_form';
391 !isset($manifest[
'style'][
'block']) && !isset($manifest[
'style'][
'nodes'])
394 $manifest[
'style'] = [
395 'block' => [
'type' => Block::DEFAULT_WRAPPER_STYLE],
396 'nodes' => $manifest[
'style'] ?? [],
399 $manifest[
'style'][
'nodes'][self::SELECTOR_FORM_NODE] = [
400 'type' => self::STYLE_SETTING,
405 $link =
'/crm/webform/';
409 $link =
'/bitrix/admin/b24connector_crm_forms.php?lang=' . LANGUAGE_ID;
413 $manifest[
'block'][
'attrsFormDescription'] =
'<a href="' . $link .
'" target="_blank">' .
419 $manifest[
'callbacks'] = [
420 'afterAdd' =>
function (
Block &$block)
425 $dom = $block->getDom();
426 if (!($node = $dom->querySelector(self::SELECTOR_FORM_NODE)))
431 $attrsToSet = [self::ATTR_FORM_EMBED =>
''];
434 $attrsToSet[self::ATTR_FORM_FROM_CONNECTOR] =
'Y';
439 ($attrsExists = $node->getAttributes())
440 && isset($attrsExists[self::ATTR_FORM_PARAMS])
441 && $attrsExists[self::ATTR_FORM_PARAMS]
442 && $attrsExists[self::ATTR_FORM_PARAMS]->getValue()
445 $attrsToSet[self::ATTR_FORM_PARAMS] = $attrsExists[self::ATTR_FORM_PARAMS]->getValue();
450 $forms = self::getFormsByFilter([
451 'XML_ID' =>
'crm_preset_fb'
453 $forms = self::prepareFormsToAttrs($forms);
456 $forms = self::getForms(
true);
457 $forms = self::prepareFormsToAttrs($forms);
460 $forms = self::createDefaultForm();
461 $forms = self::prepareFormsToAttrs($forms);
467 self::setFormIdParam(
469 str_replace(self::INLINE_MARKER_PREFIX,
'', $forms[0][
'value'])
476 '<div class="g-landing-alert">'
480 $block->saveContent($dom->saveHTML());
483 $block->setAttributes([self::SELECTOR_FORM_NODE => $attrsToSet]);
492 !array_key_exists(
'attrs', $manifest)
493 || !is_array($manifest[
'attrs'])
496 $manifest[
'attrs'] = [];
500 $manifest[
'attrs'][self::SELECTOR_FORM_NODE] =
501 Landing::getEditMode()
503 : [[
'attribute' => self::ATTR_FORM_PARAMS]];
521 $forms = self::getForms();
522 $forms = self::prepareFormsToAttrs($forms);
526 'name' =>
'Embed form flag',
527 'attribute' => self::ATTR_FORM_EMBED,
532 'name' =>
'Form design',
533 'attribute' => self::ATTR_FORM_STYLE,
538 'name' =>
'Form from connector flag',
539 'attribute' => self::ATTR_FORM_FROM_CONNECTOR,
550 'attribute' => self::ATTR_FORM_PARAMS,
558 'attribute' => self::ATTR_FORM_USE_STYLE,
577 'attribute' => self::ATTR_FORM_PARAMS,
579 'items' => !empty(self::$errors)
580 ? array_map(fn ($item) => [
'name' => $item[
'message'],
'value' =>
false], self::$errors)
599 foreach ($forms as $form)
601 if (array_key_exists(
'ACTIVE', $form) && $form[
'ACTIVE'] !==
'Y')
607 'name' => $form[
'NAME'],
608 'value' => self::INLINE_MARKER_PREFIX . $form[
'ID'],
611 if ($form[
'IS_CALLBACK_FORM'] ===
'Y')
617 array_unshift($sorted, $item);
635 if (empty($landingIds))
640 if (!is_array($landingIds))
642 $landingIds = [$landingIds];
645 return BlockTable::getList(
647 'select' => [
'ID',
'LID'],
649 '=LID' => $landingIds,
651 'CONTENT' =>
'%data-b24form=%',
665 $block =
new Block($blockId);
666 if (preg_match(self::REGEXP_FORM_ID_INLINE, $block->getContent(), $matches))
668 return (
int)$matches[1];
681 $block =
new Block($blockId);
682 self::setFormIdParam($block, $formId);
685 return $block->getError()->isEmpty();
695 if (($form = self::getFormById($formId)))
698 $newParam = self::INLINE_MARKER_PREFIX . $form[
'ID'];
701 self::SELECTOR_FORM_NODE => [self::ATTR_FORM_PARAMS => $newParam],
712 if ($formId = self::createForm([]))
714 return self::getFormsByFilter([
'ID' => $formId]);
728 $form =
new WebForm\Form;
730 $defaultData = WebForm\Preset::getById(
'crm_preset_cd');
732 $defaultData[
'XML_ID'] =
'';
733 $defaultData[
'ACTIVE'] =
'Y';
734 $defaultData[
'IS_SYSTEM'] =
'N';
735 $defaultData[
'IS_CALLBACK_FORM'] =
'N';
736 $defaultData[
'BUTTON_CAPTION'] = $form->getButtonCaption();
738 $agreementId = UserConsent::getDefaultAgreementId();
739 $defaultData[
'USE_LICENCE'] = $agreementId ?
'Y' :
'N';
742 $defaultData[
'LICENCE_BUTTON_IS_CHECKED'] =
'Y';
743 $defaultData[
'AGREEMENT_ID'] = $agreementId;
746 $isLeadEnabled = LeadSettings::getCurrent()->isEnabled();
747 $defaultData[
'ENTITY_SCHEME'] = (string)(
749 ? WebForm\Entity::ENUM_ENTITY_SCHEME_LEAD
750 : WebForm\Entity::ENUM_ENTITY_SCHEME_DEAL
753 $currentUserId = is_object(
$GLOBALS[
'USER']) ?
$GLOBALS[
'USER']->getId() :
null;
754 $defaultData[
'ACTIVE_CHANGE_BY'] = $currentUserId;
755 $defaultData[
'ASSIGNED_BY_ID'] = $currentUserId;
757 $formData = array_merge($defaultData, $formData);
758 $form->merge($formData);
761 return !$form->hasErrors() ? $form->getId() :
null;
773 if (($formData = self::getSpecialFormsData()[$xmlId]))
776 foreach (self::getForms() as $form)
779 array_key_exists(
'XML_ID', $form)
780 && $form[
'XML_ID'] === $xmlId
783 $formId = $form[
'ID'];
790 $formId = self::createForm($formData);
795 self::setFormIdParam($block, $formId);
806 'crm_preset_store_v3' => [
807 'XML_ID' =>
'crm_preset_store_v3',
811 'RESULT_SUCCESS_TEXT' =>
Loc::getMessage(
'LANDING_FORM_SPECIAL_STOREV3_RESULT_SUCCESS'),
812 'RESULT_FAILURE_TEXT' =>
Loc::getMessage(
'LANDING_FORM_SPECIAL_STOREV3_RESULT_FAILURE'),
813 'COPYRIGHT_REMOVED' =>
'N',
816 'DEAL_DC_ENABLED' =>
'Y',
818 'BUTTON_CAPTION' =>
'',
822 'CODE' =>
'CONTACT_NAME',
823 'CAPTION' =>
Loc::getMessage(
'LANDING_FORM_SPECIAL_STOREV3_FIELD_NAME'),
831 'CODE' =>
'CONTACT_PHONE',
832 'CAPTION' =>
Loc::getMessage(
'LANDING_FORM_SPECIAL_STOREV3_FIELD_PHONE'),
840 'CODE' =>
'DEAL_COMMENTS',
841 'CAPTION' =>
Loc::getMessage(
'LANDING_FORM_SPECIAL_STOREV3_FIELD_COMMENT'),
851 $isLeadEnabled = LeadSettings::getCurrent()->isEnabled();
853 foreach ($data as $id => $form)
857 foreach ($data[$id][
'FIELDS'] as $key => $field)
859 $field[
'CODE'] = str_replace([
'CONTACT',
'DEAL'],
'LEAD', $field[
'CODE']);
860 $data[$id][
'FIELDS'][$key] = $field;
880 $res = BlockTable::getList(
891 while ($row = $res->fetch())
893 $block =
new Block($row[
'ID']);
894 self::updateBlockToEmbed($block);
907 !$manifest[
'block'][
'subtype']
908 || (!is_array($manifest[
'block'][
'subtype']) && $manifest[
'block'][
'subtype'] !==
'form')
909 || (is_array($manifest[
'block'][
'subtype']) && !in_array(
'form', $manifest[
'block'][
'subtype'],
true))
916 !($resultNode = $dom->querySelector(self::SELECTOR_FORM_NODE))
917 || !($attrs = $resultNode->getAttributes())
918 || !array_key_exists(self::ATTR_FORM_PARAMS, $attrs))
922 $formParams = explode(
'|', $attrs[self::ATTR_FORM_PARAMS]->getValue());
923 if (count($formParams) !== 2 || !(
int)$formParams[0])
929 $forms = self::getForms();
930 if (array_key_exists($formParams[0], $forms))
932 $form = $forms[$formParams[0]];
933 self::setFormIdParam($block, $form[
'ID']);
934 $resultNode->setAttribute(self::ATTR_FORM_EMBED,
'');
935 $resultNode->removeAttribute(self::ATTR_FORM_OLD_DOMAIN);
936 $resultNode->removeAttribute(self::ATTR_FORM_OLD_HEADER);
939 !array_key_exists(self::ATTR_FORM_STYLE, $attrs)
940 || !$attrs[self::ATTR_FORM_STYLE]->getValue()
944 $contentFromRepo = Block::getContentFromRepository($block->
getCode());
947 && preg_match(self::REGEXP_FORM_STYLE, $contentFromRepo, $style)
950 $resultNode->setAttribute(self::ATTR_FORM_STYLE, $style[1]);
955 if (($oldStyleNode = $dom->querySelector(self::SELECTOR_OLD_STYLE_NODE)))
957 $oldStyleNode->getParentNode()->removeChild($oldStyleNode);
972 "Now using embedded forms, no need domain",
save(array $additionalFields=[])
getManifest($extended=false, $missCache=false, array $params=array())
saveContent(string $content, $designed=false)
static loadMessages($file)
static getMessage($code, $replace=null, $language=null)
$GLOBALS['____1979065141']