JavaScript

Модули JavaScript

Разработчики должны использовать нативные для браузера модули ECMAScript для написания кода JavaScript в Elgg.

Здесь мы опишем создание и импорт этих модулей в Elgg.

Выполнение модуля на текущей странице

Указать Elgg загрузить существующий модуль на текущей странице просто:

<?php
elgg_import_esm('myplugin/say_hello');

На стороне клиента это асинхронно загрузит модуль, загрузит любые зависимости и выполнит код модуля, если он есть.

Определение модуля

Файлы с расширением «.mjs» автоматически добавляются в importmap, чтобы их можно было импортировать на основе имени представления.

Например, если у нас есть файл в «views/default/myplugin/say_hello.mjs», мы можем импортировать из PHP с помощью elgg_import_esm('myplugin/say_hello') или из JavaScript с помощью оператора import import 'myplugin/say_hello'; или по требованию с помощью функции import().

Если ваши модули не имеют расширения «.mjs», например, когда они поступают из зависимости, вам может потребоваться зарегистрировать их в importmap. После регистрации их можно импортировать под зарегистрированным именем.

<?php
elgg_register_esm('myplugin/say_hello', elgg_get_simplecache_url('external/dependency/modulename.js'));

Передача настроек в модули

События elgg.data

Модуль elgg предоставляет объект elgg.data, который заполняется из двух событий на стороне сервера:

  • elgg.data, page: Фильтрует ассоциативный массив данных, передаваемых клиенту.

Передадим некоторые данные в модуль:

<?php

function myplugin_config_page(\Elgg\Event $event) {
    $value = $event->getValue();
    $value['myplugin']['api'] = elgg_get_site_url() . 'myplugin-api';
    $value['myplugin']['key'] = 'none';

    $user = elgg_get_logged_in_user_entity();
    if ($user) {
            $value['myplugin']['key'] = $user->myplugin_api_key;
    }

    return $value;
}

elgg_register_event_handler('elgg.data', 'page', 'myplugin_config_page');
define(['elgg'], function(elgg) {
    var api = elgg.data.myplugin.api;
    var key = elgg.data.myplugin.key; // "none" or a user's key

    // ...
});

Установка URL модуля

У вас может быть скрипт AMD вне ваших представлений, который вы хотите сделать доступным как модуль.

Лучший способ сделать это — настроить путь к файлу с помощью секции views файла elgg-plugin.php в корне вашего плагина:

<?php // elgg-plugin.php
return [
    'views' => [
            'default' => [
                'underscore.js' => 'vendor/npm-asset/underscore/underscore.min.js',
            ],
    ],
];

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

<?php // elgg-plugin.php
return [
    'views' => [
            'default' => [
                'underscore.js' => __DIR__ . '/node_modules/underscore/underscore.min.js',
            ],
    ],
];

Вот и всё! Теперь Elgg будет загружать этот файл всякий раз, когда запрашивается модуль «underscore».

Модули, предоставляемые с Elgg

Модуль elgg

elgg.normalize_url()

Нормализует URL относительно корня elgg:

// "http://localhost/elgg/blog"
elgg.normalize_url('/blog');

elgg.forward()

Перенаправляет на новую страницу.

elgg.forward('/blog');

Эта функция автоматически нормализует URL.

elgg.parse_url()

Разбирает URL на составные части:

// returns {
//   fragment: "fragment",
//   host: "community.elgg.org",
//   path: "/file.php",
//   query: "arg=val"
// }
elgg.parse_url('http://community.elgg.org/file.php?arg=val#fragment');

elgg.get_logged_in_user_guid()

Возвращает guid авторизованного пользователя.

elgg.is_logged_in()

True, если пользователь авторизован.

elgg.is_admin_logged_in()

True, если пользователь авторизован и является администратором.

В объекте elgg установлено несколько значений конфигурации:

// The root of the website.
elgg.config.wwwroot;
// The default site language.
elgg.config.language;
// The Elgg release (X.Y.Z).
elgg.config.release;

Модуль elgg/Ajax

См. страницу Ajax для подробностей.

Модуль elgg/hooks

