Projekt

Allgemein

Profil

Herunterladen (11 KB) Statistiken
| Zweig: | Markierung: | Revision:
2504ebe1 Sven Schöling
package SL::Presenter::Part;

use strict;

2477c498 Moritz Bunkus
use SL::DB::Part;
65d2537d Martin Helmling
use SL::DB::PartClassification;
use SL::Locale::String qw(t8);
0e5e3501 Sven Schöling
use SL::Presenter::EscapedText qw(escape is_escaped);
f95d6823 Bernd Bleßmann
use SL::Presenter::Tag qw(input_tag html_tag name_to_id select_tag link_tag);
2477c498 Moritz Bunkus
2504ebe1 Sven Schöling
use Exporter qw(import);
0e5e3501 Sven Schöling
our @EXPORT_OK = qw(
part_picker part select_classification classification_abbreviation
type_abbreviation separate_abbreviation typeclass_abbreviation
);
our %EXPORT_TAGS = (ALL => \@EXPORT_OK);
f33995ff Geoffrey Richardson
use Carp;

sub part {
0e5e3501 Sven Schöling
my ($part, %params) = @_;
f33995ff Geoffrey Richardson
$params{display} ||= 'inline';

croak "Unknown display type '$params{display}'" unless $params{display} =~ m/^(?:inline|table-cell)$/;

ee51b82f Tamino Steinert
my $text = escape($part->partnumber);
if (! delete $params{no_link}) {
my $href = 'controller.pl?action=Part/edit'
. '&part.id=' . escape($part->id);
$text = link_tag($href, $text, %params);
}
0e5e3501 Sven Schöling
is_escaped($text);
f33995ff Geoffrey Richardson
}
2504ebe1 Sven Schöling
sub part_picker {
0e5e3501 Sven Schöling
my ($name, $value, %params) = @_;
2504ebe1 Sven Schöling
20576aac Sven Schöling
$value = SL::DB::Manager::Part->find_by(id => $value) if $value && !ref $value;
0e5e3501 Sven Schöling
my $id = $params{id} || name_to_id($name);
ee74ea82 Sven Schöling
my @classes = $params{class} ? ($params{class}) : ();
push @classes, 'part_autocomplete';
2504ebe1 Sven Schöling
my $ret =
0e5e3501 Sven Schöling
input_tag($name, (ref $value && $value->can('id') ? $value->id : ''), class => "@classes", type => 'hidden', id => $id,
426a5bf3 Sven Schöling
'data-part-picker-data' => JSON::to_json(\%params),
) .
0e5e3501 Sven Schöling
input_tag("", ref $value ? $value->displayable_name : '', id => "${id}_name", %params);
2504ebe1 Sven Schöling
5aec18fe Sven Schöling
$::request->layout->add_javascripts('kivi.Part.js');
3ac83c61 Moritz Bunkus
$::request->presenter->need_reinit_widgets($id);

0e5e3501 Sven Schöling
html_tag('span', $ret, class => 'part_picker');
2504ebe1 Sven Schöling
}

0e5e3501 Sven Schöling
sub picker { goto &part_picker }

65d2537d Martin Helmling
#
# shortcut for article type
#
sub type_abbreviation {
0e5e3501 Sven Schöling
my ($part_type) = @_;
0ca195cd Bernd Bleßmann
return '' if !$part_type;
65d2537d Martin Helmling
return $::locale->text('Assembly (typeabbreviation)') if $part_type eq 'assembly';
return $::locale->text('Part (typeabbreviation)') if $part_type eq 'part';
return $::locale->text('Assortment (typeabbreviation)') if $part_type eq 'assortment';
return $::locale->text('Service (typeabbreviation)');
}

