Drupal7表单定制和Drupal6大致相同,但是也有一些区别。这次我就来说说Drupal7是如何定制表单的。新建一个“form_theme”模块,然后创建一个表单,显示如下:
3 a6 _5 \% n' Z" ?1 kMy name is [FORM INPUT] [FORM INPUT] and I am [FORM INPUT] years old.
. X: z* Z7 a& ]- b% i这三个表单元素的默认值依次显示“First name”,“Last name”和“Age”,当用户点击某个INPUT时,该表单元素的值为空,然后你就能随意书写了。
) h$ [+ d3 A2 `; j这个简易的功能涉及到:) _' o9 C+ X* y2 ~7 |+ ~8 [
- 主题化表单
- 给表单添加JQuery(JavaScript)
- 给表单添加CSS( O* O- e r; L' ~3 D7 w: R2 Q8 L
这个教程的主要目的是学习如何主题化表单,我不会对一些与主题化不相关的代码做过多地介绍。同样地,如果你想看懂这篇教程,你必须先知道:; b3 y/ G- N" i% W8 c
- 怎样在Drupal7中创建一个模块
- 怎样在Drupal中使用drupal_get_form()创建一个表单
8 o- @/ ?6 }% D- C/ Y1 Q' O6 c 我也不会对教程中的CSS和JQuery代码做过多的讲解,你可以直接复制并粘贴到本地去试验。呵呵,我的目的是如何将CSS和JQuery添加进Drupal中。
0 K. w; G) G& V R, W/ a3 X开始吧!
5 c. w& b) ]' ?4 f- Y第一步:使用hook_menu()为表单注册一个路径
o6 i5 Z" }' I/ o6 z4 y- \2 _2 H我需要先注册一个页面路径好展现表单,下面是hook_menu()的实现:
# p3 Z4 ?- `' l ]2 [! ~7 r i! r
/ u- D8 h" _6 `8 f& f5 t) X. T) H<?php8 u- v% r& e% Q' v% J
function form_theme_menu()
; [8 z) S( A* L7 W+ ]* ]6 w{
, ?) n) p' }* m5 M9 q: z $menu['form_theme'] = array
2 }5 @( W/ V$ Q! L4 @- a (
. x( p7 v6 z' J% h8 ~! D7 c7 o 'title' => 'Theming Forms',
6 O( R3 D" [ I5 [ 'description' => 'Practicing theming forms in Drupal 7',& F k6 a# C/ Q0 e
'page callback' => 'drupal_get_form',
' P) Y0 [" y8 S) M6 v 'page arguments' => array('form_theme_form'),/ ~ K+ x- g' h$ r. Q9 Y
'access callback' => TRUE,
2 F# p6 h9 A8 p7 f' I% r6 G );5 i: `; j- H5 n" @) P
return $menu;& u# D5 R2 h C( d, S5 y1 G
}
# x: d# D/ k7 u1 y+ t?>+ [: O1 L; A( R
9 Q% n# Z6 Y/ f第二步:定义表单! y) p0 t* I( s8 f( Q1 t: ^
在我的表单里,我需要三个textfield,表单定义如下:- `7 j4 g4 Z# s) ]6 Q0 n, i* A% w
& M' W! _1 x4 c d$ _& p# j4 \<?php
+ }" j* U/ s7 I" w$form['first_name'] = array
* I2 w8 W$ h8 {(
& C! c: W; Y% x" \& K '#type' => 'textfield',
' Z* D8 A3 u5 J! \6 _3 n- Y);
" G+ X! @( S: H- w$form['last_name'] = array
$ q5 Z& ]5 {0 r, L+ `9 q$ [+ h6 y" E(' G. c4 `% ~, Y8 @. Y5 Q
'#type' => 'textfield',
! B1 A0 z: @- M2 y: Q' b* P) p" A);! R2 h3 E6 @# p/ H$ K
$form['age'] = array
7 ?: r2 `6 `5 S1 j+ G(
0 z- c W7 C9 g8 I& m# M '#type' => 'textfield',
; m+ U% j% q2 Z; S9 {* c! _ '#maxlength' => 3,: L+ v- ^1 o6 p3 P
);
/ \$ |, C; \$ A4 D3 n?>
# O5 y+ B/ ]- A z; e' d3 Q1 [ c+ G% A: ^) _+ c% ^
嘿嘿,代码十分简洁吧。我已经创建了这些表单元素,它们没什么修饰或其它配置。
1 h+ v, k% P+ U" E( D) F) ~; M然后,我需要添加CSS和Javascript到该表单。Drupal7有个新属性,#attached,我能通过它添加,代码如下:+ J5 |" D# z g+ Q1 ^: G5 p4 f* t9 U
6 V* ^# C( S3 b6 F7 [- ]<?php
* r' s: D5 M- P: S2 `1 [, |// Get the path to the module
8 r6 `/ ?: z3 ?* M# V( X$path = drupal_get_path('module', 'form_theme');
& g7 C( g$ Q, Z- K" x// Attach the CSS and JS to the form
) c9 E# x& b! T4 {$ U0 r+ l: f$form['#attached'] = array
2 D- X& A% ~+ \% A: a7 c1 E(7 {5 t; v. z" v! R( D/ ]
'css' => array" s2 n( [ {: n* r
(
( u8 H& H9 q/ p2 ~' o 'type' => 'file',
/ O1 R, W$ L( y. J- @! Z! ? 'data' => $path . '/form_theme.css',, E4 e1 Y2 C- G9 g# M; {& Y
),
0 x- Z, w& h( [9 _5 Z$ Y 'js' => array! T( A/ n; L$ w9 ^
(7 C) U' b! w0 x& ~ |9 b
'type' => 'file',! S, Z5 o ^8 J; r8 k
'data' => $path . '/form_theme.js',
, ]8 p$ w1 h% `$ T; ^ ),, ^" o& ~2 Q4 t/ _: c: z( q& x
);$ _9 i& w/ ^: u) a* A
?>, l: _6 E8 p6 n
1 `% v: ~( M* Y( L
这种方法相比drupal_add_js()和drupal_add_css()有个很大的好处,就是其它模块可以在该模块的样式和脚本的基础上做修改。5 Q2 o; K0 W6 g+ t* G
最后,返回我的$form表单,代码如下:
2 H% X3 U6 \6 U( o: i5 ]* U0 C [! h1 G" \: n) t9 w/ X7 k; w
<?php
3 g+ Z% S4 o; X3 Xfunction form_theme_form($form, &$form_state)
+ x# I, l: r. y- b1 {6 E. d! I{* A* r. \ i4 r8 w. \) g4 P: z: I
$form['first_name'] = array
# s" i/ ^! H) n% g/ |; P. y+ E, O (
; F- e/ f' R. ~9 A. u O9 ~ g '#type' => 'textfield',6 R, y- f- D( v- r
);' L8 m& a8 f- \
$form['last_name'] = array
% }9 _) g5 c" _" o/ W% G (
" ^4 q5 N9 @+ e( Y/ R5 C5 ~: c$ U* q '#type' => 'textfield',! c; c7 V* j+ d, S; N+ r
);
8 w. \1 o0 Q# O0 I: L- V; y $form['age'] = array3 t; p! t0 o6 ?% o
(# W) Q1 F9 g% z6 ?, Z% B8 S! z
'#type' => 'textfield',! v% I( A- P$ a! O d8 F, K7 N, }
'#maxlength' => 3,+ N# n6 H* ]7 T, l
); n" b0 V6 E9 v( l
// Get the path to the module) p- S8 r( j9 I) Q
$path = drupal_get_path('module', 'form_theme');
) G% P$ i( y! D# T6 J1 \8 }* C // Attach the CSS and JS to the form0 C6 e/ S# |0 H3 y. I. z
$form['#attached'] = array
8 z+ ], L, z* g# c$ B F (
# P4 c, S: P5 ~8 @. Q6 c% | 'css' => array" A- z3 A; o. ^3 L+ H* \
(6 u+ Z# i5 u8 i& F$ N
'type' => 'file',4 h( h- l* x( e/ V8 X
'data' => $path . '/form_theme.css', o% W2 r# V/ P2 [, M
), @8 p6 E" N; V
'js' => array
# ]0 T8 y# g& [2 W! a (
( {5 ?* L4 Z& e6 Z 'type' => 'file',
$ j c1 \+ h8 C, [ 'data' => $path . '/form_theme.js',
" f0 r) |' n/ B7 h, A0 Q; @ ),/ R; k5 z& r4 z1 G! }
);- m1 O6 B6 r2 B+ f: D
return $form;
5 Y. `' p/ U' \, h% p9 ^6 \/ {}) D. O7 D0 L. e3 d& M! c
?>
* R# [! [$ Q6 B5 ~5 ?% T x% r, K
( S7 w: c6 q+ z9 Y' _. l第三步:用hook_theme()注册一个主题函数! E* O. _/ E* Y6 ^) u
从Drupal6开始,主题函数就需要通过hook_theme()注册,但是在Drupal6和Drupal7中还是有些细微的区别。在Drupal7中,表单的主题函数不是使用“arguments”,而是使用仅仅只有“form”一个值的“render element”。在注册主题函数时,你必须让索引和你已经定义的表单函数保持一致。代码如下:
; }( W: X' j3 q0 n: r
- {1 n' c1 {3 H% R" n( T9 E<?php1 M& M/ M/ ^7 X
function form_theme_theme()
9 o; x1 e, W# Q- d5 `, ]. A, F{& E( S# `; i v1 t7 r, f' P0 r
return array9 K' W) V6 S8 O- `; _- Q
(
& z$ X* S. l- e/ M- F* R/ g# A 'form_theme_form' => array
5 v0 m$ P/ v; V7 p1 F* Z () l6 `" T& a8 z, ]
'render element' => 'form': ?9 Q5 o& a3 f7 d$ R" K% o' b
),3 O7 o6 |+ h; r* E. p! s5 j
);
9 k6 [1 A9 i2 T}
/ B; B- ]; `0 b3 A5 M?>
7 g; N1 { g7 j5 r6 S- c, @+ C& S) R" v% K9 L
正如你所见,我已经注册了一个主题函数。主题函数的命名十分重要,因为这个主题函数跟表单有相同的名称,Drupal在实现这个表单时会自动调用该主题函数。我也不需要添加#theme到我定义的表单$form中,这是多余的。1 G; H/ }) Q1 R" N) e u. d
第四步:写主题函数0 r* Z7 l/ P3 R+ }' m
在Drupal7中,写主题函数,有几个注意点。它们是:- ?+ n9 c' k- v7 q7 m( e
- 函数只有一个参数,命名为$variables的数组。$variables有一个form索引,该索引的值就包括所有你已定义的表单元素。
- 所有的表单元素必须要作为参数传给drupal_render()函数。这个函数能将一个PHP数组转换成HTML,并且将Javascript和css添加进去。这些Drupal会自动帮你完成,你仅仅需要传递这些参数就行了。
- 在写主题函数的最后,你必须将剩余的表单元素传给drupal_render_children()函数,这样才能将剩下的或隐藏的表单元素转换成HTML。这是跟Drupal6一个很大的不同。在Drupal6中,我们直接传递$form给drupal_render(),但是在Drupal7中,这样做就会导致死循环,而且不会出现任何错误提示。
# e2 m9 d( m$ ^0 P: Y( S J* S5 k 主题函数是以“theme_”加上我们上面注册过“form_theme_form”命名的。代码如下:
: j3 X/ Y3 ]7 ^2 L% H4 B$ k* I% A" W/ n! m6 N
<?php2 z- g5 _ T/ S. y
function theme_form_theme_form($variables)
& ?- _# X( d4 U% M9 ]8 z{
) Y: b* f" q. ?) y5 O) a% t // Isolate the form definition form the $variables array
4 k4 w7 t- |* o. @' b $form = $variables['form'];
# _' d3 X5 d* M5 n3 E. ]% {4 J $output = '<h2>' . t('Please enter your information below') . '</h2>';% q0 J# P! ^* k' n
// Put the entire structure into a div that can be used for9 d! N, {+ {5 t1 V# {
// CSS purposes |) p1 c- `0 |* i) i
$output .= '<div id="personal_details">';( n* G% H) A N1 W3 F/ y1 O
// Each of the pieces of text is wrapped in a <span>
' s; Y# ]5 [- M" Y$ L // tag to allow it to be floated left
& e2 o4 [2 N$ {. a8 } F0 B $output .= '<span>' . t('My name is') . '</span>';
- s% q( H) c. C6 j7 q // Form elements are rendered with drupal_render()( J# b% y5 m! F& {
$output .= drupal_render($form['first_name']);
; F& B. N+ K$ @( W $output .= drupal_render($form['last_name']);2 p* ]7 [# R3 E. h1 I* |2 K
$output .= '<span>' . t('and I am') . '</span>';6 T" h; H& c6 T) Y9 {
$output .= drupal_render($form['age']);/ R, Y9 y6 R7 Y4 f
$output .= '<span>' . t('years old.') . '</span>';% S$ \* x' _8 s" C" x2 q& P
$output .= '</div>';# L/ Y+ s3 H, p( z: e4 b
// Pass the remaining form elements through drupal_render_children()! y; P# }- u0 Y. I' j
$output .= drupal_render_children($form);
+ Q: h" P* L' B X" o9 H // return the output
8 n7 b! E j( Q6 y8 A! ` return $output;
' b2 D- w! @/ X% r$ `# X. C}. B" x& O+ }7 m) ]- Y! ^' D
?>
" E6 h1 P. H3 R1 r
% B L/ t u6 i! J& T9 p到这里,我已经完成大部分的内容,定义表单,注册主题函数,实现主题函数。但是我还没添加CSS和Javascript。$ Q5 _1 W( U9 r; j% ^4 Z" e8 L- t
第五步:创建CSS和Javascript文件- z# `/ a$ t! m, Z/ D- j& m
在第二步中我添加了CSS和JS路径,这两个文件都在form_theme模块的根目录。CSS代码如下:- Y6 m& B5 r2 z/ l
+ |6 z% }# @1 b
#personal_details span, #personal_details div, q1 J# A6 u; T0 ~% z
{) X8 E( b9 N( l+ |+ v
float:left;& b1 y$ d9 G+ [" x8 g, c( `8 ]% s
}
+ B* T- I8 I# v5 o# D) Z8 O D! h* g2 ?& ^7 j5 t
#personal_details .form-item-first-name, #personal_details .form-item-last-name; K. i: x. ^# J+ ^* T* D7 d( v6 ]
{
2 n1 j/ \, t7 {* j5 C' Xwidth:115px;# W' {; f# e! @# W y% [8 ]
}
8 r' W- m7 j0 `7 J, }/ X9 _3 c6 B; L) k5 ^
#edit-first-name, #edit-last-name+ ]* x8 N8 W" U# O! A" u
{( X' `8 \; e7 J2 Q( k: X8 L. D
width:100px;
; k% T. j, }5 u' `, r* k0 e}+ m1 l5 y0 f u5 f
# G3 H# n8 {1 @ S; w# j0 S* I
#personal_details .form-item-age
0 i4 P9 e7 r+ m{
7 P9 A7 z2 y' M; k1 @width:50px;2 N& n1 W* S r9 c# e: K1 j) p/ q+ V
}
& \9 K6 }; A8 b) }! t- C- q( F9 T) n+ a& G, `
#edit-age
8 ~) A; v$ K# u7 u4 i{# g/ N) m8 x. H5 C* T i# Q
width:35px;' E# l/ w* \; {. D
}
6 g8 K8 w+ g/ ]5 u% ~* m/ f; Z% r) l. x, O' o6 n% j( S
#personal_details span% Q$ [/ M# D/ N9 Y z
{: f: S( Z' l6 T$ H, n
margin-right:5px;& U1 ~' d1 l/ ~- N$ S/ t; S
padding-top:5px;5 h' S% ^" I* W' R, A
}1 H$ G- Q5 X% {8 o* q9 ]
' g8 H2 v+ t( x" {! F
Javascript代码如下: t" m6 v/ y" n7 d4 ?$ C
. A9 c$ Y M) B- m7 r, f, d
// We wrap the entire code in an anonymous function
9 q5 j9 A4 h- T1 f4 k) u0 B) {// in order to prevent namespace collisions, and to: ~5 S) `8 L+ m/ G
// allow for jQuery to be set in a safe mode where
+ z" _& ^) @8 O2 v7 [; N// it will not collide with other javascript libraries.
! V) ?5 l6 R1 Q# I' U// While this is the proper way to do it in Drupal 7,
+ _ N8 U: k; }6 M// this method is actually good to use in Drupal 6 as9 w) v# R ~' [
// well, for the same reasons.
% [; z! J7 ` b7 _/ [' ^) G(function($)
+ Y1 ?. T4 w; H9 z# U' O# p3 t9 L{0 [! Z4 j# ]* F! I' l& e
// In Drupal 6, each element of Drupal.behaviors% b% p: |! s2 u7 f5 H) b- k2 q/ k
// was a function that was executed when the
/ k. D& B; R& f9 U+ W" e// document was ready. In Drupal 7, each element0 K! I q6 V4 t* T) e
// of Drupal.behaviors is an object with an
2 z6 _! h6 O! L! U3 N// element 'attach' (and optionally an element
) \3 _6 _4 W8 U7 q; H// 'detach'), which is executed when the document
! w& `, u4 Y+ Y' E( P// is ready
& H6 @% Y! t, _+ BDrupal.behaviors.formTheme = {
4 ^( X" e- [! V" |- eattach:function() {
" k0 } p# k6 z9 X f( D// First, define an empty array" U3 q0 a' W5 ~6 e3 B
var defaults = [];" f5 E7 [) f3 w% Z1 }3 y$ A
// Next, add three elements to the array,
: \$ b% c, M% E/ O# s// one for each of the form elements. The value' H- J& H' w% l& T n
// is of the array element is set as the default
6 P1 J, ~8 F! Y, W% \& }6 @/ ?// text. This text is run through Drupal.t(),
% Y D6 s; M/ y/ O8 O$ Z6 J// which is the Drupal JavaScript equivalent, ~: G+ w0 H V+ W/ E( w
// of the Drupal PHP t() function, and allows. D1 S% p: W( H* |# A$ G
// for translating of text in a JavaScript document: g+ x! s, L; Z' L h% b) w: A
defaults["#edit-first-name"] = Drupal.t("First Name");$ F; O: X3 }6 O: z7 d
defaults["#edit-last-name"] = Drupal.t("Last Name");; Y2 `' D; t' j7 r' j6 }" s5 V
defaults["#edit-age"] = Drupal.t("Age");
4 c) P) b" o: B9 r) A l// Next we loop through each of the elements of the array1 p( h1 u" j- u {9 D# c" Q
var element;+ F' \2 W1 ]2 E- {! z& R
for(element in defaults)
1 V8 G. }, @# l, N+ t{$ P8 L `1 |7 D' N r7 h8 N
// We wrap the body in the following if() statement: I7 g0 s% I" r6 u/ H8 ^
// as each element in an array will also have a
, D9 ^9 H2 Y% c& e. F5 S8 X) a// prototype element. If you don't understand this,
& H; R9 I. q& R// don't worry. Just copy it. It will make your
: b- B3 j: y' c4 ?! n! h// for(A in B) loops run better.
2 Y. e/ Q( W: n' b9 N! Zif(defaults.hasOwnProperty(element)) {
9 c) O) F/ q9 }7 m! Z; x// 1) Set a placeholder in the form element& R7 b* ]- D4 |" K- o
// 2) Set the CSS text color to grey for the placeholder; @+ v5 V6 X$ t/ Q7 o5 Y/ o/ `8 x
// 3) Attach an onfocus and onblur listener to each element3 F8 b' `5 K) B
$(element).val(defaults[element]).css("color", "grey").focus(function()
# ?/ `6 _ ^2 w ?% a' U7 T{! `. M( P6 x* ]0 K
// This is entered on focus. It checks5 I n; D( w1 w8 O( Q% b# ]. u% k
// if the value of the form element is
5 g4 X1 T0 z7 L/ O// the default value of the placeholder,
# T" e, O3 T$ i( F. t// and if it is, it clears the value and9 D# D* ]7 `5 Q6 c
// sets the text color to black,as the0 E9 b+ C# p$ R. f
// entered text will be the actual text5 {. r9 Y' T5 j2 K
// and not the greyed out placeholder text.! f" M; T- S. w5 L& l% e5 N4 a' K
var key = "#" + $(this).attr("id");
% W4 M1 l& P$ W: dif($(this).val() === defaults[key]) {
, [5 D/ g+ Z/ N$(this).css("color", "black").val("");
9 t6 [2 k2 z) s+ W9 R! e @}
- C5 F% N6 I% T& C5 W8 F8 V}).blur(function()
4 @( g1 J* P5 ]) \" ?{
3 w) j1 [$ C5 `% C// This is entered on blur, when the element/ v& b+ d- y# X/ z1 }, T
// is exited out of. It checks if the element
8 ~: ]# V4 |$ H6 _// is empty, and if it is, it sets the default$ f: w7 ~8 T: A) `( r
// placeholder text back into the element, and
- }$ p1 ?8 v0 F1 _// changes the text color to the grey placeholder( l/ x, |" e. g% B( v
// text color.
" i( Y& D2 h. Sif($(this).val() == "") {/ Q8 ^. E* g3 m* y4 x7 |
var key = "#" + $(this).attr("id");
( n4 n4 |% S& g7 ^$(this).css("color", "grey").val(defaults[key]);2 T3 g& A! _) a1 v. E
}$ ~, J5 [% Y$ C- T- V1 s
});, i3 Q( y( M7 w c
}
1 I* B! N1 `- F}
( o) X1 I. j9 m% m7 J. m}
' L* Y& |; q( v: \: C7 ]: K};
7 p' ?/ V$ o; @- e- L: @}(jQuery));! [+ t( K) W! A5 s* P2 g
: K, W% K4 X9 ?& w @
好了,你可以试试看。
- m5 U% [5 Y4 {原文出自:http://junepeng.info/zh/node/28' l3 ?2 O8 X9 P
a. W+ U9 s' t9 M, Q% s* |, ^8 z0 ?
; j+ T% o$ l% x/ c+ a5 q, q1 p5 z# U) F
9 S$ C) L8 s% Y W" i
" Y2 t$ {0 U! n: g
|
|