TopQuickSearch: Doku
[kivitendo-erp.git] / SL / Controller / TopQuickSearch.pm
1 package SL::Controller::TopQuickSearch;
2
3 use strict;
4 use parent qw(SL::Controller::Base);
5
6 use SL::ClientJS;
7 use SL::JSON;
8 use SL::Locale::String qw(t8);
9
10 use Rose::Object::MakeMethods::Generic (
11  'scalar --get_set_init' => [ qw(module js) ],
12 );
13
14 my @available_modules = (
15   'SL::Controller::TopQuickSearch::Article',
16   'SL::Controller::TopQuickSearch::Part',
17   'SL::Controller::TopQuickSearch::Service',
18   'SL::Controller::TopQuickSearch::Assembly',
19   'SL::Controller::TopQuickSearch::Contact',
20   'SL::Controller::TopQuickSearch::GLTransaction',
21 );
22 my %modules_by_name;
23
24 sub action_query_autocomplete {
25   my ($self) = @_;
26
27   my $hashes = $self->module->query_autocomplete;
28
29   $self->render(\ SL::JSON::to_json($hashes), { layout => 0, type => 'json', process => 0 });
30 }
31
32 sub action_select_autocomplete {
33   my ($self) = @_;
34
35   my $redirect_url = $self->module->select_autocomplete;
36
37   $self->js->redirect_to($redirect_url)->render;
38 }
39
40 sub action_do_search {
41   my ($self) = @_;
42
43   my $redirect_url = $self->module->do_search;
44
45   if ($redirect_url) {
46     $self->js->redirect_to($redirect_url)
47   }
48
49   $self->js->render;
50 }
51
52 sub available_modules {
53   my ($self) = @_;
54
55   $self->require_modules;
56
57   map { $_->new } @available_modules;
58 }
59
60 sub enabled_modules {
61   my %enabled_names = map {
62     $_ => 1
63   } @{ $::instance_conf->get_quick_search_modules };
64
65   grep {
66     $enabled_names{$_->name}
67   } $_[0]->available_modules
68 }
69
70 sub active_modules {
71   grep {
72     $::auth->assert($_->auth, 1)
73   } $_[0]->enabled_modules
74 }
75
76 sub init_module {
77   my ($self) = @_;
78
79   $self->require_modules;
80
81   die 'Need module' unless $::form->{module};
82
83   die 'Unknown module ' . $::form->{module} unless my $class = $modules_by_name{$::form->{module}};
84
85   $::auth->assert($class->auth);
86
87   return $class->new;
88 }
89
90 sub init_js {
91   SL::ClientJS->new(controller => $_[0])
92 }
93
94 sub require_modules {
95   my ($self) = @_;
96
97   if (!$self->{__modules_required}) {
98     for my $class (@available_modules) {
99       eval "require $class" or die $@;
100       $modules_by_name{ $class->name } = $class;
101     }
102     $self->{__modules_required} = 1;
103   }
104 }
105
106 1;
107
108 __END__
109
110 =encoding utf-8
111
112 =head1 NAME
113
114 SL::Controller::TopQuickSearch - Framework for pluggable quicksearch fields in the layout top header.
115
116 =head1 SYNOPSIS
117
118   use SL::Controller::TopQuickSearch;
119   my $search = SL::Controller::TopQuickSearch->new;
120   $::request->layout->add_javascripts('kivi.QuickSearch.js');
121
122   # in template
123   [%- FOREACH module = search.enabled_modules %]
124   <input type='text' id='top-search-[% module.name %]'>
125   [%- END %]
126
127 =head1 DESCRIPTION
128
129 This controller provides abstraction for different search plugins, and ensures
130 that all follow a common useability scheme.
131
132 Modules should be configurable per user, but currently are not. Disabling
133 modules can be done by removing them from available_modules or in client_config.
134
135 =head1 BEHAVIOUR REQUIREMENTS
136
137 =over 4
138
139 =item *
140
141 A single text input field with the html5 placeholder containing a small
142 description of the target will be rendered from the plugin information.
143
144 =item *
145
146 On typing, the autocompletion must be enabled.
147
148 =item *
149
150 On C<Enter>, the search should redirect to an appropriate listing of matching
151 results.
152
153 If only one item matches the result, the plugin should instead redirect
154 directly to the matched item.
155
156 =item *
157
158 Search terms should accept the broadest possible matching, and if possible with
159 C<multi> parsing.
160
161 =item *
162
163 In case nothing is found, a visual indicator should be given, but no actual
164 redirect should occur.
165
166 =item *
167
168 Each search must check rights and must not present a backdoor into data that
169 the user should not see.
170
171 =item *
172
173 By design the search must not try to guess C<exact matches>.
174
175 =back
176
177 =head1 INTERFACE
178
179 The full interface is described in L<SL::Controller::TopQuickSeach::Base>
180
181 =head1 TODO
182
183   * user configuration
184   * searches for orders, customers, vendors
185
186 =head1 BUGS
187
188 None yet :)
189
190 =head1 AUTHOR
191
192 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
193
194 =cut