Каталог решений - Yep — простая flat-file CMS на OneScript

Yep — простая flat-file CMS на OneScript

Yep — простая flat-file CMS на OneScript

В наличии

В статье рассмотрено создание простейшей flat-file CMS, на основе каркасной конфигурации для web-приложений OneScript, в среде 1С:Предприятие.

Категория:

Описание

Введение

После публикации статьи, с описанием каркасной конфигурации, для создания web-приложений OneScript и почитав комментарии, я подумал, что неплохо бы сделать пример на ее основе, посложнее, чем вывод пары страничек html, а также такой, чтобы его можно было использовать в практических целях. В разное время на Инфорстарте появлялись публикации, с описанием создания различных CMS с использованием http-сервисов 1С:Предприятие, и я решил в качестве демонстрации создать еще один “велосипед”.

Поскольку опыта в написании CMS я не имею, при помощи google было найдено пару простейших CMS с открытым кодом, которые можно было бы взять за основу – это PICO CMS и Grav CMS. Поскольку я не имею опыта написания программ на php, а также не занимаюсь web-разработкой, пришлось остановить свой выбор на PICO CMS, как на более простой.

О том, что из этого получилось – читайте ниже, а посмотреть на это чудо-творение можно нажав на кнопку "Показать демо" или нажав сюда.

 

Анализ алгоритма работы PICO CMS

После просмотра исходного кода PICO CMS, стало понятным, что в общих чертах она работает по примерно следующей схеме:

  1. Клиент из браузера отправляет запрос с идентификатором контента, который необходимо отобразить. Контент представляет собой обычные текстовые файлы в формате markdown, которые расположены на web-сервере.
  2. CMS ищет и загружает контент в память, в соответствии с настройками, которые хранятся в конфигурационных файлах. Конфигурационные файлы – это обычные текстовые файлы в формате yaml.
  3. CMS имеет так называемые темы. Фактически – это набор шаблонов html-страниц, а также необходимое оформление в виде css, javascript и других файлов. В содержании контента содержится информация о том, какой шаблон необходимо использовать для отображения страницы. Соответственно, на основе этой информации загружается необходимый шаблон.
  4. Производится преобразование контента из markdown в html.
  5. На основе загруженного шаблона, обработанного контента и других параметров, шаблонизатор формирует html страницу, которая и возвращается клиенту.

В качестве шаблонизатора, в системах, написанных на php как правило используется twig. Если совсем утрировано – это такой прокачанный вариант СтрЗаменить.

 

Основные принципы работы Yep

Поскольку Yep CMS создана на 1С, она использует концепцию СКД, где html-страница, возвращаемая пользователю рассматривается как некий отчет. Схема работы, в этом случае, имеет примерно следующий вид:

В качестве схемы данных выступает контент, в качестве параметров компоновки – параметры запроса. Макетом компоновки данных является "Тема" — это макет выводимой страницы, а также ее оформление. На основе этих компонентов, компоновщик данных формирует соответствие, элементами которого являются макет страницы, контент, значения параметров для заполнения макета etc. Процессором вывода данных является сам web-сервис. Он вызывает компоновщик данных, затем на основе полученного результата формирует html страницу и возвращает ее клиенту в теле ответа.

 

Детали реализации

Файловая структура

Файловая структура приложения представлена на рисунке ниже:

Как можно увидеть, в дополнение к стандартным файлам и папкам web-приложения, в корне приложения находятся файлы – Конфигурация.yaml и НастройкиТемы.yaml. Первый – содержит глобальные настройки CMS (такие как имя документа по умолчанию, имя текущей темы etc.), второй – настройки текущей темы (цвета etc). В корне приложения расположены файлы скриптов OneScript – это index.os и article.os, которые формируют страницы/отчеты на основе нашего макета компоновки данных и отправляют их клиенту. Также имеются две папки Контент и Темы. В папке “Контент”, находятся файлы, содержимое которых мы будем отображать, а также файл, описывающий меню нашего сайта.

 В папке “Темы” содержатся варианты оформления наших страниц-отчетов, а также макеты/шаблоны страниц.

Идентификатор контента

Служит для идентификации файла, содержание которого мы хотим отобразить.  В нашем случае, будем передавать его в качестве параметра, аналогично тому, как это сделано в WordPress. В качестве идентификатора используем относительный виртуальный путь к файлу контента, причем используется имя файла контента без расширения. Таким образом, запрос на отображение определенного файла будет выглядеть примерно следующим образом:

http://ИмяСайта/ИмяПроцессораВывода.os?p=ОтносительныйПуть/ИмяФайлаКонтента

Глобальные настройки CMS

Находятся в файле Конфигурация.yaml, который имеет формат yaml и расположен в корне приложения. Содержимое файла имеет примерно следующий вид:

---
# Файл конфигурации Yep CMS

