View | Details | Raw Unified | Return to bug 14242
Collapse All | Expand All

(-)a/installer/data/mysql/atomicupdate/bug_14242-autofill_syspref.sql (+1 lines)
Line 0 Link Here
1
INSERT IGNORE INTO systempreferences (`variable`, `value`, `options`, `explanation`,`type`) VALUES ('OPACAutoFill', '0', NULL, 'Automaticly fill forms with data from Google Books API','YesNo');
(-)a/installer/data/mysql/sysprefs.sql (+1 lines)
Lines 329-334 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
329
('OAI-PMH:DeletedRecord','persistent','Koha\'s deletedbiblio table will never be deleted (persistent), might be deleted (transient), or will never have any data in it (no)','transient|persistent|no','Choice'),
329
('OAI-PMH:DeletedRecord','persistent','Koha\'s deletedbiblio table will never be deleted (persistent), might be deleted (transient), or will never have any data in it (no)','transient|persistent|no','Choice'),
330
('OAI-PMH:MaxCount','50',NULL,'OAI-PMH maximum number of records by answer to ListRecords and ListIdentifiers queries','Integer'),
330
('OAI-PMH:MaxCount','50',NULL,'OAI-PMH maximum number of records by answer to ListRecords and ListIdentifiers queries','Integer'),
331
('OPACAcquisitionDetails','0','','Show the acquisition details at the OPAC','YesNo'),
331
('OPACAcquisitionDetails','0','','Show the acquisition details at the OPAC','YesNo'),
332
('OPACAutoFill','0',NULL,'Automaticly fill forms with data from Google Books API','YesNo'),
332
('OpacAddMastheadLibraryPulldown','0','','Adds a pulldown menu to select the library to search on the opac masthead.','YesNo'),
333
('OpacAddMastheadLibraryPulldown','0','','Adds a pulldown menu to select the library to search on the opac masthead.','YesNo'),
333
('OpacAdvSearchMoreOptions','pubdate,itemtype,language,subtype,sorting,location','Show search options for the expanded view (More options)','pubdate|itemtype|language|subtype|sorting|location','multiple'),
334
('OpacAdvSearchMoreOptions','pubdate,itemtype,language,subtype,sorting,location','Show search options for the expanded view (More options)','pubdate|itemtype|language|subtype|sorting|location','multiple'),
334
('OpacAdvSearchOptions','pubdate,itemtype,language,sorting,location','Show search options','pubdate|itemtype|language|subtype|sorting|location','multiple'),
335
('OpacAdvSearchOptions','pubdate,itemtype,language,sorting,location','Show search options','pubdate|itemtype|language|subtype|sorting|location','multiple'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref (+7 lines)
Lines 513-518 OPAC: Link Here
513
                  no: Don't display
513
                  no: Don't display
514
            - a branch selection list for news items in the OPAC.
514
            - a branch selection list for news items in the OPAC.
515
        -
515
        -
516
            - pref: OPACAutoFill
517
              default: 0
518
              choices:
519
                  yes: Enable
520
                  no: Disable
521
            - automatic form filling with data from Google Books API.
522
        -
516
            - "Use the following as the OPAC ISBD template:"
523
            - "Use the following as the OPAC ISBD template:"
517
            - pref: OPACISBD
524
            - pref: OPACISBD
518
              type: textarea
525
              type: textarea
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/includes/opac-bottom.inc (+4 lines)
Lines 250-255 $.widget.bridge('uitooltip', $.ui.tooltip); Link Here
250
    </script>
250
    </script>
251
[% END %]
251
[% END %]
252
252
253
[% IF ( Koha.Preference('OPACAutoFill') ) %]
254
    <script type="text/javascript" src="[% interface %]/[% theme %]/js/autofill.js"></script>
255
[% END %]
256
253
[% IF ( BakerTaylorEnabled ) %]
257
[% IF ( BakerTaylorEnabled ) %]
254
    [% Asset.js("js/bakertaylorimages.js") | $raw %]
258
    [% Asset.js("js/bakertaylorimages.js") | $raw %]
255
    <script>
259
    <script>
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-suggestions.tt (-2 / +22 lines)
Lines 41-47 Link Here
41
                            <p>Only certain fields (marked in red) are required, but the more information you enter the easier it will be for the librarians to find the title you're requesting. The "Notes" field can be used to provide any additional information.</p>
41
                            <p>Only certain fields (marked in red) are required, but the more information you enter the easier it will be for the librarians to find the title you're requesting. The "Notes" field can be used to provide any additional information.</p>
42
42
43
                            <form action="/cgi-bin/koha/opac-suggestions.pl" method="post" id="add_suggestion_form">
43
                            <form action="/cgi-bin/koha/opac-suggestions.pl" method="post" id="add_suggestion_form">
44
                                <fieldset class="rows">
44
                                [% IF Koha.Preference( 'OPACAutoFill' ) %]
45
                                <fieldset class="rows well" style="margin-bottom: 3em;padding-top: 5px;">
46
                                    <label for="isbn">Standard number (ISBN, ISSN or other):</label><input type="text" id="isbn" name="isbn"  maxlength="80" />
47
                                </fieldset>
48
                                [% END %]
49
                                    <fieldset class="rows [% IF Koha.Preference( 'OPACAutoFill' ) %]well[% END %]">
45
                                    <ol>
50
                                    <ol>
46
                                        <li><label for="title">Title:</label><input type="text" id="title" name="title" class="span6" maxlength="255" /></li>
51
                                        <li><label for="title">Title:</label><input type="text" id="title" name="title" class="span6" maxlength="255" /></li>
47
                                        <li><label for="author">Author:</label><input type="text" id="author" name="author" class="span6" maxlength="80" /></li>
52
                                        <li><label for="author">Author:</label><input type="text" id="author" name="author" class="span6" maxlength="80" /></li>
Lines 50-56 Link Here
50
                                            <label for="copyrightdate">Copyright date:</label><input type="text" id="copyrightdate" name="copyrightdate" pattern="[12]\d{3}" size="4" maxlength="4" />
55
                                            <label for="copyrightdate">Copyright date:</label><input type="text" id="copyrightdate" name="copyrightdate" pattern="[12]\d{3}" size="4" maxlength="4" />
51
                                            </div>
56
                                            </div>
52
                                        </li>
57
                                        </li>
53
                                        <li><label for="isbn">Standard number (ISBN, ISSN or other):</label><input type="text" id="isbn" name="isbn"  maxlength="80" /></li>
58
                                        [% IF NOT Koha.Preference( 'OPACAutoFill' ) %]
59
                                        <li><label for="isbn">Standard number (ISBN, ISSN or other):</label><input type="text" id="isbn" name="isbn" maxlength="80" /></li>
60
                                        [% END %]
54
                                        <li><label for="publishercode">Publisher:</label><input type="text" id="publishercode" name="publishercode" class="span6" maxlength="80" /></li>
61
                                        <li><label for="publishercode">Publisher:</label><input type="text" id="publishercode" name="publishercode" class="span6" maxlength="80" /></li>
55
                                        <li><label for="collectiontitle">Collection title:</label><input type="text" id="collectiontitle" name="collectiontitle" class="span6" maxlength="80" /></li>
62
                                        <li><label for="collectiontitle">Collection title:</label><input type="text" id="collectiontitle" name="collectiontitle" class="span6" maxlength="80" /></li>
56
                                        <li><label for="place">Publication place:</label><input type="text" id="place" name="place"  maxlength="80" /></li>
63
                                        <li><label for="place">Publication place:</label><input type="text" id="place" name="place"  maxlength="80" /></li>
Lines 293-298 Link Here
293
        }
