Archive for the ‘Modul’ Category

A WYSIWYG editorok lényege, hogy a felhasználó HTML tudás nélkül is tudjon webes felületen formázni. Ezt úgy érjük el, hogy a html szöveget tartalmazó textarea-ra egy JavaScript szerkesztőfelületet adunk, ami a begépelt és formázott szöveget HTML kódokká alakítja át.

Drupal alá is létezik sok közkedvelt WYSIWYG editor modul, pl: FCK Editor vagy a TinyMCE Editor, melyek mindig előkelő helyen vannak a leggyakrabban letöltött Drupal modulok között.

Nekem a kedvencem mégis a Wysiwyg API modul, mégpedig azért, mert egy alapvető problémát old meg: a beviteli formák összeütközése a WYSIWYG editorral a beviteli forma szűrői miatt. Ez röviden annyit takar, hogy a többi WYSIWYG editor jogosultsághoz van rendelve, tehát ha egy felhasználónak megvan a joga az editorhoz akkor használhatja, de ha kiválasztja Filetred HTML beviteli formát, amelyben a sortörések, url-ek stb. szűrve vannak, akkor az eléggé össze fog akadni a WYSIWYG editorral. Ilyenkor ugyebár a felhasználó boldogan formázza a szöveget, majd elmenti a Drupal a szűrt beviteli formában és egyáltalán nem úgy néz ki a végeredmény mint ahogy azt akarta a felhasználó. Persze Ő soha nem fog rájönni, hogy mimiatt történt, és úgy gondolja valami fejlesztési hiba van a dologban. Természetesen ez nem fejelsztési hiba, de akkor sem várható el egy editortól, hogy rájöjjön mi okozza a problémát.

A Wysiwyg API modul erre talált gyógyírt, mégpedig azzal, hogy az editor használhatóságát a beviteli formához lehet megadni, nem pedig egy user jogosultság. Minden definiált beviteli formához külön-külön más és más editoroka lehet beállítani. Ekkor két kérdés merül fel:

  1. mi az hogy más és más WYSIWYG editorokat lehet rendelni?
  2. bárki használhatja az editort hisz nincs jogosultsághoz kötve?

Az első kérdésre a válasz az, hogy a Wysiwyg API egyszerre több WYSIWYG editort képes kezelni. Ez annyit takar, hogy a beállítási oldalán fel van sorova egy csomó WYSIWYG editor (pl MarkItUp, FCK editor vagy a TinyMCE editor), és amelyik fel van telepítve a megadott könyvtárba azt ki lehet választani egy legördülőből a beviteli formák felsorolása mellett.

A másodikra a válasz: nem. A beviteli formák beállítása oldalán meg lehet adni, hogy egy adott beviteli formát milyen csoport hasznáhat, és tetszőleges számút létrehozhatunk. Tehát pl, ha a Full HTML-t meg akarjuk hagyni a HTML-t értő és WYSIWYG editort nem használó csoport számára, akkor létrehozunk egy új beviteli formát, amelyben szintén nincs semmilyen szürő és hozzárendeljük a kívánt csoporthoz.

Ennyit a Wysiwyg API modul szépségéről, térjünk rá a cikk lényegére, a teaser beállítására.

Miután feltelepítettük a modult észrevehetjük, hogy eltűnt a teaser lehetőségére szolgáló gomb a body rész felett. Ez annyit takar hogy innenstől kezdve magunk nem állíthatjuk be hogy a teaser rész meddig tartson és azt sem, hogy ez akár különbözzön a tartalom többi részétől.

Mivel én hasznosnak találom ezt a funkciót, és többször is szükség volt már rá, ezért elkezdtem kutakodni és utánajárni hogy is lehetne megoldani. A TinyMCE editorban van egy pagebreak plugin, tehát lehetséges hogy megoldódik a probléma, mert a Drupal body részében egy helyre beírjuk a

<!--break-->

