Extract name from input inside of string in smarty - html

I was wondering if there is a possibility to extract attributes from a string in Smarty.
Sample:
{$mySmartyArray}
//This array contains
//Array( 0 => "<input name='aaa' />",
// 1 => "<input value='' name='bbb' placeholder='' />",
// 2 => "<input placeholder='foobar' name='ccc' />"
// );
What I want to achieve is something like:
<select name="{$mySmartyArray[0]:attr[name]}">
Of course, I know this looks kind of crap, but I'm looking for some kind of selector.
Or am I supposed to do this with a dirty strpos search ?
Or is a regular expression a possibility?
The task is:
PHP calls some functions and creates the smarty stuff. Now I want to replace the inputs in the array with some select-options.
I'm about to create a smarty plugin to do something like:
<select name="{preg_match value=$mySmartyArray[0] pattern='myRegExHere'}">
<option>...</option>
</select>
Which brings me to my next question: What would be the regex for selecting this?

I added a Plugin to solve my problem:
function smarty_function_preg_match($params, &$smarty)
{
if (!empty($params['pattern']) && !empty($params['subject'])) {
$subject = $params['subject'];
$pattern = "~{$params['pattern']}~";
preg_match($pattern, $subject, $match);
return $match[1];
}
}
The usage is now
{preg_match pattern='name="(.*?)"' subject=$new_item_data.content}
In my case, this returns the name value:
<select name="{preg_match pattern='name="(.*?)"' subject=$new_item_data.content}">
<option>aaa</option>
<option>bbb</option>
</select>

Related

How to generate radio button with label tag completely outside input tag in yii2