# Название Вашего сайта
ИмяСайта: Yep!

# Краткое описание сайта
Описание: Простая flat-file CMS на 1С

# Имя файла, содержащего информацию о меню
ИмяФайлаМеню: Меню.yaml

# Каталог, где расположен контент (файлы md etc.)
КаталогКонтента: Контент/

# Расширение для файлов контента
РасширениеФайлаКонтента: ".md"

# Каталог, где расположены темы
КаталогТем: Темы/

# Имя папки активной темы
ТекущаяТема: "Демо"

# Расширение для файлов макетов (шаблонов)
РасширениеФайлаМакета: ".html"

# Указывает, надо ли преобразовывать контент из Markdown в Html автоматически
ПреобразоватьКонтент: да

# Определяет имя файла контента по умолчанию. Используется, если контент с указанным именем не найден
СтраницаПоУмолчанию: index

# Список расширений Markdown, который используется для преобразования.
# Если параметр не задан, используется yaml+advanced
РасширенияMarkdown: yaml+advanced

Меню сайта

В отличие от Pico и Grav, где меню сайта строится динамически на основе файловой структуры, в настоящей CMS меню сайта описывается файлом Меню.yaml, который расположен в корне папки контента и имеет примерно следующую структуру:

---
# Файл конфигурации меню сайта
# Меню представляет собой массив элементов (пунктов меню)
# Для организации подменю, в пункт меню добавляется свойство Подменю.

# Пример пункта меню со ссылкой
#- Заголовок: "Со ссылкой"
#  url: "http://oscript.io" 

# Пример пункта меню с подменю
#- Заголовок: С подменю
#  Подменю:
#    - Заголовок: Подменю1
#      Каталог: Описание/
#      Контент: overview
#      Страница: index

- Заголовок: ГЛАВНАЯ
  Страница: index
  Каталог: /
  Контент: index

- Заголовок: ОПИСАНИЕ
  Каталог: Описание/
  Контент: overview
  Страница: index

- Заголовок: ДОКУМЕНТАЦИЯ
  Каталог: Документация/
  Контент: index
  Страница: article

- Заголовок: ЗАГРУЗИТЬ
  Каталог: Download/
  Контент: links
  Страница: index

Формат контента

Файлы контента представляют собой простые текстовые файлы в формате Markdown, которые имеют заголовок, содержащий метаданные в формате yaml.

Примерное содержание файла контента представлено ниже:

---
Заголовок: Yep CMS
Описание: Простая flat-file CMS на языке 1С
ПреобразоватьКонтент: да
ЭтоМакет: да
ЗаполнитьПараметры: да
---
![Это ссылка]({{КаталогКонтента}}/images/default_banner.png)