kifejezést, akkor ezt a Drupal úgy értelmezi, hogy az előtte lévő rész a teaser rész. Ez eddig szép és jó, csak kéne egy ilyen gomb az editor szerkesztőfelületére.

Ehhez a modul editors/tinymce.inc fájl wysiwyg_tinymce_plugins() fgv-ét kell módosítanunk.
A végén találunk benne egy ilyen részt:

  1.   if ($editor['installed version'] > 3) {
  2.     $plugins['xhtmlxtras'] = array(
  3.       'path' => $editor['library path'] .'/plugins/xhtmlxtras',
  4.       'buttons' => array('cite' => t('Citation'), 'del' => t('Deleted'), 'abbr' => t('Abbreviation'), 'acronym' => t('Acronym'), 'ins' => t('Inserted')),
  5.       'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',
  6.       'internal' => TRUE,
  7.       'load' => TRUE,
  8.     );
  9.     $plugins['safari'] = array(
  10.       'path' => $editor['library path'] .'/plugins/safari',
  11.       'extensions' => array('safari' => t('Safari compatibility')),
  12.       'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari',
  13.       'internal' => TRUE,
  14.       'load' => TRUE,
  15.     );
  16.   }

ezt kell kibővítenünk a következő képpen:

  1.   if ($editor['installed version'] > 3) {
  2.     $plugins['xhtmlxtras'] = array(
  3.       'path' => $editor['library path'] .'/plugins/xhtmlxtras',
  4.       'buttons' => array('cite' => t('Citation'), 'del' => t('Deleted'), 'abbr' => t('Abbreviation'), 'acronym' => t('Acronym'), 'ins' => t('Inserted')),
  5.       'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',
  6.       'internal' => TRUE,
  7.       'load' => TRUE,
  8.     );
  9.     $plugins['safari'] = array(
  10.       'path' => $editor['library path'] .'/plugins/safari',
  11.       'extensions' => array('safari' => t('Safari compatibility')),
  12.       'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari',
  13.       'internal' => TRUE,
  14.       'load' => TRUE,
  15.     );
  16.     $plugins['pagebreak'] = array(
  17.       'path' => $editor['library path'] .'/plugins/pagebreak',
  18.       'buttons' => array('pagebreak' => t('Drupal Teaser')),
  19.       'url' => 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/pagebreak',
  20.       'internal' => TRUE,
  21.       'load' => TRUE,
  22.     );
  23.   }

Ekkor a TinyMCE editor beállítási oldalán a gombok között megjelenik a Drupal Teaser gomb. Ha kiválasztjuk, akkor a tartalom szerkesztésénél láthatjuk, hogy megjelenik és ha megnyomjuk megjelenik a

<--! pagebreak -->

felirat a szövegben. Várjuk a csodát, hogy majd biztos jó lesz, de sajnos nem működik. Ennek az az oka, hogy a TinyMCE editor pagebreak plugin-je a következőt helyettesíti be:

<--! pagebreak -->

holott a Drupal ezt tudja értelmezni:

<!--break-->

Ebből látszik, hogy a plugin JavaScript fájljába is bele kell kontárkodnunk egy kicsit, mégpedig a modul könyvtárán belül a tinymce/jscripts/tiny_mce/plugins/pagebreak/editor_plugin.js fájlba. Keressük meg a részt, ami beleteszi a kifejezést:

"pagebreak_separator","<!-- pagebreak -->"

és írjuk át a megfelelőre:

"pagebreak_separator","<!---break-->"

Ekkor ha újra megpróbáljuk beállítani, hogy meddig tartson a teaser rész, tökéletesen működni fog.

Mostmár csak egy dolgot akarunk megoldani, mégpedig hogy a teaser rész különbözhessen a tartalomtól.