Yii2 HTML::radio() helper generate html input tag with label tag around that input like this:
<label>
<input type="radio" name="abc" value="1"> Hello
</label>
But I need it like this:
<input type="radio" name="abc" value="1" id="radio1">
<label for "radio1">Hello</label>
Is it postible to custozime this inside radio helper ?
No, you can't. As you can see from yii\helper\BaseHtml class code, this nesting of tags comes from the source code of radio() method, without means of configuration by changing options.
What you need is override that method. It's really easy.
In the namespace app\helpers, create class Html. Put it into a new file named /Helpers/Html.php relative to your app root (if you've got Yii basic app), and put something like this inside:
namespace app\helpers;
use Yii;
use yii\helpers\BaseHtml;
class Html extends BaseHtml
{
public static function radio($name, $checked = false, $options = [])
{
$options['checked'] = (bool) $checked;
$value = array_key_exists('value', $options) ? $options['value'] : '1';
if (isset($options['uncheck'])) {
// add a hidden field so that if the radio button is not selected, it still submits a value
$hidden = static::hiddenInput($name, $options['uncheck']);
unset($options['uncheck']);
} else {
$hidden = '';
}
if (isset($options['label'])) {
$label = $options['label'];
$labelOptions = isset($options['labelOptions']) ? $options['labelOptions'] : [];
unset($options['label'], $options['labelOptions']);
$content = static::input('radio', $name, $value, $options);
$content .= static::label($label, null, $labelOptions);
return $hidden . $content;
} else {
return $hidden . static::input('radio', $name, $value, $options);
}
}
}
Explanation:
We've just copied the code of radio() method from yii\helpers\BaseHtml and changed the lines containing static::label() to separate output of static::input() from it;
Since both original and our custom classes extend yii\helpers\BaseHtml, and original yii\helpers\Html is not redefining none of BaseHtml methods, there will be no loss in logic for elements other than radio.
Namespace and class name shouldn't be exactly the same, but obviously they should just differ from yii\helpers\Html.
Just replace use yii\helpers\Html; with use app\helpers\Html; in your View code.
That's all!

Build templated directive in AngularJS

I have blocks of HTML like this that repeat tons of time in my code:
<div>
<label for="producer">Producer:</label>
<select id="producer" ng-model="producer" ng-options="producer.name for producer in producers">
<option value="">-- Choose Producer --</option>
</select>
</div>
So I want to make a directive (??) where I could instead do this:
<gsBoundSelect gsLabel="Producer:" gsDefaultOption="-- Choose Producer --"
ng-model="producer"
ng-options="producer.name for producer in producers" />
The for/id fields could just be a random generated string.
I've been reading up on directives but I can't quite figure out exactly how to do this so that I can pass in parameters like this. The examples I've seen all want a bound scope variable passed in vs an attribute.
It seems like I need both a link function and a template, but I'm confused how to do that. Thanks.
Found enough data through various books to get something working. Not sure if it's the best way, but it definitely works:
module.directive('gsBoundSelect', function ($compile) {
function generateUUID() {
...
}
return {
restrict: 'E',
link: function (scope, element, attrs) {
var lblId = generateUUID();
var content = [
'<div>',
' <label for="' + lblId + '">' + attrs.gsLabel + '</label>',
' <select id="' + lblId + '" ng-model="' + attrs.ngModel + '" ng-options="' + attrs.ngOptions + '">',
' <option value="">-- ' + attrs.gsDefaultOption + ' --</option>',
' </select>',
'</div>'].join('');
// We need to transform the content into a jqLite object
var jqLiteElem = angular.element(content);
$compile(jqLiteElem)(scope);
element.replaceWith(jqLiteElem);
}
};
});
As a side-note...I discovered the element directives added must be closed with a full tag, not the shorter syntax like I showed in my example. So the above works with this HTML:
<gsBoundSelect gsLabel="Producer:" gsDefaultOption="-- Choose Producer --"
ng-model="producer"
ng-options="producer.name for producer in producers">
</gsBoundSelect>

How insert raw HTML to label?

Is there some easy way how put raw HTML tag to label? I have this:
{{ Form::label('firstName', 'First name <em>*</em>', array('class' => 'input_tag')) }}
and it produces:
<label class="input_tag" for="firstName">First Name <em>*</em></label>
BUT tag EM is not interpreted as it should be. What I want is:
<label class="input_tag" for="firstName">First Name <em>*</em></label>
use HTML::decode():
{!! HTML::decode(Form::label('firstName', 'First name <em>*</em>', array('class' => 'input_tag'))) !!}
Using sprintf in a macro is much faster than redecoding:
Form::macro('rawLabel', function($name, $value = null, $options = array())
{
$label = Form::label($name, '%s', $options);
return sprintf($label, $value);
});
You can create a helper function (macro) just like:
HTML::macro('raw', function($htmlbuilder) {
return htmlspecialchars_decode($htmlbuilder);
});
in your view:
{{ HTML::raw(Form::label('input_firstname', 'Prénom <sup>*</sup>')) }}
I often use raw html for form input and labels as I find it easier to read and use html5 attributes such as required and placeholder. This form is a good example of how to use raw html with Input::old which allows you to capture old input. https://github.com/Zizaco/confide/blob/master/src/views/login.blade.php
For required inputs, instead of trying to add HTML into the label, I add a class, 'required-input' (or something).
Then I have the following CSS rule
label.required-input:before {
content: ' * ';
color: #f00;
}
This would work unless you are needing to have the <em>*</em> for screen readers. But you can still add the required flag on the input.
Got it, it's using the e() helper function that uses htmlentities() to format your labels and this is converting your tag to &lt;em&gt;*&lt;/em&gt;.
The quick and (very) dirty fix is to add this to your start.php or some other place before the first call to Helpers.php:
function e($value) { return $value; }
But this far from ideal.
I believe the Form::label($name, $value, $attributes, $escape_html) takes a fourth parameter which tells it whether to not to escape html. It defaults to true. So if your expected result is an italic *, pass false as the fourth parameter.

How to make HTML combo box save values added by user in textbox?

I have made a combobox for a web page. It takes values from user into text box & adds those to list on double click in text box. I want to make user entered values permanently stored as option in list. How can I do it. One more question is how can I count the number of options in list so that I add an element next to that.
Here is my code.
<html>
<head>
<script language="javascript">
function AddListItem(form)
{
var TestVar = form.txtInput.value;
form.txtInput.value = "";
form.select.options[3]=new Option(TestVar, TestVar, true);
}
</script>
<head>
<body>
<form id='Form1'>
<input id='txtInput' type='text' maxlength = "5" size="5" ondblclick="AddListItem(this.form)"/>
<p>
<select id='select'>
<option>abc</option>
<option>cde</option>
<option>efg</option>
</select>
</form>
</body>
</html>
To permanently add you need a server-side script.
To temporarily add you can use javascript:
function addVal(newVal) {
var sel = document.getElementById('select');
var opt = document.createElement("OPTION");
sel.addChildNode(opt);
opt.innerHTML = newVal;
opt.value = newVal; //(alternatively)
}
To count the number of options:
function countOpts() {
var sel document.getElementById('select');
return sel.options.length;
}
(only for conceptual use, not tested as functional)
You add an <option> dynamically like this:
function add(selectId, optText, optValue)
{
var newOption = document.createElement("option")
newOption.text = optText;
newOption.value = optValue;
document.getElementById(selectId).options.add(newOption);
}
selectId is the id of <select>, optText is the text to be displayed in the dropdown and optValue is the value that will be sumbitted to the server.
For your code, call it as
<input id='txtInput' type='text' maxlength = "5" size="5" ondblclick="add('select', this.value, this.value)"/>
As you see, you don't really need to find the length of the options, but you can do it via options.length:
document.getElementById(selectId).options.length;
That said,
You might want to add this to the
dropdown, as well as to pass to the
server, to add to some table, for
instance. You might have to do that
call via AJAX, when you add it to
the dropdown
Adding the new item
on double click of the textbox is
not very usable. On blur might be an
option. Better is an 'Add' button after the
textbox .
Sounds like you need a server-side script then. When you submit the form, you can have a field that is 'remembering' all of the dropdown options:
The simplified HTML:
<form method='post' action=''>
<input name='newDDoption' />
<input type='hidden' name='ddStorage' value='<?PHP echo implode("|||",$ddOptions); ?>' />
<button>GO</button>
</form>
The simplified PHP:
<?PHP
$ddOptions = explode("|||",$_POST['ddStorage']);
$ddOptions[] = $_POST['newDDoption'];
echo "<select>";
for($x=0;$x<count($ddOptions);$x++) {
echo "<option>".$ddOptions[$x]."</option>";
}
echo "</select>";
?>
To explain: PHP saves the ddOptions in the form -> User enters new option -> The form is submitted -> PHP finds the stored values -> PHP pushes on the new value -> PHP loops through and creates your permanent dropdown menu.

When submitting a GET form, the query string is removed from the action URL

Consider this form:
<form action="http://www.blabla.com?a=1&b=2" method="GET">
<input type="hidden" name="c" value="3" />
</form>
When submitting this GET form, the parameters a and b are disappearing.
Is there a reason for that?
Is there a way of avoiding this behaviour?
Isn't that what hidden parameters are for to start with...?
<form action="http://www.example.com" method="GET">
<input type="hidden" name="a" value="1" />
<input type="hidden" name="b" value="2" />
<input type="hidden" name="c" value="3" />
<input type="submit" />
</form>
I wouldn't count on any browser retaining any existing query string in the action URL.
As the specifications (RFC1866, page 46; HTML 4.x section 17.13.3) state:
If the method is "get" and the action is an HTTP URI, the user agent takes the value of action, appends a `?' to it, then appends the form data set, encoded using the "application/x-www-form-urlencoded" content type.
Maybe one could percent-encode the action-URL to embed the question mark and the parameters, and then cross one's fingers to hope all browsers would leave that URL as it (and validate that the server understands it too). But I'd never rely on that.
By the way: it's not different for non-hidden form fields. For POST the action URL could hold a query string though.
In HTML5, this is per-spec behaviour.
See Association of controls and forms - Form submission algorithm.
Look at "4.10.22.3 Form submission algorithm", step 17. In the case of a GET form to an http/s URI with a query string:
Let destination be a new URL that is equal to the action except that
its <query> component is replaced by query (adding a U+003F QUESTION
MARK character (?) if appropriate).
So, your browser will trash the existing "?..." part of your URI and replace it with a new one based on your form.
In HTML 4.01, the spec produces invalid URIs - most browsers didn't actually do this though...
See Forms - Processing form data, step four - the URI will have a ? appended, even if it already contains one.
What you can do is using a simple foreach on the table containing the GET information. For example in PHP :
foreach ($_GET as $key => $value) {
$key = htmlspecialchars($key);
$value = htmlspecialchars($value);
echo "<input type='hidden' name='$key' value='$value'/>";
}
As the GET values are coming from the user, we should escape them before printing on screen.
You should include the two items (a and b) as hidden input elements as well as C.
I had a very similar problem where for the form action, I had something like:
<form action="http://www.example.com/?q=content/something" method="GET">
<input type="submit" value="Go away..." />
</form>
The button would get the user to the site, but the query info disappeared so the user landed on the home page rather than the desired content page. The solution in my case was to find out how to code the URL without the query that would get the user to the desired page. In this case my target was a Drupal site, so as it turned out /content/something also worked. I also could have used a node number (i.e. /node/123).
If you need workaround, as this form can be placed in 3rd party systems, you can use Apache mod_rewrite like this:
RewriteRule ^dummy.link$ index.php?a=1&b=2 [QSA,L]
then your new form will look like this:
<form ... action="http:/www.blabla.com/dummy.link" method="GET">
<input type="hidden" name="c" value="3" />
</form>
and Apache will append 3rd parameter to query
When the original query has array, for php:
foreach (explode("\n", http_build_query($query, '', "\n")) as $keyValue) {
[$key, $value] = explode('=', $keyValue, 2);
$key = htmlspecialchars(urldecode($key), ENT_COMPAT | ENT_HTML5);
$value = htmlspecialchars(urldecode($value), ENT_COMPAT | ENT_HTML5);
echo '<input type="hidden" name="' . $key . '" value="' . $value . '"' . "/>\n";
}
To answer your first question yes the browser does that and the reason is
that the browser does not care about existing parameters in the action URL
so it removes them completely
and to prevent this from happening use this JavaScript function that I wrote
using jQuery in:
function addQueryStringAsHidden(form){
if (form.attr("action") === undefined){
throw "form does not have action attribute"
}
let url = form.attr("action");
if (url.includes("?") === false) return false;
let index = url.indexOf("?");
let action = url.slice(0, index)
let params = url.slice(index);
url = new URLSearchParams(params);
for (param of url.keys()){
let paramValue = url.get(param);
let attrObject = {"type":"hidden", "name":param, "value":paramValue};
let hidden = $("<input>").attr(attrObject);
form.append(hidden);
}
form.attr("action", action)
}
My observation
when method is GET and form is submitted, hidden input element was sent as query parmater. Old params in action url were wiped out. So basically in this case, form data is replacing query string in action url
When method is POST, and form is submitted, Query parameters in action url were intact (req.query) and input element data was sent as form data (req.body)
So short story long, if you want to pass query params as well as form data, use method attribute as "POST"
This is in response to the above post by Efx:
If the URL already contains the var you want to change, then it is added yet again as a hidden field.
Here is a modification of that code as to prevent duplicating vars in the URL:
foreach ($_GET as $key => $value) {
if ($key != "my_key") {
echo("<input type='hidden' name='$key' value='$value'/>");
}
}
Your construction is illegal. You cannot include parameters in the action value of a form. What happens if you try this is going to depend on quirks of the browser. I wouldn't be surprised if it worked with one browser and not another. Even if it appeared to work, I would not rely on it, because the next version of the browser might change the behavior.
"But lets say I have parameters in query string and in hidden inputs, what can I do?" What you can do is fix the error. Not to be snide, but this is a little like asking, "But lets say my URL uses percent signs instead of slashes, what can I do?" The only possible answer is, you can fix the URL.
I usually write something like this:
foreach($_GET as $key=>$content){
echo "<input type='hidden' name='$key' value='$content'/>";
}
This is working, but don't forget to sanitize your inputs against XSS attacks!
<form ... action="http:/www.blabla.com?a=1&b=2" method ="POST">
<input type="hidden" name="c" value="3" />
</form>
change the request method to' POST' instead of 'GET'.