## ![alt text]({{КаталогТем}}{{ТекущаяТема}}/images/checkmark-o24.png) Простая "файловая" CMS
Yep CMS - это простая система управления контентом, где в качестве контента используются файлы в формате Markdown.
Основой, для создания настоящей системы, является [Pico CMS](http://picocms.org). Однако, некоторые идеи заимствованы также из [Grav CMS](https://getgrav.org/).  
## ![alt text]({{КаталогТем}}{{ТекущаяТема}}/images/checkmark-o24.png) Создана на платформе OneScript
Yep CMS - фактически является http-сервисом, написанным на языке 1С:Предприятие, который выполняется платформой [OneScript](http://oscript.io).  
## ![alt text]({{КаталогТем}}{{ТекущаяТема}}/images/checkmark-o24.png) Разработка и отладка в конфигураторе
Поскольку платформа OneScript обеспечивает совместимость с языком 1С:Предприятие, разработка, отладка и тестирование может производиться непосредственно в конфигураторе.

Как можно увидеть, файл контента имееет заголовок в формате yaml, в котором содержится ряд параметров. Обязательным параметром страницы является “Заголовок”. Также имеется ряд параметров, отвечающих за преобразование контента из формата markdown в формат html.

Компоновка данных

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

// Формирует результат компоновки данных, который используется для вывода страницы
//
Функция ПолучитьРезультатКомпоновкиДанных(ПараметрыКомпоновки) Экспорт
	
	РезультатКомпоновки = Новый Соответствие;
	РезультатКомпоновки.Вставить("Ответ", Новый HTTPСервисОтвет(200));
	КонфигурацияCMS = ПолучитьКонфигурацию();
	
	Если КонфигурацияCMS.Получить("РасширенияMarkdown") = Неопределено Тогда
		КонфигурацияCMS.Вставить("РасширенияMarkdown", "yaml+advanced");
	КонецЕсли;
		
	ПараметрыКомпоновки.Вставить("Конфигурация", КонфигурацияCMS);
	
	НастройкиТемы = ПолучитьНастройкиТемы();
	
	Если Не НастройкиТемы = Неопределено Тогда
		СкопироватьПараметры(НастройкиТемы, КонфигурацияCMS, "НастройкиТемы.");
	КонецЕсли;
	
	РезультатКомпоновки.Вставить("Конфигурация", КонфигурацияCMS);
	РезультатКомпоновки.Вставить("Меню", ПолучитьМеню(ПараметрыКомпоновки));
	РезультатКомпоновки.Вставить("Макет", ПолучитьМакет(ПараметрыКомпоновки));
	
	Страница =  ПолучитьСтраницу(ПараметрыКомпоновки);
	
	Если Страница = Неопределено Тогда
		РезультатКомпоновки.Вставить("Ответ", Новый HTTPСервисОтвет(404));
		Возврат РезультатКомпоновки;
	КонецЕсли;
	
	РезультатКомпоновки.Вставить("Страница", Страница);
	
	ПараметрыВывода = ПолучитьПараметрыВывода(ПараметрыКомпоновки, РезультатКомпоновки);
	РезультатКомпоновки.Вставить("ПараметрыВывода", ПараметрыВывода); 
	
	ОбработатьКонтент(РезультатКомпоновки);
	ПараметрыВывода.Вставить("Контент", Страница.Получить("Контент"));
	
	Возврат РезультатКомпоновки;
	
КонецФункции

Обработка контента

Обработка контента (его преобразование из markdown в html) осуществляется в функции ОбработатьКонтент. Исходный код функции представлен ниже:

// Осуществляет преобразования загруженного контента, в соответствии с настройками
//
Процедура ОбработатьКонтент(РезультатКомпоновки, Страница = Неопределено) Экспорт
	
	Если Страница = Неопределено Тогда
		Страница = РезультатКомпоновки["Страница"];
	КонецЕсли;
	
	КонфигурацияCMS = РезультатКомпоновки["Конфигурация"];
	ПараметрыВывода = РезультатКомпоновки["ПараметрыВывода"];
	
	Если НРег(Страница.Получить("ЭтоМакет")) = "да" И Нрег(Страница.Получить("ЗаполнитьПараметры")) = "да" Тогда
		Страница.Вставить("Контент", Макеты.ЗаполнитьПараметры(Страница.Получить("Контент"), ПараметрыВывода));
	КонецЕсли;
	
	Если Не НРег(Страница.Получить("ПреобразоватьКонтент")) = "нет" И Не НРег(КонфигурацияCMS.Получить("ПреобразоватьКонтент")) = "нет" Тогда
		Страница.Вставить("Контент", MarkdownПроцессор.ПолучитьHtmlИзMarkdown(Страница.Получить("Контент"), КонфигурацияCMS["РасширенияMarkdown"]));
	КонецЕсли;
	
КонецПроцедуры

Как можно увидеть, на процесс обработки контента влияют некотороые глобальные параметры конфигурации, а также параметры, специфичные для файла контента.

Если в свойствах файла контента, установлены свойства ЭтоМакет = да и ЗаполнитьПараметры = да, то в этом случае, перед преобразованием будет осуществлена подстановка параметров из результатов компоновки в тело контента.

Если Свойство ПреобразоватьКонтент, которое может быть определено в свойствах файла контента и в глобальных настройках не запрещают преобразование, контент будет преобразован в html. Если же преобразование запрещено – контент будет помещен в результаты компоновки в исходном виде, что позволяет манипулировать им во время вывода.

 

Создание темы (оформления)

Поскольку я не являюсь каким-либо специалистом в html, css etc, я просто позаимствовал тему по умолчанию Pico CMS. Файловая структура темы после распаковки имеет следующий вид:

Перенесем все папки и файлы, которые относятся к оформлению (css, js etc.) в нашу тему и создадим на основе файла index.twig макет страницы, а также процессор вывода.

Макет страницы

Исходный файл index.twig имеет следующий вид:

<!DOCTYPE html>
<html class="no-js">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

    <title>{% if meta.title %}{{ meta.title }} | {% endif %}{{ site_title }}</title>
    {% if meta.description %}
        <meta name="description" content="{{ meta.description|striptags }}" />
    {% endif %}{% if meta.robots %}
        <meta name="robots" content="{{ meta.robots }}" />
    {% endif %}

    {% if current_page %}
        <link rel="canonical" href="{{ current_page.url }}" />
    {% endif %}

    <link rel="stylesheet" href="{{ theme_url }}/css/style.css" type="text/css" />
    <link rel="stylesheet" href="{{ theme_url }}/css/droidsans.css" type="text/css" />
    <link rel="stylesheet" href="{{ theme_url }}/css/fontello.css" type="text/css" />
</head>
<body{% if config.theme_config.widescreen %} class="widescreen"{% endif %}>

    <div id="header">
        <div class="container">
            <a id="nav-toggle" title="Toggle Menu" role="button" aria-controls="nav" aria-expanded="false" tabindex="1">
                <span class="icon-menu" aria-hidden="true"></span>
                <span class="sr-only">Toggle Menu</span>
            </a>
            <h1>
                <a href="{{ "index"|link }}">{{ site_title }}</a>
            </h1>
            <div id="nav" role="region" tabindex="-1">
                <ul>
                    {% for page in pages if page.title and not page.hidden %}
                        {% set pageDepth = page.id|split('/')|length %}
                        {% if (pageDepth == 2) and (page.id ends with "/index") or (pageDepth == 1) %}
                            <li{% if page.id == current_page.id %} class="active"{% endif %}>
                                <a href="{{ page.url }}">{{ page.title }}</a>
                            </li>
                        {% endif %}
                    {% endfor %}
                </ul>
            </div>
        </div>
    </div>

    <div id="main">
        <div class="container">
            {{ content }}
        </div>
    </div>

    <div id="footer">
        <div class="container">
            <div class="social">
                {% for social in pages._meta.meta.social %}
                    <a href="{{ social.url }}" title="{{ social.title }}" role="button">
                        <span class="icon-{{ social.icon }}" aria-hidden="true"></span>
                        <span class="sr-only">{{ social.title }}</span>
                    </a>
                {% endfor %}
            </div>
            <p>
                <a href="/redirect.php?url=aHR0cDovL3BpY29jbXMub3JnLw==">Pico</a> was made by <a href="/redirect.php?url=aHR0cDovL2dpbGJlcnQucGVsbGVncm9tLm1l">Gilbert Pellegrom</a>
                and is maintained by <a href="/redirect.php?url=aHR0cHM6Ly9naXRodWIuY29tL3BpY29jbXMvUGljby9ncmFwaHMvY29udHJpYnV0b3Jz">The Pico Community</a>.
                Released under the <a href="/redirect.php?url=aHR0cHM6Ly9naXRodWIuY29tL3BpY29jbXMvUGljby9ibG9iL21hc3Rlci9MSUNFTlNFLm1k">MIT license</a>.
            </p>
        </div>
    </div>

    <script src="{{ theme_url }}/js/modernizr-3.3.1-custom.min.js" type="text/javascript"></script>
    <script src="{{ theme_url }}/js/utils.js" type="text/javascript"></script>
    <script src="{{ theme_url }}/js/pico.js" type="text/javascript"></script>

</body>
</html>

Как можно увидеть, файл представляет собой страницу html со вставками кода шаблонизатора twig. Создадим на его основе макет с областями, аналогично тому, как это сделано в 1С:Предприятие или Crystal Reports. В качестве разделителей областей будем использовать комментарии html.

После редактирования, файл макета будет иметь следующий вид:

<!--Начало-->
<!DOCTYPE html>
<html class="no-js">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

    <title>{{Заголовок}}</title>
    <meta name="description" content="{{Описание}}" />
 <!---
    {% if current_page %}
        <link rel="canonical" href="{ current_page.url }}" />
    {% endif %}
-->
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/css/style.css" type="text/css" />
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/css/droidsans.css" type="text/css" />
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/css/fontello.css" type="text/css" />
    
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/highlight/github.css">
    <script src="{{КаталогТем}}{{ТекущаяТема}}/highlight/highlight.pack.js"></script>
    <script>hljs.initHighlightingOnLoad();</script>
</head>
<!---<body{% if config.theme_config.widescreen %} class="widescreen"{% endif %}>-->
<body>
    <div id="header">
        <div class="container">
            <a id="nav-toggle" title="Toggle Menu" role="button" aria-controls="nav" aria-expanded="false" tabindex="1">
                <span class="icon-menu" aria-hidden="true"></span>
                <span class="sr-only">Toggle Menu</span>
            </a>
            <h1>
                <a href="">{{ИмяСайта}}</a>
            </h1>
            <div id="nav" role="region" tabindex="-1">
                <ul>
					<!--ПунктМеню-->
								<li{{ОформлениеПунктаМеню}}>
                                <a href="{{url}}">{{Заголовок}}</a>
                            </li>
					<!--ПунктМеню-->
					<!--Контент-->
                </ul>
            </div>
        </div>
    </div>

    <div id="main">
        <div class="container">
            {{Контент}}
        </div>
    </div>

    <div id="footer">
        <div class="container">
			<!--
            <div class="social">
                {% for social in pages._meta.meta.social %}
                    <a href="{ social.url }}" title="{ social.title }}" role="button">
                        <span class="icon-{ social.icon }}" aria-hidden="true"></span>
                        <span class="sr-only">{ social.title }}</span>
                    </a>
                {% endfor %}
            </div>
				-->
                <p>
                    Создано на основе <a href="/redirect.php?url=aHR0cDovL3BpY29jbXMub3JnLw==">Pico</a> в среде <a href="/redirect.php?url=aHR0cDovLzFjLnJ1Lw==">1С:Предприятие</a>
                    , выполняется на <a href="/redirect.php?url=aHR0cDovL29zY3JpcHQuaW8=">OneScript</a>.
                </p>
        </div>
    </div>

    <script src="{{КаталогТем}}{{ТекущаяТема}}/js/modernizr-3.3.1-custom.min.js" type="text/javascript"></script>
    <script src="{{КаталогТем}}{{ТекущаяТема}}/js/utils.js" type="text/javascript"></script>
    <script src="{{КаталогТем}}{{ТекущаяТема}}/js/pico.js" type="text/javascript"></script>

</body>
</html>
<!--Контент-->

Сохраним его с именем index.html в папку темы.

Вывод страницы

На основе анализа кода шаблонизатора, создадим http-сервис с именем index.os, который будет формировать страницу на основе результатов компоновки. Исходный код сервиса представлен ниже:


Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
	
	ПараметрыКомпоновки = Новый Соответствие;
	ПараметрыКомпоновки.Вставить("Запрос", Запрос);
	РезультатКомпоновки = ПроцессорКомпоновкиДанных.ПолучитьРезультатКомпоновкиДанных(ПараметрыКомпоновки);
	
	Ответ = РезультатКомпоновки["Ответ"];
	
	Если Не Ответ.КодСостояния = 200 Тогда
	
		Возврат Ответ;
	
	КонецЕсли; 
	
	Макет = РезультатКомпоновки["Макет"];
	ПараметрыВывода = РезультатКомпоновки["ПараметрыВывода"];
	Текст = "";
	
	// Формируем область до меню
	Область = Макеты.ПолучитьОбласть(Макет, "<!--Начало-->", "<!--ПунктМеню-->");
	Текст = Макеты.ЗаполнитьПараметры(Область.Текст, ПараметрыВывода);
	
	// Формируем меню
	Меню = РезультатКомпоновки.Получить("Меню");
	Страница = РезультатКомпоновки["Страница"];
	
	Если Не Меню = Неопределено Тогда
		
		Для каждого ПунктМеню Из Меню Цикл
		
			Область = Макеты.ПолучитьОбласть(Макет, "<!--ПунктМеню-->", "<!--ПунктМеню-->");
			
			Если Не ПунктМеню.Получить("Каталог") = Неопределено И СтрНачинаетсяС(Страница["Идентификатор"], ПунктМеню.Получить("Каталог")) Тогда
				ПунктМеню.Вставить("ОформлениеПунктаМеню", " class=""active"" ");
			КонецЕсли;
			
			Текст = Текст + Макеты.ЗаполнитьПараметры(Область.Текст, ПунктМеню);
		
		КонецЦикла; 
		
	КонецЕсли;
	
	//// Вставляем контент
	Область = Макеты.ПолучитьОбласть(Макет, "<!--Контент-->", "<!--Контент-->");
	Текст = Текст + Макеты.ЗаполнитьПараметры(Область.Текст, ПараметрыВывода);
	Текст = Макеты.УдалитьНезаполненныеПараметры(Текст);
	Ответ.УстановитьТелоИзСтроки(Текст);
	
	Возврат Ответ;
	
КонецФункции

 

Добавляем статьи

К сожалению, тема по умолчанию не содержит каких-либо функций, позволяющих отображать контент с динамической навигацией, поэтому добавим его самостоятельно.

Для этого, на основе предыдущего, создадим макет примерно следующего вида:

<!--Начало-->
<!DOCTYPE html>
<html class="no-js">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

    <title>{{Заголовок}}</title>
    <meta name="description" content="{{Описание}}" />
 <!---
    {% if current_page %}
        <link rel="canonical" href="{ current_page.url }}" />
    {% endif %}
-->
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/css/style.css" type="text/css" />
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/css/droidsans.css" type="text/css" />
    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/css/fontello.css" type="text/css" />

    <link rel="stylesheet" href="{{КаталогТем}}{{ТекущаяТема}}/highlight/github.css">
    <script src="{{КаталогТем}}{{ТекущаяТема}}/highlight/highlight.pack.js"></script>
    <script>hljs.initHighlightingOnLoad();</script>

</head>
<!---<body{% if config.theme_config.widescreen %} class="widescreen"{% endif %}>-->
<body>
    <div id="header">
        <div class="container">
            <a id="nav-toggle" title="Toggle Menu" role="button" aria-controls="nav" aria-expanded="false" tabindex="1">
                <span class="icon-menu" aria-hidden="true"></span>
                <span class="sr-only">Toggle Menu</span>
            </a>
            <h1>
                <a href="">{{ИмяСайта}}</a>
            </h1>
            <div id="nav" role="region" tabindex="-1">
                <ul>
                    <!--ПунктМеню-->
                    <li{{ОформлениеПунктаМеню}}>
                        <a href="{{url}}">{{Заголовок}}</a>
                        </li>
                        <!--ПунктМеню-->
                        <!--ЗавершениеЗаголовка-->
                </ul>
            </div>
        </div>
    </div>
    <div style="width=100%; padding-left: 2em; padding-top: 1em;">
    <!--ЗавершениеЗаголовка-->
    <!--НавигацияПапки-->
    <a href="{{url}}">{{Заголовок}}</a>
    <!--НавигацияПапки-->
    <!--ПередНавигацияСтраница-->
    </div>
	<div id="main">
<aside style="float: left;padding-left: 2rem; min-width: 32em;">
<!--ПередНавигацияСтраница-->
<!--НавигацияСтраница-->
 <a href="{{url}}">{{Заголовок}}</a><br>
<!--НавигацияСтраница-->
<!--Контент-->
</aside>
		<div class="container">
                	{{Контент}}
        	</div>
	</div>
        <div id="footer">
            <div class="container">
                <!--
                <div class="social">
                    {% for social in pages._meta.meta.social %}
                        <a href="{ social.url }}" title="{ social.title }}" role="button">
                            <span class="icon-{ social.icon }}" aria-hidden="true"></span>
                            <span class="sr-only">{ social.title }}</span>
                        </a>
                    {% endfor %}
                </div>
                    -->
                <p>
                    Создано на основе <a href="/redirect.php?url=aHR0cDovL3BpY29jbXMub3JnLw==">Pico</a> в среде <a href="/redirect.php?url=aHR0cDovLzFjLnJ1Lw==">1С:Предприятие</a>
                    , выполняется на <a href="/redirect.php?url=aHR0cDovL29zY3JpcHQuaW8=">OneScript</a>.
                </p>
            </div>
        </div>
        <script src="{{КаталогТем}}{{ТекущаяТема}}/js/modernizr-3.3.1-custom.min.js" type="text/javascript"></script>
        <script src="{{КаталогТем}}{{ТекущаяТема}}/js/utils.js" type="text/javascript"></script>
        <script src="{{КаталогТем}}{{ТекущаяТема}}/js/pico.js" type="text/javascript"></script>