Ennek megoldására a wysiwyg.module wysiwyg_form_alter() (hook_form_alter()) fgv-ét kell módosítanunk.
Ha megnézzük az egész fgv. csak ennyitből áll:

  1. function wysiwyg_form_alter(&$form, &$form_state) {
  2.   $form['#after_build'][] = 'wysiwyg_process_form';
  3.   // Disable 'teaser' textarea.
  4.   if (isset($form['body_field'])) {
  5.     unset($form['body_field']['teaser_js']);
  6.     $form['body_field']['teaser_include'] = array();
  7.   }
  8. }

Kommentbe benne is van, hogy a teaser részt kiszedi a modul. A teaser_js részt megszűnteti, ez jó is nekünk így, mert egyrészt összeakad a modullal a js (ez az, ha rányomunk a gombra akkor DHTML-el felkerül egy újabb textarea amelyben megadhatjuk a teaser rész tartalmát), másrészt pedig a WYSIWYG editorral már meg tudjuk oldali a teaser elkülönítését, és így legalább szerkeszthető is (úgy értem a WYSIWYG editorral). Nekünk gyakorlatilag csak az “Összefoglaló megjelenítése a teljes nézetben is” checkbox kellene, hogy meg tudjuk adni a teaser beépüljön a tartalomba, vagy különböző legyen.

Ezt úgy tudjuk elérni kiszedjük (vagy kikommentezzük) a következő részt:

  1. $form['body_field']['teaser_include'] = array();

Így a wysiwyg_form_alter() fgv. a követekző képpen módosul:

  1. function wysiwyg_form_alter(&$form, &$form_state) {
  2.   $form['#after_build'][] = 'wysiwyg_process_form';
  3.   // Disable 'teaser' textarea.
  4.   if (isset($form['body_field'])) {
  5.     unset($form['body_field']['teaser_js']);
  6.     //$form['body_field']['teaser_include'] = array();
  7.   }
  8. }

Ekkor szépen megjelenik a checkbox, és beállíthajuk a teaser-t is.

Olyan oldalaknál ahol egy bizonyos node tipushoz sok beviteli mező tartozik elvárás lehet, hogy ne kelljen minden módosításnál lemenni a lap aljára.

A logikus megoldás az, hogy az ENTER gomb lenyomásával jelzi a felhasználó, hogy végzett a tartalom módosításával, feltöltésével.

Az eseményt a jQuery JavaScript könyvtárral könnyen meg lehet oldalni, utána pedig már csak egy nagyon egyszerű Drupal modult kell hozzá írni, és minden olyan weblapon alkalmazni lehet ahol szükség van rá.

Íme a JavaScript fájl amint majd hozzárendelünk az oldalhoz:

  1. var writing   = false;
  2. var node_edit = false;
  3.  
  4. $(document).ready(function() {
  5.  
  6.   if ($('#node-form').length) {
  7.     node_edit = true;
  8.   }
  9.  
  10.   if (node_edit) {
  11.     $('.form-textarea', $('#node-form').parent()).focus(function() {
  12.       writing = true;
  13.     });
  14.     $('.form-textarea', $('#node-form').parent()).blur(function() {
  15.       writing = false;
  16.     });
  17.   }
  18. });
  19.  
  20. $(document).keypress(function(event) {
  21.   if (event.keyCode == 13 && !writing && node_edit) {
  22.  
  23.     if (confirm_submit()) {
  24.       $('#edit-submit', $('#node-form').parent()).click();
  25.     }
  26.   }
  27. });
  28.  
  29. function confirm_submit() {
  30.   var agree = confirm("Valóban menti a tartalom változásait?");
  31.   if (agree) {
  32.     return true ;
  33.   } else {
  34.     return false ;
  35.   }
  36. }

Menjünk végig a kódon, mi miért van!

