@snabcentr/client-core 2.68.0 → 2.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import * as i1 from 'rxjs';
2
2
  import { of, startWith as startWith$1, Subject, ReplaySubject, partition, combineLatest, map as map$1, debounceTime, switchMap, tap, filter, shareReplay, distinctUntilChanged, BehaviorSubject, materialize, dematerialize, merge, distinctUntilKeyChanged, skip, first, catchError as catchError$1, throwError, expand, takeWhile, toArray, EMPTY, take, defaultIfEmpty, concatMap, finalize, takeUntil, interval, share, scan } from 'rxjs';
3
3
  import { map, startWith, catchError } from 'rxjs/operators';
4
4
  import { parseISO, parse, isValid, format } from 'date-fns';
5
- import { isString, isNil, isMatch, isArray, get } from 'lodash-es';
5
+ import { isString, isNil, isMatch, isArray, omit, get } from 'lodash-es';
6
6
  import * as i0 from '@angular/core';
7
7
  import { InjectionToken, inject, PLATFORM_ID, Injectable, Inject, Optional, EventEmitter, DestroyRef, LOCALE_ID, Pipe, RendererFactory2 } from '@angular/core';
8
8
  import { WA_LOCAL_STORAGE, WA_USER_AGENT, WA_WINDOW } from '@ng-web-apis/common';