</body>
</html>
<!--Контент-->

а также соответствующий ему http-сервис с именем article.os


Функция ОбработкаВызоваHTTPСервиса(Запрос) Экспорт
	
	ПараметрыКомпоновки = Новый Соответствие;
	ПараметрыКомпоновки.Вставить("Запрос", Запрос);
	РезультатКомпоновки = ПроцессорКомпоновкиДанных.ПолучитьРезультатКомпоновкиДанных(ПараметрыКомпоновки);
	
	Ответ = РезультатКомпоновки["Ответ"];
	
	Если Не Ответ.КодСостояния = 200 Тогда
	
		Возврат Ответ;
	
	КонецЕсли; 
	
	Макет = РезультатКомпоновки["Макет"];
	ПараметрыВывода = РезультатКомпоновки["ПараметрыВывода"];
	Текст = "";
	
	// Формируем область до меню
	Область = Макеты.ПолучитьОбласть(Макет, "<!--Начало-->", "<!--ПунктМеню-->");
	Текст = Макеты.ЗаполнитьПараметры(Область.Текст, ПараметрыВывода);
	
	// Формируем меню
	Меню = РезультатКомпоновки.Получить("Меню");
	Страница = РезультатКомпоновки["Страница"];
	
	Если Не Меню = Неопределено Тогда
		
		Для каждого ПунктМеню Из Меню Цикл
		
			Область = Макеты.ПолучитьОбласть(Макет, "<!--ПунктМеню-->", "<!--ПунктМеню-->");
			
			Если Не ПунктМеню.Получить("Каталог") = Неопределено И СтрНачинаетсяС(Страница["Идентификатор"], ПунктМеню.Получить("Каталог")) Тогда
				ПунктМеню.Вставить("ОформлениеПунктаМеню", " class=""active"" ");
			КонецЕсли;
			
			Текст = Текст + Макеты.ЗаполнитьПараметры(Область.Текст, ПунктМеню);
		
		КонецЦикла; 
		
	КонецЕсли;
	
	// Вставляем область после меню
  	Область = Макеты.ПолучитьОбласть(Макет, "<!--ЗавершениеЗаголовка-->", "<!--ЗавершениеЗаголовка-->");
	Текст = Текст + Область.Текст;

	// Формируем навигацию папок
	Область = Макеты.ПолучитьОбласть(Макет, "<!--НавигацияПапки-->", "<!--НавигацияПапки-->");
	СтраницыПапки = ПолучитьСтраницыПапок(РезультатКомпоновки);
	ТекстНавигацияПапки = "";
	Количество = СтраницыПапки.Количество();
	Индекс = 0;
	Для Индекс = 0 По Количество - 1 Цикл
	
		Если Не Индекс = Количество - 1 Тогда
			СтраницыПапки[Индекс].Заголовок = СтраницыПапки[Индекс].Заголовок + " > ";
		КонецЕсли;
		
		ТекстНавигацияПапки = ТекстНавигацияПапки + Макеты.ЗаполнитьПараметры(Область.Текст, СтраницыПапки[Индекс]);	
	
	КонецЦикла; 
	
	Текст = Текст + ТекстНавигацияПапки;
	
	// Формируем навигацию страниц и подпапок текущей папки
	Область = Макеты.ПолучитьОбласть(Макет, "<!--ПередНавигацияСтраница-->", "<!--ПередНавигацияСтраница-->");
	Текст = Текст + Область.Текст;
	
	Область = Макеты.ПолучитьОбласть(Макет, "<!--НавигацияСтраница-->", "<!--НавигацияСтраница-->");
	МассивСтраниц = ПолучитьСтраницыТекущейПапки(РезультатКомпоновки);
	МассивСтраниц = ОтсортироватьСтраницыПоЗаголовку(МассивСтраниц);
	
	Для каждого СтраницаНавигация Из МассивСтраниц Цикл
	
		Если СтраницаНавигация.Идентификатор = Страница["Идентификатор"] Тогда
			СтраницаНавигация.Заголовок = "<b>" + СтраницаНавигация.Заголовок + "</b>";
		КонецЕсли;
		
		Текст = Текст + Макеты.ЗаполнитьПараметры(Область.Текст, СтраницаНавигация);
	
	КонецЦикла; 
	
	//// Вставляем контент
	Область = Макеты.ПолучитьОбласть(Макет, "<!--Контент-->", "<!--Контент-->");
	Текст = Текст + Макеты.ЗаполнитьПараметры(Область.Текст, ПараметрыВывода);
	Текст = Макеты.УдалитьНезаполненныеПараметры(Текст);
	Ответ.УстановитьТелоИзСтроки(Текст);
	
	Возврат Ответ;
	
