+ my ($self, $name, $value, %attributes) = _hashify(3, @_);
+
+ my $cols = delete $attributes{cols} || delete $attributes{size};
+ my $minrows = delete $attributes{min_rows} || 1;
+ my $maxrows = delete $attributes{max_rows};
+ my $rows = $::form->numtextrows($value, $cols, $maxrows, $minrows);
+
+ $attributes{id} ||= _tag_id();
+ my $id = $attributes{id};
+
+ return $self->textarea_tag($name, $value, %attributes, rows => $rows, cols => $cols) if $rows > 1;
+
+ return '<span>'
+ . $self->input_tag($name, $value, %attributes, size => $cols)
+ . "<img src=\"image/edit-entry.png\" onclick=\"kivi.switch_areainput_to_textarea('${id}')\" style=\"margin-left: 2px;\">"
+ . '</span>';
+}
+
+sub multiselect2side {
+ my ($self, $id, %params) = _hashify(2, @_);
+
+ $params{labelsx} = "\"" . _J($params{labelsx} || $::locale->text('Available')) . "\"";
+ $params{labeldx} = "\"" . _J($params{labeldx} || $::locale->text('Selected')) . "\"";
+ $params{moveOptions} = 'false';
+
+ my $vars = join(', ', map { "${_}: " . $params{$_} } keys %params);
+ my $code = <<EOCODE;
+<script type="text/javascript">
+ \$().ready(function() {
+ \$('#${id}').multiselect2side({ ${vars} });
+ });
+</script>
+EOCODE
+
+ return $code;
+}
+
+sub sortable_element {
+ my ($self, $selector, %params) = _hashify(2, @_);
+
+ my %attributes = ( distance => 5,
+ helper => <<'JAVASCRIPT' );
+ function(event, ui) {
+ ui.children().each(function() {
+ $(this).width($(this).width());
+ });
+ return ui;
+ }
+JAVASCRIPT
+
+ my $stop_event = '';
+
+ if ($params{url} && $params{with}) {
+ my $as = $params{as} || $params{with};
+ my $filter = ".filter(function(idx) { return this.substr(0, " . length($params{with}) . ") == '$params{with}'; })";
+ $filter .= ".map(function(idx, str) { return str.replace('$params{with}_', ''); })";
+
+ my $params_js = $params{params} ? qq| + ($params{params})| : '';
+ my $ajax_return = '';
+ if ($params{ajax_return}) {
+ $ajax_return = 'kivi.eval_json_result';
+ }
+
+ $stop_event = <<JAVASCRIPT;
+ \$.post('$params{url}'${params_js}, { '${as}[]': \$(\$('${selector}').sortable('toArray'))${filter}.toArray() }, $ajax_return);
+JAVASCRIPT
+ }
+
+ if (!$params{dont_recolor}) {
+ $stop_event .= <<JAVASCRIPT;
+ \$('${selector}>*:odd').removeClass('listrow1').removeClass('listrow0').addClass('listrow0');
+ \$('${selector}>*:even').removeClass('listrow1').removeClass('listrow0').addClass('listrow1');
+JAVASCRIPT
+ }
+
+ if ($stop_event) {
+ $attributes{stop} = <<JAVASCRIPT;
+ function(event, ui) {
+ ${stop_event}
+ return ui;
+ }
+JAVASCRIPT
+ }