@@ -7644,36 +7644,36 @@ class SchemaOrgFactory {
7644
7644
  *
7645
7645
  * @param product Данные о продукте.
7646
7646
  * @param productPath Url путь к товару. В пути должен присутствовать шаблон ':id', обозначающий идентификатор товара для подстановки.
7647
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7647
7648
  */
7648
- generateForProductItem(product, productPath) {
7649
+ generateForProductItem(product, productPath, id) {
7649
7650
  const productUrl = `${this.urls.siteUrl}${productPath.replace(':id', this.idOrSlugPipe.transform(product).toString())}`;
7650
7651
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
7651
- const image = this.mediaImageTransformerPipe.transform(product?.getImagePreview() ?? product.image, true);
7652
+ const image = this.mediaImageTransformerPipe.transform(product?.getImagePreview?.() ?? product.image, true);
7652
7653
  const description = product.properties?.description;
7653
7654
  const priceValidUntil = this.normalizePriceValidUntil(product.discount?.expiredAt);
7654
7655
  return {
7655
7656
  '@context': 'https://schema.org',
7656
7657
  '@type': 'Product',
7658
+ ...(id && { '@id': id }),
7657
7659
  name: product.name,
7658
7660
  ...(image && { image }),
7659
7661
  ...(description && { description }),
7660
7662
  mpn: product.code,
7661
7663
  url: productUrl,
7662
- offers: [
7663
- {
7664
- '@type': 'Offer',
7665
- priceCurrency: 'RUB',
7666
- ...(priceValidUntil && { priceValidUntil }),
7667
- price: product.costRub,
7668
- availability: this.getAvailability(product),
7669
- itemCondition: 'https://schema.org/NewCondition',
7670
- seller: {
7671
- '@type': 'Organization',
7672
- name: this.companyInfo.name,
7673
- },
7674
- url: productUrl,
7664
+ offers: {
7665
+ '@type': 'Offer',
7666
+ priceCurrency: 'RUB',
7667
+ ...(priceValidUntil && { priceValidUntil }),
7668
+ price: product.costRub,
7669
+ availability: this.getAvailability(product),
7670
+ itemCondition: 'https://schema.org/NewCondition',
7671
+ seller: {
7672
+ '@type': 'Organization',
7673
+ name: this.companyInfo.name,
7675
7674
  },
7676
- ],
7675
+ url: productUrl,
7676
+ },
7677
7677
  };
7678
7678
  }
7679
7679
  /**
@@ -7684,13 +7684,15 @@ class SchemaOrgFactory {
7684
7684
  * @param categoryPath Url путь к категориям товаров. В пути должен присутствовать шаблон ':id', обозначающий идентификатор категории для подстановки.
7685
7685
  * @param productPath Url путь к товару. В пути должен присутствовать шаблон ':id', обозначающий идентификатор товара для подстановки.
7686
7686
  * @param breadcrumbs Данные о хлебных крошках для категории.
7687
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7687
7688
  */
7688
- generateForCategoryItem(category, products, categoryPath, productPath, breadcrumbs) {
7689
+ generateForCategoryItem(category, products, categoryPath, productPath, breadcrumbs, id) {
7689
7690
  const description = category.seo?.description ?? category.properties?.description;
7690
7691
  const image = this.mediaImageTransformerPipe.transform(category.image, true);
7691
7692
  return {
7692
7693
  '@context': 'https://schema.org',
7693
7694
  '@type': 'CollectionPage',
7695
+ ...(id && { '@id': id }),
7694
7696
  name: category.seo?.title ?? category.name,
7695
7697
  ...(description && { description }),
7696
7698
  url: this.getCategoryCanonicalUrl(category, categoryPath),
@@ -7708,12 +7710,6 @@ class SchemaOrgFactory {
7708
7710
  name: category.name,
7709
7711
  ...(description && { description }),
7710
7712
  },
7711
- // Информация о сайте.
7712
- isPartOf: {
7713
- '@type': 'WebSite',
7714
- name: this.companyInfo.name,
7715
- url: this.urls.siteUrl,
7716
- },
7717
7713
  // Связанные страницы.
7718
7714
  relatedLink: [
7719
7715
  `${this.urls.siteUrl}${categoryPath.replace(':id', '')}`,
@@ -7754,6 +7750,223 @@ class SchemaOrgFactory {
7754
7750
  ],
7755
7751
  };
7756
7752
  }
7753
+ /**
7754
+ * Генерирует и возвращает схему данных OnlineStore на основе данных компании из окружения.
7755
+ */
7756
+ // eslint-disable-next-line sonarjs/function-return-type
7757
+ generateForOrganization() {
7758
+ const postalAddress = this.createPostalAddress(this.companyInfo.address);
7759
+ return {
7760
+ '@context': 'https://schema.org',
7761
+ '@type': 'OnlineStore',
7762
+ '@id': `${this.urls.siteUrl}#organization`,
7763
+ name: this.companyInfo.name,
7764
+ legalName: this.companyInfo.name,
7765
+ url: this.urls.siteUrl,
7766
+ logo: this.urls.logoUrl,
7767
+ image: this.urls.logoUrl,
7768
+ email: this.companyInfo.mail,
7769
+ telephone: this.companyInfo.phone,
7770
+ ...(postalAddress && { address: postalAddress }),
7771
+ legalAddress: this.createPostalAddress({ streetAddress: this.companyInfo.legalAddress }),
7772
+ // TODO: Перечислить все розничные магазины.
7773
+ // hasPOS: [],
7774
+ taxID: this.companyInfo.inn,
7775
+ identifier: {
7776
+ '@type': 'PropertyValue',
7777
+ propertyID: 'OGRN',
7778
+ value: this.companyInfo.ogrn,
7779
+ },
7780
+ contactPoint: this.createOrganizationContactPoints(),
7781
+ ...(this.companyInfo.warehouseAddress.length > 0 && {
7782
+ location: this.companyInfo.warehouseAddress.map((warehouseAddress) => ({
7783
+ '@type': 'Place',
7784
+ name: `${this.companyInfo.name} — склад самовывоза`,
7785
+ address: warehouseAddress,
7786
+ })),
7787
+ }),
7788
+ };
7789
+ }
7790
+ /**
7791
+ * Генерирует и возвращает схему данных для указанной новости.
7792
+ *
7793
+ * @param news Данные о новости.
7794
+ * @param newsPath Url путь к новости. В пути должен присутствовать шаблон ':id', обозначающий идентификатор новости для подстановки.
7795
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7796
+ */
7797
+ generateForNewsArticle(news, newsPath, id) {
7798
+ const newsUrl = `${this.urls.siteUrl}${newsPath.replace(':id', news.id.toString())}`;
7799
+ const image = this.mediaImageTransformerPipe.transform(news.image, true);
7800
+ const headline = news.seo?.title ?? news.subject;
7801
+ const description = news.seo?.description;
7802
+ const datePublished = this.normalizeSchemaDate(news.createdAt);
7803
+ const articleBody = news.text ? this.stripHtml(news.text) : undefined;
7804
+ return {
7805
+ '@context': 'https://schema.org',
7806
+ '@type': 'NewsArticle',
7807
+ ...(id && { '@id': id }),
7808
+ headline,
7809
+ ...(description && { description }),
7810
+ ...(image && { image }),
7811
+ ...(datePublished && { datePublished }),
7812
+ ...(articleBody && { articleBody }),
7813
+ url: newsUrl,
7814
+ mainEntityOfPage: newsUrl,
7815
+ author: {
7816
+ '@type': 'Organization',
7817
+ name: this.companyInfo.name,
7818
+ url: this.urls.siteUrl,
7819
+ },
7820
+ publisher: {
7821
+ '@type': 'Organization',
7822
+ name: this.companyInfo.name,
7823
+ logo: {
7824
+ '@type': 'ImageObject',
7825
+ url: this.urls.logoUrl,
7826
+ },
7827
+ },
7828
+ };
7829
+ }
7830
+ /**
7831
+ * Генерирует и возвращает схему данных FAQPage для страницы с вопросами и ответами.
7832
+ *
7833
+ * @param items Список вопросов и ответов.
7834
+ * @param pagePath Url путь к странице FAQ.
7835
+ * @param pageName Необязательное название страницы.
7836
+ * @param id Необязательный идентификатор сущности для поля `@id` в JSON-LD.
7837
+ */
7838
+ generateForFaqPage(items, pagePath, pageName, id) {
7839
+ const pageUrl = `${this.urls.siteUrl}${pagePath}`;
7840
+ return {
7841
+ '@context': 'https://schema.org',
7842
+ '@type': 'FAQPage',
7843
+ ...(id && { '@id': id }),
7844
+ ...(pageName && { name: pageName }),
7845
+ url: pageUrl,
7846
+ mainEntity: items.map((item) => ({
7847
+ '@type': 'Question',
7848
+ name: item.question,
7849
+ acceptedAnswer: {
7850
+ '@type': 'Answer',
7851
+ text: this.stripHtml(item.answer),
7852
+ },
7853
+ })),
7854
+ };
7855
+ }
7856
+ /**
7857
+ * Объединяет несколько JSON-LD сущностей в один документ с `@graph`.
7858
+ *
7859
+ * @param data Массив JSON-LD сущностей для объединения.
7860
+ */
7861
+ // eslint-disable-next-line class-methods-use-this,sonarjs/function-return-type
7862
+ merge(data) {
7863
+ return {
7864
+ '@context': 'https://schema.org',
7865
+ '@graph': data.map((item) => omit(item, '@context')),
7866
+ };
7867
+ }
7868
+ /**
7869
+ * Формирует PostalAddress из структурированного адреса компании.
7870
+ *
7871
+ * @param address Структурированный адрес компании.
7872
+ */
7873
+ // eslint-disable-next-line class-methods-use-this
7874
+ createPostalAddress(address) {
7875
+ const streetAddress = [address.streetAddress, address.extendedAddress].filter(Boolean).join(', ');
7876
+ if (!streetAddress && !address.locality && !address.region && !address.postalCode && !address.country) {
7877
+ return undefined;
7878
+ }
7879
+ return {
7880
+ '@type': 'PostalAddress',
7881
+ ...(streetAddress && { streetAddress }),
7882
+ ...(address.locality && { addressLocality: address.locality }),
7883
+ ...(address.region && { addressRegion: address.region }),
7884
+ ...(address.postalCode && { postalCode: address.postalCode }),
7885
+ ...(address.country && { addressCountry: address.country }),
7886
+ };
7887
+ }
7888
+ /**
7889
+ * Формирует список ContactPoint для Organization.
7890
+ */
7891
+ createOrganizationContactPoints() {
7892
+ const contactPoints = [
7893
+ {
7894
+ '@type': 'ContactPoint',
7895
+ contactType: 'customer service',
7896
+ telephone: this.companyInfo.phone,
7897
+ email: this.companyInfo.mail,
7898
+ areaServed: 'RU',
7899
+ availableLanguage: 'Russian',
7900
+ },
7901
+ ];
7902
+ if (this.companyInfo.secondaryPhone) {
7903
+ contactPoints.push({
7904
+ '@type': 'ContactPoint',
7905
+ contactType: 'customer service',
7906
+ telephone: this.companyInfo.secondaryPhone,
7907
+ areaServed: 'RU',
7908
+ availableLanguage: 'Russian',
7909
+ });
7910
+ }
7911
+ if (this.companyInfo.hr) {
7912
+ contactPoints.push({
7913
+ '@type': 'ContactPoint',
7914
+ contactType: 'HR',
7915
+ telephone: this.companyInfo.hr.phone,
7916
+ email: this.companyInfo.hr.mail,
7917
+ areaServed: 'RU',
7918
+ availableLanguage: 'Russian',
7919
+ });
7920
+ }
7921
+ return contactPoints;
7922
+ }
7923
+ /**
7924
+ * Удаляет HTML-разметку из текста.
7925
+ *
7926
+ * @param html Текст с HTML-разметкой.
7927
+ */
7928
+ // eslint-disable-next-line class-methods-use-this
7929
+ stripHtml(html) {
7930
+ const withoutTags = html
7931
+ .split('<')
7932
+ .map((part, index) => {
7933
+ if (index === 0) {
7934
+ return part;
7935
+ }
7936
+ const closeTagIndex = part.indexOf('>');
7937
+ return closeTagIndex === -1 ? part : ` ${part.slice(closeTagIndex + 1)}`;
7938
+ })
7939
+ .join('');
7940
+ return withoutTags
7941
+ .replaceAll(/\s+/g, ' ')
7942
+ .replaceAll(/ ([.,!?;:])/g, '$1')
7943
+ .trim();
7944
+ }
7945
+ /**
7946
+ * Нормализует дату в формат Schema.org (ISO 8601).
7947
+ *
7948
+ * @param dateValue Дата для нормализации.
7949
+ */
7950
+ // eslint-disable-next-line class-methods-use-this
7951
+ normalizeSchemaDate(dateValue) {
7952
+ if (!dateValue) {
7953
+ return undefined;
7954
+ }
7955
+ if (/^\d{4}-\d{2}-\d{2}/.test(dateValue)) {
7956
+ return dateValue;
7957
+ }
7958
+ const withTimeMatch = /^(\d{2})\.(\d{2})\.(\d{4}) (\d{2}):(\d{2})$/.exec(dateValue);
7959
+ if (withTimeMatch) {
7960
+ const [, day, month, year, hours, minutes] = withTimeMatch;
7961
+ return `${year}-${month}-${day}T${hours}:${minutes}:00`;
7962
+ }
7963
+ const dateOnlyMatch = /^(\d{2})\.(\d{2})\.(\d{4})$/.exec(dateValue);
7964
+ if (!dateOnlyMatch) {
7965
+ return undefined;
7966
+ }
7967
+ const [, day, month, year] = dateOnlyMatch;
7968
+ return `${year}-${month}-${day}`;
7969
+ }
7757
7970
  /**
7758
7971
  * Нормализует дату окончания цены в формат Schema.org (YYYY-MM-DD).
7759
7972
  *
@@ -7775,9 +7988,9 @@ class SchemaOrgFactory {
7775
7988
  // eslint-disable-next-line class-methods-use-this
7776
7989
  getAvailability(product) {
7777
7990
  if (product.onOrder) {
7778
- return 'PreOrder';
7991
+ return 'https://schema.org/PreOrder';
7779
7992
  }
7780
- return product.stockCount?.length ? 'InStock' : 'OutOfStock';
7993
+ return product.stockCount?.length ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock';
7781
7994
  }
7782
7995
  /**
7783
7996
  * Проверяет, является ли категория виртуальной.
@@ -7821,21 +8034,19 @@ class SchemaOrgFactory {
7821
8034
  url: productUrl,
7822
8035
  ...(image && { image }),
7823
8036
  ...(description && { description }),
7824
- offers: [
7825
- {
7826
- '@type': 'Offer',
7827
- priceCurrency: 'RUB',
7828
- ...(priceValidUntil && { priceValidUntil }),
7829
- price: product.costRub,
7830
- availability: this.getAvailability(product),
7831
- itemCondition: 'https://schema.org/NewCondition',
7832
- seller: {
7833
- '@type': 'Organization',
7834
- name: this.companyInfo.name,
7835
- },
7836
- url: productUrl,
8037
+ offers: {
8038
+ '@type': 'Offer',
8039
+ priceCurrency: 'RUB',
8040
+ ...(priceValidUntil && { priceValidUntil }),
8041
+ price: product.costRub,
8042
+ availability: this.getAvailability(product),
8043
+ itemCondition: 'https://schema.org/NewCondition',
8044
+ seller: {
8045
+ '@type': 'Organization',
8046
+ name: this.companyInfo.name,
7837
8047
  },
7838
- ],
8048
+ url: productUrl,
8049
+ },
7839
8050
  },
7840
8051
  };
7841
8052
  }
@@ -7857,14 +8068,21 @@ class SchemaOrgFactory {
7857
8068
  itemListOrder: 'https://schema.org/ItemListUnordered',
7858
8069
  itemListElement: [
7859
8070
  // Добавляем подкатегории в начало списка.
7860
- ...childCategories.slice(0, 5).map((subCategory, index) => ({
7861
- '@type': 'ListItem',
7862
- position: index + 1,
7863
- name: subCategory.name,
7864
- url: this.getCategoryCanonicalUrl(subCategory, categoryPath),
7865
- image: this.mediaImageTransformerPipe.transform(subCategory.image, true),
7866
- description: subCategory.seo?.description ?? subCategory.properties?.description,
7867
- })),
8071
+ ...childCategories.slice(0, 5).map((subCategory, index) => {
8072
+ const image = this.mediaImageTransformerPipe.transform(subCategory.image, true);
8073
+ const description = subCategory.seo?.description ?? subCategory.properties?.description;
8074
+ return {
8075
+ '@type': 'ListItem',
8076
+ position: index + 1,
8077
+ item: {
8078
+ '@type': 'CollectionPage',
8079
+ name: subCategory.name,
8080
+ url: this.getCategoryCanonicalUrl(subCategory, categoryPath),
8081
+ ...(image && { image }),
8082
+ ...(description && { description }),
8083
+ },
8084
+ };
8085
+ }),
7868
8086
  // Добавляем товары после подкатегорий.
7869
8087
  ...products.slice(0, 10).map((product, index) => this.createProductsListItem(product, childCategories.length + index + 1, productPath)),
7870
8088
  ],
@@ -7877,37 +8095,46 @@ class SchemaOrgFactory {
7877
8095
  * @param categoryPath Url путь к категориям товаров. В пути должен присутствовать шаблон ':id', обозначающий идентификатор категории для подстановки.
7878
8096
  */
7879
8097
  createCatalogBreadcrumbsList(breadcrumbs, categoryPath) {
8098
+ const catalogUrl = `${this.urls.siteUrl}${categoryPath.replace(':id', '')}`;
7880
8099
  const breadcrumbItems = [
7881
8100
  // Всегда добавляем главную страницу.
7882
- {
7883
- '@type': 'ListItem',
7884
- position: 1,
7885
- name: 'Главная',
7886
- item: this.urls.siteUrl,
7887
- },
8101
+ this.createBreadcrumbListItem(1, 'Главная', this.urls.siteUrl),
7888
8102
  // Добавляем каталог.
7889
- {
7890
- '@type': 'ListItem',
7891
- position: 2,
7892
- name: 'Каталог',
7893
- item: `${this.urls.siteUrl}/${categoryPath}`,
7894
- },
8103
+ this.createBreadcrumbListItem(2, 'Каталог', catalogUrl),
7895
8104
  ];
7896
8105
  // Добавляем существующие breadcrumbs с корректировкой позиций.
7897
8106
  breadcrumbs.forEach((item, index) => {
7898
8107
  const link = isArray(item.routerLink) ? item.routerLink.join('/') : item.routerLink;
7899
- breadcrumbItems.push({
7900
- '@type': 'ListItem',
7901
- position: index + 3, // Начинаем с позиции 3 (после Главная и Каталог).
7902
- name: item.label,
7903
- item: link ? `${this.urls.siteUrl}/${link}` : undefined,
7904
- });
8108
+ breadcrumbItems.push(this.createBreadcrumbListItem(index + 3, item.label, link ? `${this.urls.siteUrl}/${link}` : undefined));
7905
8109
  });
7906
8110
  return {
7907
8111
  '@type': 'BreadcrumbList',
8112
+ itemListOrder: 'https://schema.org/ItemListOrderAscending',
7908
8113
  itemListElement: breadcrumbItems,
7909
8114
  };
7910
8115
  }
8116
+ /**
8117
+ * Создаёт элемент BreadcrumbList в формате, рекомендованном Schema.org.
8118
+ *
8119
+ * @param position Позиция элемента в цепочке.
8120
+ * @param name Название элемента.
8121
+ * @param url URL элемента.
8122
+ */
8123
+ // eslint-disable-next-line class-methods-use-this
8124
+ createBreadcrumbListItem(position, name, url) {
8125
+ return {
8126
+ '@type': 'ListItem',
8127
+ position,
8128
+ ...(url
8129
+ ? {
8130
+ item: {
8131
+ '@id': url,
8132
+ name,
8133
+ },
8134
+ }
8135
+ : { name }),
8136
+ };
8137
+ }
7911
8138
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SchemaOrgFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7912
8139
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SchemaOrgFactory, providedIn: 'root' }); }
7913
8140
  }
@@ -7963,6 +8190,10 @@ class ScSeoService {
7963
8190
  * Объект {@link Document}, предоставляющий доступ к DOM страницы.
7964
8191
  */
7965
8192
  this.document = inject(DOCUMENT);
8193
+ /**
8194
+ * Фабрика для создания данных Schema.org.
8195
+ */
8196
+ this.schemaOrgFactory = inject(SchemaOrgFactory);
7966
8197
  /**
7967
8198
  * Фабрика для создания экземпляров {@link Renderer2}.
7968
8199
  */
@@ -7978,8 +8209,9 @@ class ScSeoService {
7978
8209
  * @param resource Ресурс на основе которого необходимо установить мета-теги.
7979
8210
  * @param img Изображение. Если не пришло, то будет установлено значение по умолчанию.
7980
8211
  * @param robots Список robots-тегов для страницы.
8212
+ * @param schemaOrgData Данные Schema.org для встраивания на странице.
7981
8213
  */
7982
- setFromResource(resource, img = this.urls.logoUrl, robots = ['index', 'follow']) {
8214
+ setFromResource(resource, img, robots, schemaOrgData) {
7983
8215
  const updatedResource = {
7984
8216
  title: this.replaceTemplates(resource?.title ?? this.defaultSeo.title, resource?.instanceData ?? {}),
7985
8217
  description: this.replaceTemplates(resource?.description ?? this.defaultSeo.description, resource?.instanceData ?? {}),
@@ -7987,21 +8219,24 @@ class ScSeoService {
7987
8219
  meta: resource?.meta ?? [],
7988
8220
  };
7989
8221
  const url = `${this.urls.siteUrl}${this.router.url}`;
7990
- this.setMetaTags(updatedResource.title, updatedResource.description, updatedResource.keywords, updatedResource.meta, robots);
7991
- this.setOpenGraphMetaTags(updatedResource.title, updatedResource.description, url, img);
8222
+ this.setMetaTags(updatedResource.title, updatedResource.description, updatedResource.keywords, updatedResource.meta, robots ?? ['index', 'follow']);
8223
+ this.setOpenGraphMetaTags(updatedResource.title, updatedResource.description, url, img ?? this.urls.logoUrl);
7992
8224
  this.setCanonicalLink(url);
8225
+ // Устанавливаем Schema.org параметры.
8226
+ this.setSchemaOrgData(this.schemaOrgFactory.merge([this.schemaOrgFactory.generateForOrganization(), ...(schemaOrgData ? [schemaOrgData] : [])]));
7993
8227
  }
7994
8228
  /**
7995
8229
  * Устанавливает seo параметры со значением по умолчанию.
7996
8230
  *
7997
8231
  * @param title Заголовок страницы.
7998
8232
  * @param robots Список robots тегов для страницы.
8233
+ * @param schemaOrgData Данные Schema.org для встраивания на странице.
7999
8234
  */
8000
- setByDefault(title, robots = ['index', 'follow']) {
8235
+ setByDefault(title, robots, schemaOrgData) {
8001
8236
  this.setFromResource({
8002
8237
  title: `${title ?? this.defaultSeo.title} - ${this.companyInfo.name}`,
8003
8238
  description: title ? `${title}, ${this.defaultSeo.description}` : this.defaultSeo.description,
8004
- }, this.urls.logoUrl, robots);
8239
+ }, this.urls.logoUrl, robots ?? ['index', 'follow'], schemaOrgData);
8005
8240
  }
8006
8241
  /**
8007
8242
  * Устанавливает seo параметры со значением по умолчанию. Устанавливает значение "не индексировать" для поисковых роботов.
@@ -8032,9 +8267,7 @@ class ScSeoService {
8032
8267
  this.setOpenGraphMetaTags(title, description, url, this.mediaImageTransformerPipe.transform(item.image, true));
8033
8268
  this.setCanonicalLink(url);
8034
8269
  // Устанавливаем Schema.org параметры.
8035
- if (schemaOrgData) {
8036
- this.setSchemaOrgData(schemaOrgData);
8037
- }
8270
+ this.setSchemaOrgData(this.schemaOrgFactory.merge([this.schemaOrgFactory.generateForOrganization(), ...(schemaOrgData ? [schemaOrgData] : [])]));
8038
8271
  }
8039
8272
  /**
8040
8273
  * Заменяет шаблоны в тексте на значения из объекта.