КонецФункции

Функция ПолучитьСтраницыПапок(РезультатКомпоновки)
	
	КонфигурацияCMS = РезультатКомпоновки["Конфигурация"];
	Страница = РезультатКомпоновки["Страница"];
	Идентификатор = Страница["Идентификатор"];
	// Получаем страницу default для каждой подпапки
	НомерСимвола = 0;
	НомерВхождения = 1;
	НомерСимвола = СтрНайти(Идентификатор, "/",,НомерВхождения);
	Процессор = YamlПроцессор.НовыйYamlПроцессор();
	МассивСтраниц = Новый Массив;
	
	Пока Не НомерСимвола = 0 Цикл
	
		ИдентификаторПоУмолчанию = Лев(Идентификатор, НомерСимвола) + КонфигурацияCMS["СтраницаПоУмолчанию"];
		ФизическийПутьКСтранице = ПроцессорКомпоновкиДанных.ПолучитьФизическийПутьИзВиртуального(
		КонфигурацияCMS["КаталогКонтента"] + ИдентификаторПоУмолчанию) + 
			КонфигурацияCMS["РасширениеФайлаКонтента"];
		СтраницаПапка = ПроцессорКомпоновкиДанных.ЗагрузитьСтраницу(ФизическийПутьКСтранице, Процессор);
		
		СтруктураСтраница = Новый Структура;
		СтруктураСтраница.Вставить("url", "article.os?p=" + ИдентификаторПоУмолчанию);
		СтруктураСтраница.Вставить("Заголовок", СтраницаПапка["Заголовок"]);
		СтруктураСтраница.Вставить("Идентификатор", ИдентификаторПоУмолчанию);
		МассивСтраниц.Добавить(СтруктураСтраница);
		
		НомерВхождения = НомерВхождения + 1;
		НомерСимвола = СтрНайти(Идентификатор, "/",,,НомерВхождения);
		
	
	КонецЦикла;
	
	Индекс = МассивСтраниц.Количество() - 1;
	
	Если Не МассивСтраниц[Индекс].Идентификатор = Идентификатор Тогда
		СтруктураСтраница = Новый Структура;
		СтруктураСтраница.Вставить("url", "article.os?p=" + Идентификатор);
		СтруктураСтраница.Вставить("Заголовок", Страница["Заголовок"]);
		СтруктураСтраница.Вставить("Идентификатор", Идентификатор);
		МассивСтраниц.Добавить(СтруктураСтраница);
	КонецЕсли;		
	
	Возврат МассивСтраниц;
	