#
# Translations for Abbreviations:
#
# $::locale->text('None (typeabbreviation)')
# $::locale->text('Purchase (typeabbreviation)')
# $::locale->text('Sales (typeabbreviation)')
# $::locale->text('Merchandise (typeabbreviation)')
# $::locale->text('Production (typeabbreviation)')
#
# and for descriptions
# $::locale->text('Purchase')
# $::locale->text('Sales')
# $::locale->text('Merchandise')
# $::locale->text('Production')

#
# shortcut for article type
#
sub classification_abbreviation {
0e5e3501 Sven Schöling
my ($id) = @_;
0ca195cd Bernd Bleßmann
return '' if !$id;

65d2537d Martin Helmling
SL::DB::Manager::PartClassification->cache_all();
my $obj = SL::DB::PartClassification->load_cached($id);
$obj && $obj->abbreviation ? t8($obj->abbreviation) : '';
}

ea1c5dfb Martin Helmling
sub typeclass_abbreviation {
0e5e3501 Sven Schöling
my ($part) = @_;
ea1c5dfb Martin Helmling
return '' if !$part || !$part->isa('SL::DB::Part');
0e5e3501 Sven Schöling
return type_abbreviation($part->part_type) . classification_abbreviation($part->classification_id);
ea1c5dfb Martin Helmling
}

219d88ab Martin Helmling
#
# shortcut for article type
#
sub separate_abbreviation {
0e5e3501 Sven Schöling
my ($id) = @_;
0ca195cd Bernd Bleßmann
return '' if !$id;

219d88ab Martin Helmling
SL::DB::Manager::PartClassification->cache_all();
my $obj = SL::DB::PartClassification->load_cached($id);
$obj && $obj->abbreviation && $obj->report_separate ? t8($obj->abbreviation) : '';
}

65d2537d Martin Helmling
#
# generate selection tag
#
sub select_classification {
0e5e3501 Sven Schöling
my ($name, %attributes) = @_;
ce904bd6 Geoffrey Richardson
65d2537d Martin Helmling
$attributes{value_key} = 'id';
$attributes{title_key} = 'description';
ce904bd6 Geoffrey Richardson
my $classification_type_filter = delete $attributes{type} // [];

my $collection = SL::DB::Manager::PartClassification->get_all_sorted( where => $classification_type_filter );
65d2537d Martin Helmling
$_->description($::locale->text($_->description)) for @{ $collection };
0e5e3501 Sven Schöling
select_tag( $name, $collection, %attributes );
65d2537d Martin Helmling
}

2504ebe1 Sven Schöling
1;
9aaadfdc Sven Schöling
__END__

=encoding utf-8

=head1 NAME

f33995ff Geoffrey Richardson
SL::Presenter::Part - Part related presenter stuff
9aaadfdc Sven Schöling
=head1 SYNOPSIS

f33995ff Geoffrey Richardson
# Create an html link for editing/opening a part/service/assembly
5eb16622 Geoffrey Richardson
my $object = SL::DB::Manager::Part->get_first;
f33995ff Geoffrey Richardson
my $html = SL::Presenter->get->part($object, display => 'inline');

see also L<SL::Presenter>
9aaadfdc Sven Schöling
=head1 DESCRIPTION

see L<SL::Presenter>

=head1 FUNCTIONS

f33995ff Geoffrey Richardson
=over 2

=item C<part, $object, %params>

Returns a rendered version (actually an instance of
L<SL::Presenter::EscapedText>) of the part object C<$object>

ee51b82f Tamino Steinert
Remaining C<%params> are passed to the function
C<SL::Presenter::Tag::link_tag>. It can include:
f33995ff Geoffrey Richardson
9aaadfdc Sven Schöling
=over 4

f33995ff Geoffrey Richardson
=item * display

ee51b82f Tamino Steinert
Either C<inline> (the default) or C<table-cell>. Is passed to the function
C<SL::Presenter::Tag::link_tag>.

=item * no_link

If falsish (the default) then the part number will be linked to the "edit"
dialog.
f33995ff Geoffrey Richardson
=back