300
        }
294
    [% END %]
301
    [% END %]
295
302
303
    [% IF Koha.Preference( 'OPACAutoFill' ) %]
304
    $(function() {
305
        $('#isbn').autofill({
306
            'volumeInfo.title': {target: 'title', effect: 'flash'},
307
            'volumeInfo.authors': {target: 'author', effect: 'flash'},
308
            'volumeInfo.publisher': {target: 'publishercode', effect: 'flash'},
309
            /* google books api seem to only have books, so if we got a result
310
             * item, type will be a book, so set to BK (book). */
311
            'kind': {target: 'itemtype', handle: function(t,v) { t.val('BK'); },},
312
        });
313
    });
314
    [% END %]
315
296
    $(function() {
316
    $(function() {
297
        $("#suggestt").dataTable($.extend(true, {}, dataTablesDefaults, {
317
        $("#suggestt").dataTable($.extend(true, {}, dataTablesDefaults, {
298
            "order": [[ 1, "asc" ]],
318
            "order": [[ 1, "asc" ]],
(-)a/koha-tmpl/opac-tmpl/bootstrap/js/autofill.js (-1 / +202 lines)
Line 0 Link Here
0
- 
1
/*
2
 * jQuery autofill plugin
3
 *
4
 * Automaticly fills form inputs with relevant data based on search result
5
 */
6
7
(function ($) {
8
    function typeString(o) {
9
        if (typeof o != 'object')
10
            return typeof o;
11
12
        if (o === null)
13
            return "null";
14
15
        //object, array, function, date, regexp, string, number, boolean, error
16
        var internalClass = Object.prototype.toString.call(o)
17
            .match(/\[object\s(\w+)\]/)[1];
18
19
        return internalClass.toLowerCase();
20
    }
21
22
    var AutoFiller = function (elm, fields, type) {
23
        var self = this;
24
        self.type = type;
25
        self.$elm = $(elm);
26
        self.fields = fields;
27
28
        /* decorate element as autofiller */
29
        var $inputgroup = $('<div class="input-prepend">');
30
        self.$undo = $('<span class="add-on" style="display:none;cursor:pointer;">undo</span>');
31
        self.$fillbtn = $('<span class="add-on"><i class="icon-edit" style="cursor:pointer;"></i></span>');
32
        self.$error = $('<span class="add-on" style="display:none;"></span>');
33
        self.$elm.wrap($inputgroup);
34
        self.$elm.after(self.$error);
35
        self.$elm.after(self.$undo);
36
        self.$elm.after(self.$fillbtn);
37
38
        for(var key in fields) {
39
            if( fields.hasOwnProperty(key) && typeof fields[key] === 'object' ) {
40
                var $target = $('#' + self.fields[key].target);
41
                self.fields[key].$target = $target;
42
            }
43
        }
44
45
        self.$fillbtn.click(function(){
46
            /* only allow forced update once every second */
47
            if(Date.now() - self.lastupdate > 1000) {
48
                self.$elm.trigger('change');
49
            }
50
        });
51
52
        self.$undo.click(function(){
53
            for(var key in self.fields) {
54
                var field = self.fields[key];
55
                field.$target.trigger('autofill-undo');
56
            }
57
            self.$undo.hide();
58
        });
59
60
        self.$elm.change(function() {
61
            self.lastupdate = Date.now();
62
            self.$error.html('');
63
            self.$error.hide();
64
            /* give user some feedback that the request is in progress */
65
            self.$fillbtn.fadeOut(1000).fadeIn(1000);
66
67
            var gAPI = 'https://www.googleapis.com/books/v1/volumes?q=';
68
            if(self.type)
69
                gAPI += self.type + ':';
70
            gAPI += self.$elm.val();
71
            gAPI += '&maxResults=1';
72
73
            $.getJSON(gAPI, function (response) {
74
                if(response.totalItems == 0) {
75
                    self.$error.html('Sorry, nothing found.');
76
                    self.$error.show();
77
                    return;
78
                }
79
80
                var undos = 0;
81
                var item = response.items[0];
82
                for(var key in self.fields) {
83
                    var filled = false;
84
                    var value = eval('item.'+key);
85
                    var field = self.fields[key];
86
87
                    /* field handled by caller */
88
                    if('handle' in field) {
89
                        if(typeof field.handle === 'function')
90
                            field.handle(field.$target, value);
91
92
                        continue; /* next please */
93
                    }
94
95
                    /* wouldn't know what to do with result unless we have a
96
                     * target */
97
                    if( ! field.$target )
98
                        continue;
99
100
                    /* handle differently depending on datatype */
101
                    switch(typeString(value)) {
102
                        case 'array':
103
                            switch(field.$target.prop('nodeName').toUpperCase()) {
104
                                case 'TEXTAREA':
105
                                    undos++;
106
                                    field.$target.bind('autofill-undo', field.$target.text(), function(e){$(this).text(e.data);});
107
                                    field.$target.text(value.join(', '));
108
                                    break;
109
                                case 'INPUT':
110
                                default:
111
                                    undos++;
112
                                    field.$target.bind('autofill-undo', field.$target.val(), function(e){$(this).val(e.data);});
113
                                    field.$target.val(value.join(', '));
114
                                    break;
115
                            }
116
                            break;
117
                        default:
118
                            switch(field.$target.prop('nodeName').toUpperCase()) {
119
                                case 'TEXTAREA':
120
                                    undos++;
121
                                    field.$target.bind('autofill-undo', field.$target.text(), function(e){$(this).text(e.data);});
122
                                    field.$target.text(value);
123
                                    break;
124
                                case 'SELECT':
125
                                case 'INPUT':
126
                                default:
127
                                    undos++;
128
                                    field.$target.bind('autofill-undo', field.$target.val(), function(e){$(this).val(e.data);});
129
                                    field.$target.val(value);
130
                                    break;
131
                            }
132
                    }
133
134
                    switch(field.effect) {
135
                        case 'flash':
136
                            field.$target.fadeOut(500).fadeIn(500);
137
                            break;
138
                    }
139
                }
140
141
                if(undos > 0)
142
                    self.$undo.show();
143
144
            });
145
        });
146
    };
147
148
    /*
149
     * @fields object: Google Books API item propreties map for
150
     *                 mapping against a target element. Expected
151
     *                 type:
152
     *                 {
153
     *                  GoogleBooksItem.property: {target: ELEM,
154
     *                                             handle: function(target, value),
155
     *                                             effect: jQuery effects,
156
     *                                            }
157
     *                 }
158
     *
159
     *                 "target" is optional and if specified alone (i.e no
160
     *                 handle proprety) autofill will automaticly fill this
161
     *                 target element with returned data.
162
     *
163
     *                 "handle" is optional and will be called when ajax request
164
     *                 has finished and target is matched. Function specifies
165
     *                 two arguments: target and value. Target is the target
166
     *                 element specified by "target" and value is the value
167
     *                 returned by Google Books API for the matched property.
168
     *
169
     *                 If a handle function is given, full control of result data
170
     *                 is given to the handle function.
171
     *
172
     *                 "effect" is optional and specifies effect name of effect
173
     *                 to use for the target once value has been set. Can be one of:
174
     *
175
     *                      - 'flash'
176
     *
177
     * @type string: defines the query type, default to input name
178
     *               For example <input type="text" name="isbn"></input>
179
     *               will search for isbn by default
180
     *
181
     * @EXAMPLE
182
     *
183
     *  $('#isbn').autofill({
184
     *      'volumeInfo.title': {target: 'title', effect: 'flash'},
185
     *      'volumeInfo.authors': {target: 'author'},
186
     *      'volumeInfo.publisher': {target: 'publishercode'},
187
     *      'selfLink': {handle: function(t,v){window.location=v;}}
188
     *  });
189
     * */
190
    $.fn.autofill = function(fields, type) {
191
        if(type === undefined) // default to input name
192
            type = this.attr('name');
193
194
        return this.each(function(i){
195
            var plugin = $.data(this, "plugin_autofill");
196
            if (plugin)
197
                plugin.destroy();
198
199
            $.data(this, "plugin_autofill", new AutoFiller(this, fields, type));
200
        });
201
    };
202
}(jQuery));

Return to bug 14242