КонецФункции

Функция ПолучитьСтраницыТекущейПапки(РезультатКомпоновки)
	
	КонфигурацияCMS = РезультатКомпоновки["Конфигурация"];
	Страница = РезультатКомпоновки["Страница"];
	Идентификатор = Страница["Идентификатор"];
	ВиртуальныйКаталог = Лев(Идентификатор, СтрНайти(Идентификатор, "/", НаправлениеПоиска.СКонца,,1));
	Процессор = YamlПроцессор.НовыйYamlПроцессор();
	МассивСтраниц = Новый Массив;
	
	ФизическийПутьКСтранице = ПроцессорКомпоновкиДанных.ПолучитьФизическийПутьИзВиртуального(
	    КонфигурацияCMS["КаталогКонтента"] + 
		Страница["Идентификатор"] + 
		КонфигурацияCMS["РасширениеФайлаКонтента"]);
	Файл = Новый Файл(ФизическийПутьКСтранице);
	Файлы = НайтиФайлы(Файл.Путь, "*.*", Ложь);
	
	Для каждого Файл Из Файлы Цикл
	
		Если Файл.ЭтоКаталог() Тогда
		
			
			ФайлСтраницы = НайтиФайлы(Файл.ПолноеИмя, КонфигурацияCMS["СтраницаПоУмолчанию"] + КонфигурацияCMS["РасширениеФайлаКонтента"], Ложь); 
			
			Если ФайлСтраницы.Количество() = 0 Тогда
				Продолжить;
			КонецЕсли;
			
			ТекСтраница = ПроцессорКомпоновкиДанных.ЗагрузитьСтраницу(ФайлСтраницы[0].ПолноеИмя, Процессор);
			
			СтруктураСтраница = Новый Структура;
			СтруктураСтраница.Вставить("url", "article.os?p=" + ВиртуальныйКаталог + Файл.Имя + "/" + КонфигурацияCMS["СтраницаПоУмолчанию"]);
			СтруктураСтраница.Вставить("Идентификатор", ВиртуальныйКаталог + Файл.Имя + "/" + КонфигурацияCMS["СтраницаПоУмолчанию"]);
			СтруктураСтраница.Вставить("Заголовок", ТекСтраница["Заголовок"]);
			МассивСтраниц.Добавить(СтруктураСтраница);
			
		ИначеЕсли Не Файл.Расширение = КонфигурацияCMS["РасширениеФайлаКонтента"] Тогда
			
			Продолжить;
			
		Иначе
			
			ТекСтраница = ПроцессорКомпоновкиДанных.ЗагрузитьСтраницу(Файл.ПолноеИмя, Процессор);
			СтруктураСтраница = Новый Структура;
			СтруктураСтраница.Вставить("url", "article.os?p=" + ВиртуальныйКаталог + Файл.ИмяБезРасширения);
			СтруктураСтраница.Вставить("Идентификатор", ВиртуальныйКаталог + Файл.ИмяБезРасширения);  
			СтруктураСтраница.Вставить("Заголовок", ТекСтраница["Заголовок"]);
			МассивСтраниц.Добавить(СтруктураСтраница);
		
		КонецЕсли; 	
	
	КонецЦикла;
	
	Возврат МассивСтраниц;
	