2f6a11fb Bernd Bleßmann
=back
f33995ff Geoffrey Richardson
=over 2

65d2537d Martin Helmling
=item C<classification_abbreviation $classification_id>

Returns the shortcut of the classification

=back

=over 2

219d88ab Martin Helmling
=item C<separate_abbreviation $classification_id>

5eb16622 Geoffrey Richardson
Returns the shortcut of the classification if the classification has the separate flag set.
219d88ab Martin Helmling
=back

=over 2

65d2537d Martin Helmling
=item C<select_classification $name,%params>

5eb16622 Geoffrey Richardson
Returns an HTML select tag with all available classifications.
65d2537d Martin Helmling
C<%params> can include:

=over 4

=item * default

5eb16622 Geoffrey Richardson
The id of the selected item.
65d2537d Martin Helmling
=back

=back

=over 2

9e278d06 Moritz Bunkus
=item C<part_picker $name, $value, %params>
9aaadfdc Sven Schöling
9e278d06 Moritz Bunkus
All-in-one picker widget for parts. The name will be both id and name
of the resulting hidden C<id> input field (but the ID can be
overwritten with C<$params{id}>).
9aaadfdc Sven Schöling
9e278d06 Moritz Bunkus
An additional dummy input will be generated which is used to find
976b1ddf Geoffrey Richardson
parts. For a detailed description of its behaviour, see section
9e278d06 Moritz Bunkus
C<PART PICKER SPECIFICATION>.
9aaadfdc Sven Schöling
9e278d06 Moritz Bunkus
C<$value> can be a parts id or a C<Rose::DB:Object> instance.
9aaadfdc Sven Schöling
862bc8ce Geoffrey Richardson
If C<%params> contains C<part_type> only parts of this type will be used
9e278d06 Moritz Bunkus
for autocompletion. You may comma separate multiple types as in
C<part,assembly>.
9aaadfdc Sven Schöling
2de6b963 Bernd Bleßmann
If C<%params> contains C<status> only parts of this status will be used
for autocompletion. C<status> can be one of the following strings:
C<active>, C<obsolete> or C<all>. C<active> is the default if C<status> is
not given.

880a2e9f Moritz Bunkus
If C<%params> contains C<unit> only parts with this unit will be used
for autocompletion. You may comma separate multiple units as in
C<h,min>.
9aaadfdc Sven Schöling
df33875f Moritz Bunkus
If C<%params> contains C<convertible_unit> only parts with a unit
that's convertible to unit will be used for autocompletion.
9aaadfdc Sven Schöling
0c73b206 Bernd Bleßmann
If C<%params> contains C<with_makemodel> or C<with_customer_partnumber> even
parts will be used for autocompletion which partnumber is a vendor partnumber
(makemodel) or a customer partnumber.

65e51d8e Bernd Bleßmann
If C<%params> contains C<multiple> an alternative popup will be opened,
allowing multiple items to be selected. Note however that this requires
an additional callback C<set_multi_items> to work.
Also note that you can set C<multiple> to 0 (or not set C<multiple>) on
creation of the picker, but can open the alternative multi select popup
with js like this:
C<$("#pp_id").data("part_picker").o.multiple=1; $("#pp_id").data("part_picker").open_dialog()'>
where C<pp_id> is the dom id of the part picker.
Or you can even do it the other way round setting C<multiple> to 1 on creation
and open a single selection popup with js.

4af0680d Bernd Bleßmann
If C<%params> contains C<multiple_pos_input> an input field with the dom id
C<multi_items_position> will be rendered in the alternative popup.
This can be used in the callback for C<set_multi_items> to controll the
input postion for the items.

8c30110b Bernd Bleßmann
If C<%params> contains C<multiple_limit> the alternative popup will not
show any results if there are more than C<multiple_limit> results. A warning
message is displayed in this case. Set C<multiple_limit> to 0 to disable
the limitation. The limit defaults to 100.

