====== Короткий посібник із розробки модулів для Ubilling ====== Писати додаткові модулі для Ubilling дуже просто, розгляньмо процес написання найпростішого модуля на прикладі модуля, що показує всіх користувачів з їхніми ПІБ та адресами у вигляді гарної сортувальної таблички. Типовий модуль Ubilling розміщується в окремому підкаталозі **/modules/general/** і складається з двох файлів: **index.php** і **module.php**. Перший із них є власне модулем із його виконуваним кодом, другий же - описом модуля для вбудованого диспатчера. Давайте припустимо, що наш модуль називатиметься samplemod і таким чином складатиметься з двох файлів:\\ \\ {{:samplemod.png?|}} \\ Давайте детально розберемо що-ж знаходиться в цих двох містичних файликах.\\ registerModule($module, 'main', 'Sample module', 'Sample developer', array('SAMPLE' => __('right for access sample module'))); Містить у собі стандартний набір, який описує те, що модуль має клас **main** (тобто може розміщуватися в центральному блоці контенту за замовчуванням), зветься **Sample module**, написаний розробником на ім'я **Sample developer** і під час свого довантаження породжує право **SAMPLE**, за яким згодом ми розмежовуватимемо доступ до цього модуля. Зверніть увагу на конструкцію __('Рядок англійською') використану в цьому прикладі в ролі опису права на модуль. Функція повертатиме локалізований рядок відносно поточної мови, якщо він знайдений у словниковому файлі. Власне локалізація в Ubilling є подібною до gettext.\\ Все, з файлом опису модуля розібралися, поїхали далі.\\ \\ \\ $eachlogin) { $userlogin=$eachlogin['login']; $userip=$eachlogin['IP']; //Збираючи для кожного рядка таблички $tablecells=wf_TableCell($userlogin); $tablecells.=wf_TableCell($userip); $tablecells.=wf_TableCell(@$allrealnames[$userlogin]); $tablecells.=wf_TableCell(@$alladdress[ $userlogin]); $tablerows.=wf_TableRow($tablecells, 'row3'); } // оголошуємо як результат табличку з попередньо зібраними рядками // а також шириною в 100%, бордюром в 0 і класом sotrable $result=wf_TableBody($tablerows, '100%', '0', 'sortable'); } else { //якщо немає натякаємо що їх немає $result=__('No users found'); } // виводимо наш результат за допомогою функції show_window show_window(__('Sample module'), $result); } else { // якщо ні - вивалюємо на нього помилку про відмову в доступі show_error(__('You cant control this module')); } Доступ до нашого модуля ми можемо отримати за допомогою посилання **?module=samplemod**, в результаті чого ми повинні побачити приблизно таке:\\ {{:samplemod2.png?|}} Як бачите, замість рядків **Real Name** і **Address** у нас автоматично підставилися їхні мовно-залежні заміни зі словника поточної локалізації. Не перекладеним залишився один рядок **Sample module**, про який рушій локалізації поки що нічого не знає. Давайте перекладемо його скажімо російською мовою для початку.\\\ Зробити це досить просто - потрібно створити файл **/languages/ukrainian/samplemod.php** такого змісту: Після чого ми побачимо як рядок локалізувався сам по собі в нашому модулі:\\ {{:samplemod3.png?|}} \\ З нестандартних речей, чужих чистому PHP, ми використовували тільки функції бібліотеки** api.astral** для збирання таблиць за допомогою **wf_**, що не є обов'язковою, просто виглядає красивіше та читабельніше, а також результат крізь **show_window($title,$data)** замість **print()**, що вже є обов'язковою для роботи шаблонізатора фреймворка.\\ А що робити, якщо нашому модулю потрібна якась бібліотека/клас потрібна йому одному? Варіантів є кілька. Перший з них менш красивий, але більш портабельний - вставити її прямо всередину нашого модуля в **modules/general/samplemod/index.php**. Другий - просто покласти цю бібліотеку в директорію **modules/engine/**. У цьому разі вона буде довантажена до виконання нашого модуля. Хорошим тоном у цьому випадку буде переконатися, що під час свого завантаження вона не буде виробляти якогось виводу, і друге - постарайтеся уникати створення великих об'єктів у цій бібліотеці, щоб уникнути деградації продуктивності загалом. Що мається на увазі під цим? Наведемо на прикладі бібліотеки, яка описує якийсь клас SampleClass і знаходиться в **modules/engine/sampleClass.php** loadData(); } protected function loadData() { $this->data=...... } } $sampleObject=new SampleClass(); // ось цього тут бути не повинно, місце йому в modules/general/samplemod/index.php ?> Також чудовим (**і рекомендованим!**) способом може бути розміщення вашої бібліотеки в **api/libs/**, звідки її може підхопити автозавантажувач, якщо ім'я класу створюваного об'єкта відповідає імені бібліотеки з префіксом "**api.**" у лаверкейсі. Для прикладу вище це має бути файл **api/libs/api.sampleclass.php**. Під час створення об'єкта $sampleObject=new SampleClass(); цю бібліотеку буде автоматично завантажено, і вам взагалі нічого не потрібно для цього робити. ====== Розташування модуля на панелі задач ====== А як додаються модулі на панель завдань? Ну там з іконками, правами та опціями? А все так само дуже просто - розкладанням потрібних файликів у потрібні місця. Починаючи з релізу 0.8.0 цими місцями є директорія **config/taskbar.d/**, а точніше її підкаталоги. Припустимо, наш тестовий модуль є з нашої точки зору звітом. Також ми хочемо, щоб вмикався він за допомогою необов'язкової опції [[alteriniconf|alter.ini]] на ім'я SAMPLE_ENABLED. Разом кладемо файлик sample.ini в директорію **config/taskbar.d/reports/** ; Ідентифікатор модуля. Повинен бути як мінімум унікальним. ID="samplemod" ; Підпис іконки модуля - буде автоматично локалізовано поточною локаллю. NAME="Sample module" ; URL нашого модуля. Не повірите - буде клікабельним :) URL="?module=samplemod" ; Іконка модуля. Спочатку намагається знайтися в директорії taskbar поточного скіна, якщо не існує - у глобальному skins/taskbar. ICON="goat.gif" ; Право, яке вимагає модуль. Ну як мінімум право, яке потрібне для показу іконки. NEED_RIGHT="SAMPLE" ; Опція конфіга alter.ini необхідна для показу іконки таскбару. NEED_OPTION="SAMPLE_ENABLED" ; Цей параметр сигналізує, що опція є необов'язковою. ; Якщо видалити цей параметр - панель завдань буде кричати про відсутню опцію. UNIMPORTANT=1 ; Тип елемента. У нашому випадку це icon - типова іконка з підписом. Є ще widget але про це пізніше. TYPE="icon" ; Ця необов'язкова опція описує те буде відкриватись посилання на елемент. ; Може бути відсутньою чи порожньою або приймати значення _blank, _self, _parent, _top чи ім'я iframe. ; детальніше тут: https://www.w3schools.com/tags/att_a_target.asp LINK_TARGET= та отримуємо результат очікуваний результат {{:undefined:samplemod4.png|}} А що ж із віджетами, і як вони взагалі виглядають? А ось якось так [[taskbarwidgets|так]]. ====== Приклад використання dataTable ====== // jQuery dataTable construction and rendering $myUrl = '?module=testing'; $callbackRoute = 'ajaxlist'; $columns = array('Якась колонка', 'Друга колонка'); $dataTable = wf_JqDtLoader($columns, $myUrl . '&' . $callbackRoute . '=true', false, __('Data'), 50); show_window(__('Title'), $dataTable); // JSON dataTable data output on some callback route if (ubRouting::checkGet($callbackRoute)) { $json = new wf_JqDtHelper(); $json->addRow(array('якісь дані', 'інші дані')); $json->addRow(array('це в першій колонці', 'також дані')); $json->getJson(); } результат {{:jqdt.png|}} ====== Розташування модулю як плагіну профілю користувача ====== Формат plugins.ini дуже близький до формату опису елементу панелі задач. Тільки імена опцій в лаверкейсі. [унікальний ідентифікатор модуля] name = "Ім'я модулю" icon = "ім'я файлу іконки модулю" need_right=Право яке необхідне модулю need_option=Опція яка необхідна ;Наступна опція не є обов`язковою. Просто вказує те де буде відкрито посилання. ;детальніше тут: https://www.w3schools.com/tags/att_a_target.asp ;link_target=_self також модуль може бути описаним у оверлеї "чорної магії" в bmagic.ini в тому ж форматі.