КонецФункции

Функция ОтсортироватьСтраницыПоЗаголовку(МассивСтраниц)
	
	// Страниц не 100500, сортируем пузырьком :)
	// //sale.itcity.ru/public/204320/
	
	Для i = 0 По МассивСтраниц.ВГраница() Цикл
		
		Для j = 0 ПО МассивСтраниц.Вграница() - i - 1 Цикл
			
			Если МассивСтраниц[j].Заголовок > МассивСтраниц[j + 1].Заголовок Тогда
				
				Замена = МассивСтраниц[j];
            	МассивСтраниц[j] = МассивСтраниц[j + 1];
            	МассивСтраниц[j + 1] = Замена;
				
			КонецЕсли;            
			
		КонецЦикла;        
		
	КонецЦикла;    
	
	Возврат МассивСтраниц;    
	
КонецФункции

Ну вот в общем-то и все. Наша тема готова. Формируем приложение способом, описанным в предыдущей статье и размещаем его на web-сервере.

Заключение

Вот таким вот нехитрым способом, мы получили web-приложение OneScript, которое Вы можете использовать для создания своих собственных сайтов, которые могут быть посвящены к примеру описанию созданной Вами конфигурации или чему-либо еще.  Любая критика, предложения, замечания etc. приветствуются.

P.S.

Если Вы хорошо (в отличие от автора) владеете html, css, javascript, считаете web-приложжения OneScript или OneScript  или все вместе — вредными, никчемными технологиями или вчерашним днем, и имеете желание и возможность адаптировать или создать тему etc. – Welcome! 

has been added to your cart:
Оформление заказа