976b1ddf Geoffrey Richardson
Obsolete parts will by default not be displayed for selection. However they are
58e12eca Sven Schöling
accepted as default values and can persist during updates. As with other
5c48c74b Sven Schöling
selectors though, they are not selectable once overridden.
58e12eca Sven Schöling
c89986ac Sven Schöling
C<part_picker> will register it's javascript for inclusion in the next header
5162c8cc Sven Schöling
rendering. If you write a standard controller that only calls C<render> once, it
will just work. In case the header is generated in a different render call
5aa4c453 Bernd Bleßmann
(multiple blocks, ajax, old C<bin/mozilla> style controllers) you need to
5aec18fe Sven Schöling
include C<kivi.Part.js> yourself.
9aaadfdc Sven Schöling
5162c8cc Sven Schöling
On pressing <enter> the picker will try to commit the current selection,
resulting in one of the following events, whose corresponding callbacks can be
set in C<params.actions>:

=over 4

=item * C<commit_one>

5eb16622 Geoffrey Richardson
If exactly one element matches the input, the internal id will be set to this
id, the internal state will be set to C<PICKED> and the C<change> event on the
picker will be fired. Additionally, if C<params> contains C<fat_set_item> a
special event C<set_item:PartPicker> will be fired which is guaranteed to
5162c8cc Sven Schöling
contain a complete JSON representation of the part.

After that the action C<commit_one> will be executed, which defaults to
clicking a button with id C<update_button> for backward compatibility reasons.

=item * C<commit_many>

If more than one element matches the input, the internal state will be set to
undefined.

After that the action C<commit_one> will be executed, which defaults to
65e51d8e Bernd Bleßmann
opening a popup dialog for graphical interaction.
5162c8cc Sven Schöling
=item * C<commit_none>

If no element matches the input, the internal state will be set to undefined.

If an action for C<commit_none> exists, it will be called with the picker
object and current term. The caller can then implement creation of new parts.

=back

9aaadfdc Sven Schöling
=back

81e4602d Sven Schöling
=head1 PART PICKER SPECIFICATION

The following list of design goals were applied:

=over 4

=item *

Parts should not be perceived by the user as distinct inputs of partnumber and
description but as a single object

=item *

Easy to use without documentation for novice users

=item *

Fast to use with keyboard for experienced users

=item *

Possible to use without any keyboard interaction for mouse (or touchscreen)
users

=item *

Must not leave the current page in event of ambiguity (cf. current select_item
mechanism)

=item *

Should be useable with hand scanners or similar alternative keyboard devices

=item *

Should not require a feedback/check loop in the common case

=item *

976b1ddf Geoffrey Richardson
Should not be constrained to exact matches
81e4602d Sven Schöling
5162c8cc Sven Schöling
=item *

Must be atomic

=item *

Action should be overridable

81e4602d Sven Schöling
=back

The implementation consists of the following parts which will be referenced later:

=over 4

=item 1

A hidden input (id input), used to hold the id of the selected part. The only
input that gets submitted

=item 2

An input (dummy input) containing a description of the currently selected part,
also used by the user to search for parts

=item 3

A jquery.autocomplete mechanism attached to the dummy field

=item 4

A popup layer for both feedback and input of additional data in case of
ambiguity.

=item 5

976b1ddf Geoffrey Richardson
An internal status of the part picker, indicating whether id input and dummy
81e4602d Sven Schöling
input are consistent. After leaving the dummy input the part picker must
place itself in a consistent status.

=item 6

A clickable icon (popup trigger) attached to the dummy input, which triggers the popup layer.

=back

9aaadfdc Sven Schöling
=head1 BUGS

686cf1ec Sven Schöling
None atm :)
9aaadfdc Sven Schöling
=head1 AUTHOR

Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>

65d2537d Martin Helmling
Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>

9aaadfdc Sven Schöling
=cut