Модуль elgg/hooks можно использовать для взаимодействия плагинов друг с другом.

Перевод текста интерфейса

define(['elgg/hooks'], function (hooks) {
    hooks.register('my_plugin:filter', 'value', handler, priority);

    var result = hooks.trigger('my_plugin:filter', 'value', {}, 'default');

Модуль elgg/i18n

Модуль elgg/i18n можно использовать для использования переводов.

Перевод текста интерфейса

define(['elgg/i18n'], function (i18n) {
    i18n.echo('example:text', ['arg1']);
});

Модуль elgg/system_messages

Модуль elgg/system_messages можно использовать для показа системных сообщений пользователю.

define(['elgg/system_messages'], function (system_messages) {
    system_messages.success('Your success message');

    system_messages.error('Your error message');

    system_messages.clear();
});

Модуль elgg/security

Модуль elgg/security можно использовать для добавления токена безопасности к объекту, URL или строке запроса:

     define(['elgg/security'], function (security) {
    // returns {
        //   __elgg_token: "1468dc44c5b437f34423e2d55acfdd87",
        //   __elgg_ts: 1328143779,
        //   other: "data"
        // }
        security.addToken({'other': 'data'});

        // returns: "action/add?__elgg_ts=1328144079&__elgg_token=55fd9c2d7f5075d11e722358afd5fde2"
        security.addToken("action/add");

        // returns "?arg=val&__elgg_ts=1328144079&__elgg_token=55fd9c2d7f5075d11e722358afd5fde2"
        security.addToken("?arg=val");
});

Модуль elgg/spinner

Модуль elgg/spinner можно использовать для создания индикатора загрузки, закреплённого в верхней части окна. Это можно использовать для предоставления пользователям обратной связи о том, что система выполняет задачу, занимающую больше времени. Использование функций ajax из elgg/Ajax сделает это по умолчанию. Вы также можете использовать его в своём коде.

define(['elgg/spinner'], function (spinner) {
    spinner.start();
    // your code
    spinner.stop();
});

Модуль elgg/popup

Модуль elgg/popup можно использовать для отображения наложения, позиционированного относительно его якоря (триггера).

Модуль elgg/popup автоматически загружается для контента, отрисованного с помощью output/url с атрибутом class='elgg-popup' и определения целевого модуля с атрибутом href (или data-href). Позиционирование модуля popup можно определить с помощью атрибута data-position элемента триггера.

echo elgg_format_element('div', [
   'class' => 'elgg-module-popup hidden',
   'id' => 'popup-module',
], 'Popup module content');

// Simple anchor
echo elgg_view('output/url', [
   'href' => '#popup-module',
   'text' => 'Show popup',
   'class' => 'elgg-popup',
]);

// Button with custom positioning of the popup
elgg_import_esm('elgg/popup');
echo elgg_format_element('button', [
   'class' => 'elgg-button elgg-button-submit elgg-popup',
   'text' => 'Show popup',
   'data-href' => '#popup-module',
   'data-position' => json_encode([
      'my' => 'center bottom',
      'at' => 'center top',
   ]),
]);

Модуль elgg/popup позволяет создавать более сложные элементы интерфейса/пользовательского опыта. Вы можете открывать и закрывать модули popup программно:

define(['jquery', 'elgg/popup'], function($, popup) {
   $(document).on('click', '.elgg-button-popup', function(e) {

      e.preventDefault();

      var $trigger = $(this);
      var $target = $('#my-target');
      var $close = $target.find('.close');

      popup.open($trigger, $target, {
         'collision': 'fit none'
      });

      $close.on('click', popup.close);
   });
});

Вы можете использовать хук плагина getOptions, ui.popup для манипуляции позицией popup перед его открытием. Вы можете использовать события jQuery open и close для манипуляции модулем popup после его открытия или закрытия.

define(['jquery', 'elgg/Ajax'], function($, Ajax) {

   $('#my-target').on('open', function() {
      var $module = $(this);
      var $trigger = $module.data('trigger');
      var ajax = new Ajax();

      ajax.view('my_module', {
         beforeSend: function() {
            $trigger.hide();
            $module.html('').addClass('elgg-ajax-loader');
         },
         success: function(output) {
            $module.removeClass('elgg-ajax-loader').html(output);
         }
      });
   }).on('close', function() {
      var $trigger = $(this).data('trigger');
      $trigger.show();
   });
});

Открытые модули popup всегда будут содержать следующие данные, к которым можно получить доступ через $.data():

  • trigger — элемент jQuery, используемый для запуска открытия модуля popup

  • position — объект, определяющий позицию модуля popup, который был передан в $.position()

По умолчанию элемент target будет добавлен в $('body'), тем самым изменяя иерархию DOM. Если вам нужно сохранить позицию DOM модуля popup, вы можете добавить класс .elgg-popup-inline к вашему триггеру.

Модуль elgg/widgets

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

import('elgg/widgets').then((widgets) => {
    widgets.default.init();
});

Модуль elgg/lightbox

Elgg распространяется с библиотекой jQuery Colorbox. Пожалуйста, перейдите на http://www.jacklmoore.com/colorbox для получения дополнительной информации о параметрах этого лайтбокса.

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

  • elgg-lightbox — загружает ресурс HTML

  • elgg-lightbox-photo — загружает ресурс изображения (следует использовать, чтобы избежать отображения необработанных байтов изображения вместо тега img)

  • elgg-lightbox-inline — отображает встроенный элемент HTML в лайтбоксе

  • elgg-lightbox-iframe — загружает ресурс в iframe

Вы можете применить параметры colorbox к отдельному элементу elgg-lightbox, установив атрибут data-colorbox-opts в объект настроек JSON.

echo elgg_view('output/url', [
   'text' => 'Open lightbox',
   'href' => 'ajax/view/my_view',
   'class' => 'elgg-lightbox',
   'data-colorbox-opts' => json_encode([
      'width' => '300px',
   ])
]);

Используйте хук плагина "getOptions", "ui.lightbox" для фильтрации параметров, передаваемых в $.colorbox() каждый раз, когда открывается лайтбокс.

Модуль AMD elgg/lightbox следует использовать для программного открытия и закрытия лайтбокса:

define(['elgg/lightbox', 'elgg/spinner'], function(lightbox, spinner) {
   lightbox.open({
      html: '<p>Hello world!</p>',
      onClosed: function() {
         lightbox.open({
            onLoad: spinner.start,
            onComplete: spinner.stop,
            photo: true,
            href: 'https://elgg.org/cache/1457904417/default/community_theme/graphics/logo.png',
         });
      }
   });
});

Для поддержки наборов галереи (через атрибут rel) вам нужно привязать colorbox напрямую к определённому селектору (обратите внимание, что это проигнорирует data-colorbox-opts на всех элементах в наборе):

import('elgg/lightbox').then((lightbox) => {
   var options = {
      photo: true,
      width: 500
   };
   lightbox.default.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies
});

При необходимости вы также можете изменить размер лайтбокса программно:

define(['elgg/lightbox'], function(lightbox) {
   lightbox.resize({
      width: '300px'
   });
});

Если вы хотите, чтобы ваш контент загружался модулем AMD elgg/Ajax, который автоматически загружает зависимости JS, вы можете передать опцию ajaxLoadWithDependencies

define(['elgg/lightbox'], function(lightbox) {
   lightbox.open({
      href: 'some/view/with/js/dependencies',
      ajaxLoadWithDependencies: true
   });
});

Модуль elgg/ckeditor

Этот модуль можно использовать для добавления редактора WYSIWYG к textarea (требуется включение плагина ckeditor). Обратите внимание, что WYSIWYG будет автоматически прикрепляться ко всем экземплярам .elgg-input-longtext.

import('elgg/ckeditor').then((elggCKEditor) => {
   elggCKEditor.default.bind('#my-text-area');

   // Toggle CKEditor
   elggCKEditor.default.toggle('#my-text-area');

   // Focus on CKEditor input
   elggCKEditor.default.focus('#my-text-area');
   // or
   $('#my-text-area').trigger('focus');

   // Reset CKEditor input
   elggCKEditor.default.reset('#my-text-area');
   // or
   $('#my-text-area').trigger('reset');

});

Компонент встроенных вкладок

Компонент встроенных вкладок запускает событие open каждый раз, когда вкладка открывается и, в случае вкладок ajax, завершает загрузку:

// Add custom animation to tab content
$(document).on('open', '.theme-sandbox-tab-callback', function() {
        $(this).find('a').text('Clicked!');
        $(this).data('target').hide().show('slide', {
                duration: 2000,
                direction: 'right',
                complete: function() {
                        alert('Thank you for clicking. We hope you enjoyed the show!');
                        $(this).css('display', ''); // .show() adds display property
                }
        });
});

Традиционные скрипты

Хотя мы настоятельно рекомендуем использовать модули AMD, и нет API Elgg для загрузки скриптов, вы можете зарегистрировать скрипты в обработчике событий для добавления элементов в ссылки заголовка;

elgg_register_event_handler('head', 'page', $callback);

Хуки

Движок JS имеет систему хуков, аналогичную событиям движка PHP: хуки запускаются, и плагины могут регистрировать функции для реакции или изменения информации.

Регистрация обработчиков хуков

Функции обработчиков регистрируются с помощью hooks.register(). Несколько обработчиков могут быть зарегистрированы для одного и того же хука.

define(['elgg/hooks'], function(hooks) {
    hooks.register('name', 'type', {handler}, {priority});
});

Функция обработчика

Обработчик получит 4 аргумента:

  • hook — имя хука

  • type — тип хука

  • params — объект или набор параметров, специфичных для хука

  • value — текущее значение

value будет передаваться через каждый хук. В зависимости от хука, обратные вызовы могут просто реагировать или изменять данные.

Запуск пользовательских хуков

Плагины могут запускать свои собственные хуки:

define(['elgg/hooks'], function(hooks) {
    hooks.trigger('name', 'type', {params}, "value");
});

Доступные хуки

init, system

Плагины должны регистрировать свои функции init для этого хука. Он запускается после загрузки JS Elgg и инициализации всех модулей загрузки плагинов.

getOptions, ui.popup

Этот хук запускается для всплывающих отображений ("rel"="popup") и позволяет настраивать параметры размещения.

getOptions, ui.lightbox

Этот хук можно использовать для фильтрации параметров, передаваемых в $.colorbox()

config, ckeditor

Это фильтрует объект конфигурации CKEditor. Зарегистрируйтесь для этого хука в модуле загрузки плагина. Значения по умолчанию можно увидеть в модуле elgg/ckeditor/config.

prepare, ckeditor

Этот хук можно использовать для декорирования глобального CKEDITOR. Вы можете использовать этот хук для регистрации новых плагинов CKEditor и добавления привязок событий.

ajax_request_data, *

Это фильтрует данные запроса, отправляемые модулем elgg/Ajax. См. Ajax для подробностей. Хук должен проверить, являются ли данные простым объектом или экземпляром FormData, чтобы добавить значения с использованием правильного API.

ajax_response_data, *

Это фильтрует данные ответа, возвращаемые пользователям модуля elgg/Ajax. См. Ajax для подробностей.

Сторонние ресурсы

Мы рекомендуем управлять сторонними скриптами и стилями с помощью Composer. composer.json Elgg настроен для установки зависимостей из репозиториев пакетов NPM или Yarn с помощью инструмента командной строки Composer. Конфигурация ядра устанавливает ресурсы из Asset Packagist (репозиторий, управляемый сообществом Yii).

В качестве альтернативы вы можете установить fxp/composer-asset-plugin глобально для достижения тех же результатов, но установка и обновление занимают гораздо больше времени.

Например, чтобы включить jQuery, вы можете выполнить следующие команды Composer:

composer require npm-asset/jquery:~2.0

Если вы используете starter-project или подтягиваете Elgg как зависимость composer через пользовательский проект composer, обновите ваш composer.json следующей конфигурацией:

{
    "repositories": [
        {
            "type": "composer",
            "url": "https://asset-packagist.org"
        }
    ],
        "config": {
        "fxp-asset": {
            "enabled": false
        }
    },
}

Дополнительную информацию можно найти на сайте Asset Packagist.