Először is a writing változó, a node_edit változó és az oldal betöltésekor lefutó fgv-ek, vagyis a $(document).ready(function()).
A writing változó azért fontos, mert az ENTER lenyomása esetén nem feltétlenül a tartalom szerkesztésének befejeztét jelzi a felhasználó, hanem esetlegesen éppen egy olyan szöveget gépel be, amiben van sortörés. Az pedig elég nagy gond lenne, ha nem lehetne több sort bevinni egy node-ba :-)
Ezért aztán létrehozzuk a writing bool tipusú változót alapértelmezetten hamisra állítva, és figyelve az eseményeket változtatjuk, hogy éppen gépelés történik vagy sem.
Az odlal betöltődésekor a form-textarea osztályokhoz hozzárendeljük a focus() és blur() fgv-eket.
Amikor egy textarea-ba bekattint (focus) a felhasználó a writing változó értéke igazra változik, amikor elhagyja (blur) hamisat vesz fesz vel.
A node_edit bool tipusú változót azért hozzuk létre, mert a későbbiekben a hook_form_alter()-t fogjuk használni a js beépítésére, ez azonban nem csak a node-ok szerkesztésénél fut le, hanem például a felhasználók kezelési felületén is. Ezért megvizsgáljuk, hogy a node-form létezik-e, és csak akkor futtatjuk a kódót ha igen.

A billentyű lenyomása, a keypress(function).
Ezt magához az oldalhoz ($(document)) kell hozzárendelni, hiszen nem valamely beviteli mezőt figyeljük.
A fgv paramétere az event változó, ez tartalmazza a billentyűlenyomás tulajdonságait.
A keyCode a lenyomott billentyű ID-ját tartalmazza ami egy egész. Az ENTER gomb kulcsa a 13-as szám.
Emiatt a feltételben megvizsgáljuk, hogy a 13-as kódszámmal rendelkező billentyű lett-e lenyomva (ENTER), és hogy éppen folyik-e a gépelés (writing változó).
Ha a feltételnek megfelelőek az értékek és a felhasználó megerősítette (confirm_submit), hogy befelyezte a szerkesztést akkor végrehajtjuk a node mentését.

Lehetséges, hogy a

  1. $('#edit-submit', $('#node-form').parent()).click();

sor egy kis magyarázatra szorul.

Az node-form a form id attributuma.
Gondolhatnánk a legegyszerűbb meghívni a submit eseményt a submit() fgv-el. A probléma az, hogy a node szerkesztési felületén három submit gomb van: beküldés, előnézet, törlés. Emiatt a submit esemény nem egyértelmű, hiszen mind a három gomb, ugyanannak a form-nak a submit gombjai, és mindegyik mást csinál. Emiatt nem történik semmi.
A következő gondolat az, hogy oldajuk meg a problémát az edit-submit id-jú gomb click esemény meghívásával.
Ezzel a gond az, hogy a Drupal beépített form-jainak mind ez az azonosítója. Így pl ha engedélyezve van a search modul akkor annak a submit gombaja is ugyanezzel az id-val rendelkezik, tehát könnyen előfordulhat, hogy az enter lenyomása mondjuk keresést eredményez, nem pedig a tartalom elmentését.
Ezért magában a form-ban kell megkeresnünk a megfelelő gombot, viszont form-on belül nem lehet html objektumot keresni, ezért a form-ot körülölelő div-ben kell megtennünk.

Az utolső fgv. a megerősítés, vagyis rákérdez a felhasználótól, hogy valóban mentsük-e a tartalmat.

Ez a jQuery megvalósítás működik, mostmár csak be kell építeni a site-ba.

Mivel ennek a JavaScript-nek csak és kizárólag a node szerkeztési felületén kell megjelnnie, így a hook_form_alter()-t a legérdemesebb használni.

A modulunk, tehát az .info fájlon kívül ennyi:

  1. <?php
  2. /**
  3.  * hook_form_alter().
  4.  */
  5. function enter_node_submit_form_alter($form_id, &$form) {
  6.   drupal_add_js(drupal_get_path('module', 'enter_node_submit') .'/enter_node_submit.js');
  7. }
  8. ?>

A modul letölthető innen:
enter_node_submit.module