wns-mvc-package
Version:
MVC package/bundle for WNS Middleware
1,271 lines (1,190 loc) • 109 kB
JavaScript
/**
* WNS's HTTP Package
* @copyright © 2013- Pedro Nasser ®
* @license: MIT
* @page http://github.com/pedronasser/wns-http-package
*/
/**
* @class wnHtml
* @desc html helpers
* @author Pedro Nasser
*/
module.exports = {
/**
* WNS Class dependencies
*/
extend: ['wnComponent'],
/**
* NPM dependencies
*/
dependencies: ['url'],
/**
* PRIVATE
*/
private: {},
/**
* Public Variables
*/
public: {
ID_PREFIX: 'wn',
/**
* @var string the CSS class for displaying error summaries (see {@link errorSummary}).
*/
errorSummaryCss:'errorSummary',
/**
* @var string the CSS class for displaying error messages (see {@link error}).
*/
errorMessageCss:'errorMessage',
/**
* @var string the CSS class for highlighting error inputs. Form inputs will be appended
* with this CSS class if they have input errors.
*/
errorCss:'error',
/**
* @var string the tag name for the error container tag. Defaults to 'div'.
* @since 1.1.13
*/
errorContainerTag:'div',
/**
* @var string the CSS class for required labels. Defaults to 'required'.
* @see label
*/
requiredCss:'required',
/**
* @var string the HTML code to be prepended to the required label.
* @see label
*/
beforeRequiredLabel:'',
/**
* @var string the HTML code to be appended to the required label.
* @see label
*/
afterRequiredLabel:' <span class:"required">*</span>',
/**
* @var integer the counter for generating automatic input field names.
*/
count:0,
/**
* Sets the default style for attaching jQuery event handlers.
*
* If set to true (default), event handlers are delegated.
* Event handlers are attached to the document body and can process events
* from descendant elements that are added to the document at a later time.
*
* If set to false, event handlers are directly bound.
* Event handlers are attached directly to the DOM element, that must already exist
* on the page. Elements injected into the page at a later time will not be processed.
*
* You can override this setting for a particular element by setting the htmlOptions delegate attribute
* (see {@link clientChange}).
*
* For more information about attaching jQuery event handler see {@link http://api.jquery.com/on/}
* @since 1.1.9
* @see clientChange
*/
liveEvents:true,
/**
* @var boolean whether to close single tags. Defaults to true. Can be set to false for HTML5.
* @since 1.1.13
*/
closeSingleTags:true,
/**
* @var boolean whether to render special attributes value. Defaults to true. Can be set to false for HTML5.
* @since 1.1.13
*/
renderSpecialAttributesValue:true,
},
/**
* Extended methods
*/
methods: {
/**
* Encodes special characters into HTML entities.
* The {@link CApplication::charset application charset} will be used for encoding.
* @param string $text data to be encoded
* @return string the encoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars.php
*/
encode: function (text)
{
return this.getParent().html.encoder.htmlspecialchars(text,'ENT_QUOTES',this.getParent().charset);
},
/**
* Replace an array of strings with other array
* of string on the target string.
* @param array $find find
* @param array $replace replace
* @param string $string target string
* @return string result
*/
replaceArray: function(find, replace, string) {
var replaceString = string+'';
for (var i = 0; i < find.length; i++) {
replaceString = replaceString.replace(find[i], replace[i]);
}
return replaceString;
},
/**
* PHP's strstr() function in Javascript.
* @param string $haystack haystack
* @param string $haystack needle
* @param boolean $bool bool
* @return string result
*/
strstr: function(haystack, needle, bool) {
var pos = 0;
haystack += '';
pos = haystack.indexOf(needle);
if (pos == -1) {
return false;
} else {
if (bool) {
return haystack.substr(0, pos);
} else {
return haystack.slice(pos);
}
}
},
/**
* Decodes special HTML entities back to the corresponding characters.
* This is the opposite of {@link encode()}.
* @param string $text data to be decoded
* @return string the decoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars-decode.php
* @since 1.1.8
*/
decode: function (text)
{
return this.getParent().html.encoder.htmlspecialchars_decode(text,'ENT_QUOTES');
},
/**
* Encodes special characters in an array of strings into HTML entities.
* Both the array keys and values will be encoded if needed.
* If a value is an array, this method will also encode it recursively.
* The {@link CApplication::charset application charset} will be used for encoding.
* @param array $data data to be encoded
* @return array the encoded data
* @see http://www.php.net/manual/en/function.htmlspecialchars.php
*/
encodeArray: function (data)
{
d=[];
for (d in data)
{
var key = d, value = data[d];
if('string' === typeof (key))
key=this.getParent().html.encoder.htmlspecialchars(key,'ENT_QUOTES',this.getParent().charset);
if('string' === typeof (value))
value=this.getParent().html.encoder.htmlspecialchars(value,'ENT_QUOTES',this.getParent().charset);
else if(Array.isArray(value))
value=self.encodeArray(value);
d[key]=value;
}
return d;
},
/**
* Generates an HTML element.
* @param string $tag the tag name
* @param object $htmlOptions the element attributes. The values will be HTML-encoded using {@link encode()}.
* If an 'encode' attribute is given and its value is false,
* the rest of the attribute values will NOT be HTML-encoded.
* Since version 1.1.5, attributes whose value is null will not be rendered.
* @param mixed $content the content to be enclosed between open and close element tags. It will not be HTML-encoded.
* If false, it means there is no body content.
* @param boolean $closeTag whether to generate the close tag.
* @return string the generated HTML element tag
*/
tag: function (tag,htmlOptions,content,closeTag)
{
var tag = tag!=undefined ? tag : '',
content = content!=undefined ? content : false,
closeTag = closeTag!=undefined ? closeTag : true;
html='<' + tag + self.renderAttributes(htmlOptions||{});
if(content===false)
return closeTag && self.closeSingleTags ? html+' />' : html+'>';
else
return closeTag ? html+'>'+content+'</'+tag+'>' : html+'>'+content;
},
/**
* Generates an open HTML element.
* @param string $tag the tag name
* @param object $htmlOptions the element attributes. The values will be HTML-encoded using {@link encode()}.
* If an 'encode' attribute is given and its value is false,
* the rest of the attribute values will NOT be HTML-encoded.
* Since version 1.1.5, attributes whose value is null will not be rendered.
* @return string the generated HTML element tag
*/
openTag: function (tag,htmlOptions)
{
return '<' + tag + self.renderAttributes(htmlOptions) + '>';
},
/**
* Generates a close HTML element.
* @param string $tag the tag name
* @return string the generated HTML element tag
*/
closeTag: function (tag)
{
return '</'+tag+'>';
},
/**
* Encloses the given string within a CDATA tag.
* @param string $text the string to be enclosed
* @return string the CDATA tag with the enclosed content.
*/
cdata: function (text)
{
return '<![CDATA[' + text + ']]>';
},
/**
* Generates a meta tag that can be inserted in the head section of HTML page.
* @param string content content attribute of the meta tag
* @param string $name name attribute of the meta tag. If null, the attribute will not be generated
* @param string $httpEquiv http-equiv attribute of the meta tag. If null, the attribute will not be generated
* @param object $options other options in name-value pairs (e.g. 'scheme', 'lang')
* @return string the generated meta tag
*/
metaTag: function (content,name,httpEquiv,options)
{
var options = options || {};
if(name!==null)
options['name']=name;
if(httpEquiv!==null)
options['http-equiv']=httpEquiv;
options['content']=content;
return self.tag('meta',options);
},
/**
* Generates a link tag that can be inserted in the head section of HTML page.
* Do not confuse this method with {@link link()}. The latter generates a hyperlink.
* @param string $relation rel attribute of the link tag. If null, the attribute will not be generated.
* @param string $type type attribute of the link tag. If null, the attribute will not be generated.
* @param string $href href attribute of the link tag. If null, the attribute will not be generated.
* @param string $media media attribute of the link tag. If null, the attribute will not be generated.
* @param array $options other options in name-value pairs
* @return string the generated link tag
*/
linkTag: function (relation,type,href,media,options)
{
var options = options || {};
if(relation!==null)
options['rel']=relation||'';
if(type!==null)
options['type']=type||'';
if(href!==null)
options['href']=href||'';
if(media!==null)
options['media']=media||'';
return self.tag('link',options);
},
/**
* Encloses the given CSS content with a CSS tag.
* @param string $text the CSS content
* @param string $media the media that this CSS should apply to.
* @return string the CSS properly enclosed
*/
css: function (text,media)
{
if(media!=='')
media=' media="'+(media||'')+'"';
return "<style type=\"text/css\""+media+">\n/*<![CDATA[*/\n"+(text||'')+"\n/*]]>*/\n</style>";
},
/**
* Registers a 'refresh' meta tag.
* This method can be invoked anywhere in a view. It will register a 'refresh'
* meta tag with {@link CClientScript} so that the page can be refreshed in
* the specified seconds.
* @param integer $seconds the number of seconds to wait before refreshing the page
* @param string $url the URL to which the page should be redirected to. If empty, it means the current page.
* @since 1.1.1
*/
refresh: function (seconds,url)
{
// content=seconds+"";
// if(url&&url!=='')
// content+=';url='+self.normalizeUrl(url+'');
// this.getParent().clientScript.registerMetaTag(content,null,'refresh');
},
/**
* Links to the specified CSS file.
* @param string $url the CSS URL
* @param string $media the media that this CSS should apply to.
* @return string the CSS link.
*/
cssFile: function (url,media)
{
return self.linkTag('stylesheet','text/css',url,media!=='' ? media : null);
},
/**
* Encloses the given JavaScript within a script tag.
* @param string $text the JavaScript to be enclosed
* @param object $htmlOptions additional HTML attributes (see {@link tag})
* @return string the enclosed JavaScript
*/
script: function (text,htmlOptions)
{
defaultHtmlOptions={
'type':'text/javascript',
};
htmlOptions=_.merge(htmlOptions,defaultHtmlOptions);
return self.tag('script',htmlOptions,"\n/*<![CDATA[*/\n"+(text||'')+"\n/*]]>*/\n");
},
/**
* Includes a JavaScript file.
* @param string $url URL for the JavaScript file
* @param object $htmlOptions additional HTML attributes (see {@link tag})
* @return string the JavaScript file tag
*/
scriptFile: function (url,htmlOptions)
{
defaultHtmlOptions={
'type':'text/javascript',
'src':url||''
};
htmlOptions=_.merge(defaultHtmlOptions,htmlOptions);
return self.tag('script',htmlOptions,'');
},
/**
* Generates an opening form tag.
* This is a shortcut to {@link beginForm}.
* @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
* @param string $method form method (e.g. post, get)
* @param object $htmlOptions additional HTML attributes (see {@link tag}).
* @return string the generated form tag.
*/
form: function (action,method,htmlOptions)
{
var method = method || 'post',
action = action || '';
return self.beginForm(action,method,htmlOptions);
},
/**
* Generates an opening form tag.
* Note, only the open tag is generated. A close tag should be placed manually
* at the end of the form.
* @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
* @param string $method form method (e.g. post, get)
* @param object $htmlOptions additional HTML attributes (see {@link tag}).
* @return string the generated form tag.
* @see endForm
*/
beginForm: function (action,method,htmlOptions)
{
var method = method || 'post',
action = action || '',
htmlOptions = htmlOptions || {};
htmlOptions['action']=_url=self.normalizeUrl(action)+'';
htmlOptions['method']=method;
form=self.tag('form',htmlOptions,false,false);
hiddens=[];
if('get'!==method.toLowerCase() && (pos=_url.indexOf('?'))!==-1)
{
var explode = _url.substr(pos+1).split('&');
for (e in explode)
{
var pair = explode[e];
if((pos=pair.indexOf('='))!==-1)
hiddens.push(self.hiddenField(decodeURIComponent(pair.substr(0,pos).replace(/\+/g, ' ')),decodeURIComponent(url.parse(pair.substr(pos+1), true).path.replace(/\+/g, ' ')),{'id':false}));
else
hiddens.push(self.hiddenField(decodeURIComponent(pair.replace(/\+/g, ' ')),'',{'id':false}));
}
}
request=this.getParent().request;
// if(request.enableCsrfValidation && !strcasecmp(method,'post'))
// hiddens.push(self.hiddenField(request.csrfTokenName,request.getCsrfToken(),{'id':false}));
// if(hiddens!==[])
// form+="\n"+self.tag('div',{'style':'display:none'},hiddens.join("\n"));
return form;
},
/**
* Generates a closing form tag.
* @return string the generated tag
* @see beginForm
*/
endForm: function ()
{
return '</form>';
},
/**
* Generates a stateful form tag.
* A stateful form tag is similar to {@link form} except that it renders an additional
* hidden field for storing persistent page states. You should use this method to generate
* a form tag if you want to access persistent page states when the form is submitted.
* @param mixed $action the form action URL (see {@link normalizeUrl} for details about this parameter.)
* @param string $method form method (e.g. post, get)
* @param object $htmlOptions additional HTML attributes (see {@link tag}).
* @return string the generated form tag.
*/
statefulForm: function (action,method,htmlOptions)
{
var method = method || 'post',
action = action || '';
return self.form(action,method,htmlOptions)+"\n"+
self.tag('div',{'style':'display:none'},self.pageStateField(''));
},
// *
// * Generates a hidden field for storing persistent page states.
// * This method is internally used by {@link statefulForm}.
// * @param string $value the persistent page states in serialized format
// * @return string the generated hidden field
pageStateField: function (value)
{
return '<input type="hidden" name="'+this.getParent().controller.stateInputName+'" value="'+value+'" />';
},
/**
* Generates a hyperlink tag.
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code such as an image tag.
* @param mixed $url a URL or an action route that can be used to create a URL.
* See {@link normalizeUrl} for more details about how to specify this parameter.
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated hyperlink
* @see normalizeUrl
* @see clientChange
*/
link: function (text,url,htmlOptions)
{
var url = url || '#';
if(url!=='')
htmlOptions['href']=self.normalizeUrl(url);
self.clientChange('click',htmlOptions);
return self.tag('a',htmlOptions,text);
},
/**
* Generates a mailto link.
* @param string $text link body. It will NOT be HTML-encoded. Therefore you can pass in HTML code such as an image tag.
* @param string $email email address. If this is empty, the first parameter (link body) will be treated as the email address.
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated mailto link
* @see clientChange
*/
mailto: function (text,email,htmlOptions)
{
if(email==='')
email=text;
return self.link(text,'mailto:'+email,htmlOptions,true);
},
/**
* Generates an image tag.
* @param string $src the image URL
* @param string $alt the alternative text display
* @param object $htmlOptions additional HTML attributes (see {@link tag}).
* @return string the generated image tag
*/
image: function (src,alt,htmlOptions)
{
htmlOptions['src']=src;
htmlOptions['alt']=alt||'';
return self.tag('img',htmlOptions);
},
/**
* Generates a button.
* @param string $label the button label
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated button tag
* @see clientChange
*/
button: function (label,htmlOptions)
{
var label = label||'button';
if(undefined === (htmlOptions['name']))
{
if(htmlOptions.name !== undefined)
htmlOptions.name=self.ID_PREFIX+self.count++;
}
if(undefined === (htmlOptions['type']))
htmlOptions['type']='button';
if(undefined === (htmlOptions['value']))
htmlOptions['value']=label;
self.clientChange('click',htmlOptions);
return self.tag('input',htmlOptions);
},
/**
* Generates a button using HTML button tag.
* This method is similar to {@link button} except that it generates a 'button'
* tag instead of 'input' tag.
* @param string $label the button label. Note that this value will be directly inserted in the button element
* without being HTML-encoded.
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated button tag
* @see clientChange
*/
htmlButton: function (label,htmlOptions)
{
var label = label||'button';
if(undefined === (htmlOptions['name']))
htmlOptions['name']=self.ID_PREFIX+self.count++;
if(undefined === (htmlOptions['type']))
htmlOptions['type']='button';
self.clientChange('click',htmlOptions);
return self.tag('button',htmlOptions,label);
},
/**
* Generates a submit button.
* @param string $label the button label
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated button tag
* @see clientChange
*/
submitButton: function (label,htmlOptions)
{
var label = label||'submit';
htmlOptions['type']='submit';
return self.button(label,htmlOptions);
},
/**
* Generates a reset button.
* @param string $label the button label
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated button tag
* @see clientChange
*/
resetButton: function (label,htmlOptions)
{
var label = label||'reset';
htmlOptions['type']='reset';
return self.button(label,htmlOptions);
},
/**
* Generates an image submit button.
* @param string $src the image URL
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated button tag
* @see clientChange
*/
imageButton: function (src,htmlOptions)
{
htmlOptions['src']=src||'';
htmlOptions['type']='image';
return self.button('submit',htmlOptions);
},
/**
* Generates a link submit button.
* @param string $label the button label
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated button tag
* @see clientChange
*/
linkButton: function (label,htmlOptions)
{
var label = label||'submit';
if(undefined === (htmlOptions['submit']))
htmlOptions['submit']=(undefined !== htmlOptions['href']) ? htmlOptions['href'] : '';
return self.link(label,'#',htmlOptions);
},
/**
* Generates a label tag.
* @param string $label label text. Note, you should HTML-encode the text if needed.
* @param string $for the ID of the HTML element that this label is associated with.
* If this is false, the 'for' attribute for the label tag will not be rendered.
* @param object $htmlOptions additional HTML attributes.
* The following HTML option is recognized:
* <ul>
* <li>required: if this is set and is true, the label will be styled
* with CSS class 'required' (customizable with self.$requiredCss),
* and be decorated with {@link self.beforeRequiredLabel} and
* {@link self.afterRequiredLabel}.</li>
* </ul>
* @return string the generated label tag
*/
label: function (label,_for,htmlOptions)
{
if(_for===false)
delete (htmlOptions['for']);
else
htmlOptions['for']=_for;
if('undefined' === typeof (htmlOptions['required']))
{
if(htmlOptions['required'])
{
if('undefined' === typeof (htmlOptions['class']))
htmlOptions['class']+=' '+self.requiredCss;
else
htmlOptions['class']=self.requiredCss;
label=self.beforeRequiredLabel.label.self.afterRequiredLabel;
}
delete (htmlOptions['required']);
}
return self.tag('label',htmlOptions,label);
},
/**
* Generates a text field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
*/
textField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('text',name,value,htmlOptions);
},
/**
* Generates a number field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
numberField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('number',name,value,htmlOptions);
},
/**
* Generates a range field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
rangeField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('range',name,value,htmlOptions);
},
/**
* Generates a date field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
dateField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('date',name,value,htmlOptions);
},
/**
* Generates a time field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
timeField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('time',name,value,htmlOptions);
},
/**
* Generates an email field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
emailField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('email',name,value,htmlOptions);
},
/**
* Generates a telephone field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
telField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('tel',name,value,htmlOptions);
},
/**
* Generates a URL field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
* @since 1.1.14
*/
urlField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('url',name,value,htmlOptions);
},
/**
* Generates a hidden input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes (see {@link tag}).
* @return string the generated input field
* @see inputField
*/
hiddenField: function (name,value,htmlOptions)
{
return self.inputField('hidden',name,value,htmlOptions);
},
/**
* Generates a password field input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated input field
* @see clientChange
* @see inputField
*/
passwordField: function (name,value,htmlOptions)
{
self.clientChange('change',htmlOptions);
return self.inputField('password',name,value,htmlOptions);
},
/**
* Generates a file input.
* Note, you have to set the enclosing form's 'enctype' attribute to be 'multipart/form-data'.
* After the form is submitted, the uploaded file information can be obtained via $_FILES[$name] (see
* PHP documentation).
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes (see {@link tag}).
* @return string the generated input field
* @see inputField
*/
fileField: function (name,value,htmlOptions)
{
return self.inputField('file',name,value,htmlOptions);
},
/**
* Generates a text area input.
* @param string $name the input name
* @param string $value the input value
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* @return string the generated text area
* @see clientChange
* @see inputField
*/
textArea: function (name,value,htmlOptions)
{
var name = arguments[0] || '';
var value = (typeof arguments[1]=='string'?arguments[1]:'');
var htmlOptions = (typeof arguments[1]=='object'?arguments[1]:arguments[2]) || {};3
htmlOptions['name']=name||'';
if(undefined === (htmlOptions['id']))
htmlOptions['id']=self.getIdByName(name);
else if(htmlOptions['id']===false)
delete (htmlOptions['id']);
self.clientChange('change',htmlOptions);
var tag = self.tag('textarea',htmlOptions,(undefined !== htmlOptions['encode'] && !htmlOptions['encode']) ? value : self.encode(value));
return tag;
},
/**
* Generates a radio button.
* @param string $name the input name
* @param boolean $checked whether the radio button is checked
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* Since version 1.1.2, a special option named 'uncheckValue' is available that can be used to specify
* the value returned when the radio button is not checked. When set, a hidden field is rendered so that
* when the radio button is not checked, we can still obtain the posted uncheck value.
* If 'uncheckValue' is not set or set to NULL, the hidden field will not be rendered.
* @return string the generated radio button
* @see clientChange
* @see inputField
*/
radioButton: function (name,checked,htmlOptions)
{
if(checked)
htmlOptions['checked']='checked';
else
delete (htmlOptions['checked']);
value=(undefined !== htmlOptions['value']) ? htmlOptions['value'] : 1;
self.clientChange('click',htmlOptions);
if(htmlOptions.uncheckedValue!==undefined)
{
uncheck=htmlOptions['uncheckValue'];
delete (htmlOptions['uncheckValue']);
}
else
uncheck=null;
if(uncheck!==null)
{
// add a hidden field so that if the radio button is not selected, it still submits a value
if('undefined' === typeof (htmlOptions['id']) && htmlOptions['id']!==false)
uncheckOptions={'id':self.ID_PREFIX+htmlOptions['id']};
else
uncheckOptions={'id':false};
hidden=self.hiddenField(name,uncheck,uncheckOptions);
}
else
hidden='';
// add a hidden field so that if the radio button is not selected, it still submits a value
return hidden + self.inputField('radio',name,value,htmlOptions);
},
/**
* Generates a check box.
* @param string $name the input name
* @param boolean $checked whether the check box is checked
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized (see {@link clientChange} and {@link tag} for more details.)
* Since version 1.1.2, a special option named 'uncheckValue' is available that can be used to specify
* the value returned when the checkbox is not checked. When set, a hidden field is rendered so that
* when the checkbox is not checked, we can still obtain the posted uncheck value.
* If 'uncheckValue' is not set or set to NULL, the hidden field will not be rendered.
* @return string the generated check box
* @see clientChange
* @see inputField
*/
checkBox: function (name,checked,htmlOptions)
{
if(checked)
htmlOptions['checked']='checked';
else
delete (htmlOptions['checked']);
value=(undefined !== htmlOptions['value']) ? htmlOptions['value'] : 1;
self.clientChange('click',htmlOptions);
if(htmlOptions.uncheckValue!==undefined)
{
uncheck=htmlOptions['uncheckValue'];
delete (htmlOptions['uncheckValue']);
}
else
uncheck=null;
if(uncheck!==null)
{
// add a hidden field so that if the check box is not checked, it still submits a value
if('undefined' === typeof (htmlOptions['id']) && htmlOptions['id']!==false)
uncheckOptions={'id':self.ID_PREFIX+htmlOptions['id']};
else
uncheckOptions={'id':false};
hidden=self.hiddenField(name,uncheck,uncheckOptions);
}
else
hidden='';
// add a hidden field so that if the check box is not checked, it still submits a value
return hidden + self.inputField('checkbox',name,value,htmlOptions);
},
/**
* Generates a drop down list.
* @param string $name the input name
* @param string $select the selected value
* @param array $data data for generating the list options (value=>display).
* You may use {@link listData} to generate this data.
* Please refer to {@link listOptions} on how this data is used to generate the list options.
* Note, the values and labels will be automatically HTML-encoded by this method.
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are recognized. See {@link clientChange} and {@link tag} for more details.
* In addition, the following options are also supported specifically for dropdown list:
* <ul>
* <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
* <li>prompt: string, specifies the prompt text shown as the first list option. Its value is empty. Note, the prompt text will NOT be HTML-encoded.</li>
* <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
* The 'empty' option can also be an array of value-label pairs.
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
* <li>options: array, specifies additional attributes for each OPTION tag.
* The array keys must be the option values, and the array values are the extra
* OPTION tag attributes in the name-value pairs. For example,
* <pre>
* array(
* 'value1':array('disabled':true, 'label':'value 1'),
* 'value2':array('label':'value 2'),
* );
* </pre>
* </li>
* </ul>
* Since 1.1.13, a special option named 'unselectValue' is available. It can be used to set the value
* that will be returned when no option is selected in multiple mode. When set, a hidden field is
* rendered so that if no option is selected in multiple mode, we can still obtain the posted
* unselect value. If 'unselectValue' is not set or set to NULL, the hidden field will not be rendered.
* @return string the generated drop down list
* @see clientChange
* @see inputField
* @see listData
*/
dropDownList: function (name,select,data,htmlOptions)
{
htmlOptions['name']=name;
if(undefined === (htmlOptions['id']))
htmlOptions['id']=self.getIdByName(name);
else if(htmlOptions['id']===false)
delete (htmlOptions['id']);
self.clientChange('change',htmlOptions);
options="\n"+self.listOptions(select,data,htmlOptions);
hidden='';
if(!self.getParent().html.encoder.isEmpty(htmlOptions['multiple']))
{
if(substr(htmlOptions['name'],-2)!=='[]')
htmlOptions['name']+='[]';
if('undefined' === typeof (htmlOptions['unselectValue']))
{
hiddenOptions=(undefined !== htmlOptions['id']) ? {'id':self.ID_PREFIX+htmlOptions['id']} : {'id':false};
hidden=self.hiddenField(substr(htmlOptions['name'],0,-2),htmlOptions['unselectValue'],hiddenOptions);
delete (htmlOptions['unselectValue']);
}
}
// add a hidden field so that if the option is not selected, it still submits a value
return hidden + self.tag('select',htmlOptions,options);
},
/**
* Generates a list box.
* @param string $name the input name
* @param mixed $select the selected value(s). This can be either a string for single selection or an array for multiple selections.
* @param array $data data for generating the list options (value=>display)
* You may use {@link listData} to generate this data.
* Please refer to {@link listOptions} on how this data is used to generate the list options.
* Note, the values and labels will be automatically HTML-encoded by this method.
* @param object $htmlOptions additional HTML attributes. Besides normal HTML attributes, a few special
* attributes are also recognized. See {@link clientChange} and {@link tag} for more details.
* In addition, the following options are also supported specifically for list box:
* <ul>
* <li>encode: boolean, specifies whether to encode the values. Defaults to true.</li>
* <li>prompt: string, specifies the prompt text shown as the first list option. Its value is empty. Note, the prompt text will NOT be HTML-encoded.</li>
* <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
* The 'empty' option can also be an array of value-label pairs.
* Each pair will be used to render a list option at the beginning. Note, the text label will NOT be HTML-encoded.</li>
* <li>options: array, specifies additional attributes for each OPTION tag.
* The array keys must be the option values, and the array values are the extra
* OPTION tag attributes in the name-value pairs. For example,
* <pre>
* array(
* 'value1':array('disabled':true, 'label':'value 1'),
* 'value2':array('label':'value 2'),
* );
* </pre>
* </li>
* </ul>
* @return string the generated list box
* @see clientChange
* @see inputField
* @see listData
*/
listBox: function (name,select,data,htmlOptions)
{
if(undefined === (htmlOptions['size']))
htmlOptions['size']=4;
if(!self.getParent().html.encoder.isEmpty(htmlOptions['multiple']))
{
if(substr(name,-2)!=='[]')
name+='[]';
}
return self.dropDownList(name,select,data,htmlOptions);
},
/**
* Generates a check box list.
* A check box list allows multiple selection, like {@link listBox}.
* As a result, the corresponding POST value is an array.
* @param string $name name of the check box list. You can use this name to retrieve
* the selected value(s) once the form is submitted.
* @param mixed $select selection of the check boxes. This can be either a string
* for single selection or an array for multiple selections.
* @param array $data value-label pairs used to generate the check box list.
* Note, the values will be automatically HTML-encoded, while the labels will not.
* @param object $htmlOptions additional HTML options. The options will be applied to
* each checkbox input. The following special options are recognized:
* <ul>
* <li>template: string, specifies how each checkbox is rendered. Defaults
* to "{input} {label}", where "{input}" will be replaced by the generated
* check box input tag while "{label}" be replaced by the corresponding check box label,
* {beginLabel} will be replaced by <label> with labelOptions, {labelTitle} will be replaced
* by the corresponding check box label title and {endLabel} will be replaced by </label></li>
* <li>separator: string, specifies the string that separates the generated check boxes.</li>
* <li>checkAll: string, specifies the label for the "check all" checkbox.
* If this option is specified, a 'check all' checkbox will be displayed. Clicking on
* this checkbox will cause all checkboxes checked or unchecked.</li>
* <li>checkAllLast: boolean, specifies whether the 'check all' checkbox should be
* displayed at the end of the checkbox list. If this option is not set (default)
* or is false, the 'check all' checkbox will be displayed at the beginning of
* the checkbox list.</li>
* <li>labelOptions: array, specifies the additional HTML attributes to be rendered
* for every label tag in the list.</li>
* <li>container: string, specifies the checkboxes enclosing tag. Defaults to 'span'.
* If the value is an empty string, no enclosing tag will be generated</li>
* <li>baseID: string, specifies the base ID prefix to be used for checkboxes in the list.
* This option is available since version 1.1.13.</li>
* </ul>
* @return string the generated check box list
*/
checkBoxList: function (name,select,data,htmlOptions)
{
template=(undefined !== htmlOptions['template'])?htmlOptions['template']:'{input} {label}';
separator=(undefined !== htmlOptions['separator'])?htmlOptions['separator']:"<br/>\n";
container=(undefined !== htmlOptions['container'])?htmlOptions['container']:'span';
delete (htmlOptions['template'],htmlOptions['separator'],htmlOptions['container']);
if(substr(name,-2)!=='[]')
name+='[]';
if('undefined' === typeof (htmlOptions['checkAll']))
{
checkAllLabel=htmlOptions['checkAll'];
checkAllLast=(undefined !== htmlOptions['checkAllLast']) && htmlOptions['checkAllLast'];
}
delete (htmlOptions['checkAll'],htmlOptions['checkAllLast']);
labelOptions=(undefined !== htmlOptions['labelOptions'])?htmlOptions['labelOptions']:{};
delete (htmlOptions['labelOptions']);
items=[];
baseID=(undefined !== htmlOptions['baseID']) ? htmlOptions['baseID'] : self.getIdByName(name);
delete (htmlOptions['baseID']);
id=0;
checkAll=true;
for(d in data)
{
var value=d, labelTitle=data[d]
checked=!Array.isArray(select) && !strcmp(value,select) || Array.isArray(select) && in_array(value,select);
checkAll=checkAll && checked;
htmlOptions['value']=value;
htmlOptions['id']=baseID+'_'+id++;
option=self.checkBox(name,checked,htmlOptions);
beginLabel=self.openTag('label',labelOptions);
label=self.label(labelTitle,htmlOptions['id'],labelOptions);
endLabel=self.closeTag('label');
items.push(self.strtr(template,{
'{input}':option,
'{beginLabel}':beginLabel,
'{label}':label,
'{labelTitle}':labelTitle,
'{endLabel}':endLabel,
}));
}
if('undefined' === typeof (checkAllLabel))
{
htmlOptions['value']=1;
htmlOptions['id']=id=baseID+'_all';
option=self.checkBox(id,checkAll,htmlOptions);
beginLabel=self.openTag('label',labelOptions);
label=self.label(checkAllLabel,id,labelOptions);
endLabel=self.closeTag('label');
item=self.strtr(template,{
'{input}':option,
'{beginLabel}':beginLabel,
'{label}':label,
'{labelTitle}':checkAllLabel,
'{endLabel}':endLabel,
});
if(checkAllLast)
items.push(item);
else
items.unshift(item)
name=self.strtr(name,{'[':'\\[',']':'\\]'});
var js="\n";
js+=" jQuery('#$id').click(function() {\n";
js+=" jQuery(\"input[name='$name']\").prop('checked', this.checked);\n";
js+=" });\n";
js+=" jQuery(\"input[name='$name']\").click(function() {\n";
js+=" jQuery('#$id').prop('checked', !jQuery(\"input[name='$name']:not(:checked)\").length);\n";
js+=" });\n";
js+=" jQuery('#$id').prop('checked', !jQuery(\"input[name='$name']:not(:checked)\").length);";
cs=this.getParent().getClientScript();
cs.registerCoreScript('jquery');
cs.registerScript(id,js);
}
if(self.getParent().html.encoder.isEmpty(container))
return implode(separator,items);
else
return self.tag(container,{'id':baseID},implode(separator,items));
},
/**
* Generates a radio button list.
* A radio button list is like a {@link checkBoxList check box list}, except that
* it only allows single selection.
* @param string $name name of the radio button list. You can use this name to retrieve
* the selected value(s) once the form is submitted.
* @param string $select selection of the radio buttons.
* @param array $data value-label pairs used to generate the radio button list.
* Note, the values will be automatically HTML-encoded, while the labels will not.
* @param object $htmlOptions additional HTML options. The options will be applied to
* each radio button input. The following special options are recognized:
* <ul>
* <li>template: string, specifies how each radio button is rendered. Defaults
* to "{input} {label}", where "{input}" will be replaced by the generated
* radio button input tag while "{label}" will be replaced by the corresponding radio button label,
* {beginLabel} will be replaced by <label> with labelOptions, {labelTitle} will be replaced
* by the corresponding radio button label title and {endLabel} will be replaced by </label></li>
* <li>separator: string, specifies the string that separates the generated radio buttons. Defaults to new line (<br/>).</li>
* <li>labelOptions: array, specifies the additional HTML attributes to be rendered
* for every label tag in the list.</li>
* <li>container: string, specifies the radio buttons enclosing tag. Defaults to 'span'.
* If the value is an empty string, no enclosing tag will be generated</li>
* <li>baseID: string, specifies the base ID prefix to be used for radio buttons in the list.
* This option is available since version 1.1.13.</li>
* <li>empty: string, specifies the text corresponding to empty selection. Its value is empty.
* The 'empty' option can also be an array of value-label pairs.
* Each pair will be used to render a radio button at the beginning. Note, the text label will NOT be HTML-encoded.
* This option is available since version 1.1.14.</li>
* </ul>
* @return string the generated radio button list
*/
radioButtonList: function (name,select,data,htmlOptions)
{
template=(undefined !== htmlOptions['template'])?htmlOptions['template']:'{input} {label}';
separator=(undefined !== htmlOptions['separator'])?htmlOptions['separator']:"<br/>\n";
container=(undefined !== htmlOptions['container'])?htmlOptions['container']:'span';
delete (htmlOptions['template'],htmlOptions['separator'],htmlOptions['container']);
labelOptions=(undefined !== htmlOptions['labelOptions'])?htmlOptions['labelOptions']:{};
delete (htmlOptions['labelOptions']);
if('undefined' === typeof (htmlOptions['empty']))
{
if(!Array.isArray(htmlOptions['empty']))
htmlOptions['empty']={'':htmlOptions['empty']};
data=_.merge(htmlOptions['empty'],data);
delete (htmlOptions['empty']);
}
items=[];
baseID=(undefined !== htmlOptions['baseID']) ? htmlOptions['baseID'] : self.getIdByName(name);
delete (htmlOptions['baseID']);
id=0;
for(d in data)
{
var value=d, labelTitle=data[d]
checked=!strcmp(value,select);
htmlOptions['value']=value;
htmlOptions['id']=baseID+'_'+id++;
option=self.radioButton(name,checked,htmlOptions);
beginLabel=self.openTag('label',labelOptions);
label=self.label(labelTitle,htmlOptions['id'],labelOptions);
endLabel=self.closeTag('label');
items.push(self.strtr(template,{
'{input}':option,
'{beginLabel}':beginLabel,
'{label}':label,
'{labelTitle}':labelTitle,
'{endLabel}':endLabel,
}));
}
if(self.getParent().html.encoder.isEmpty(container))
return implode(separator,items);
else
return self.tag(container,{'id':baseID},implode(separator,items));
},
/**
* Generates a link that can initiate AJAX requests.
* @param string $text the link body (it will NOT be HTML-encoded.)
* @param mixed $url the URL for the AJAX request. If empty, it is assumed to be the current URL. See {@link normalizeUrl} for more details.
* @param object $ajaxOptions AJAX options (see {@link a