]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/URLVerify/CreateSession.js
Link checker: URL extraction bugfix and usability improvements
[working/Evergreen.git] / Open-ILS / web / js / dojo / openils / URLVerify / CreateSession.js
1 if (!dojo._hasResource["openils.URLVerify.CreateSession"]) {
2     dojo.require("dojo.data.ItemFileWriteStore");
3     dojo.require("dojox.jsonPath");
4     dojo.require("fieldmapper.OrgUtils");
5     dojo.require("openils.Util");
6     dojo.require("openils.CGI");
7     dojo.require("openils.PermaCrud");
8     dojo.require("openils.widget.FilteringTreeSelect");
9     dojo.require("openils.URLVerify.Verify");
10
11     dojo.requireLocalization("openils.URLVerify", "URLVerify");
12
13     dojo._hasResource["openils.URLVerify.CreateSession"] = true;
14     dojo.provide("openils.URLVerify.CreateSession");
15
16     dojo.declare("openils.URLVerify.CreateSession", null, {});
17
18     /* Take care that we add nothing to the global namespace. */
19
20 (function() {
21     var module = openils.URLVerify.CreateSession;
22     var localeStrings =
23         dojo.i18n.getLocalization("openils.URLVerify", "URLVerify");
24     var uvus_progress = 0;
25
26     /* Take search text box input, selected saved search ids, and selected
27      * scope shortname to produce one search string. */
28     module._prepare_search = function(basic, saved, scope) {
29         if (saved.length) {
30             basic += " " + dojo.map(
31                 saved, function(s) { return "saved_query(" + s + ")"; }
32             ).join(" ");
33         }
34
35         if (scope && !basic.match(/site\(.+\)/))
36             basic += " site(" + scope + ")";
37
38         return basic;
39     };
40
41     /* Reacting to the interface's "Begin" button, this function triggers the
42      * first of three server-side processes necessary to create a session:
43      *
44      * 1) create the session itself (API call), */
45     module.begin = function() {
46         var name = uv_session_name.attr("value");
47
48         var scope;
49         try {
50             scope = module.org_selector.store.getValue(
51                 module.org_selector.item,
52                 "shortname"
53             );
54         } catch (E) {
55             /* probably nothing valid is selected; move on */
56             void(0);
57         }
58
59         var search = module._prepare_search(
60             uv_search.attr("value"),
61             dojo.filter(
62                 dojo.byId("saved-searches").options,
63                 function(o) { return o.selected; }
64             ).map(
65                 function(o) { return o.value; }
66             ),
67             scope
68         );
69
70         if (!module.tag_and_subfields.any()) {
71             alert(localeStrings.NEED_UVUS);
72             return;
73         }
74
75         module.progress_dialog.attr("title", localeStrings.CREATING);
76         module.progress_dialog.show(true);
77         fieldmapper.standardRequest(
78             ["open-ils.url_verify", "open-ils.url_verify.session.create"], {
79                 "params": [openils.User.authtoken, name, search],
80                 "async": true,
81                 "onresponse": function(r) {
82                     if (r = openils.Util.readResponse(r)) {
83                         /* I think we're modal enough to get away with this. */
84                         module.session_id = r;
85                         module.save_tags();
86                     } else {
87                         module.progress_dialog.hide();
88                     }
89                 }
90             }
91         );
92     };
93
94     /* 2a) save the tag/subfield sets for URL extraction, */
95     module.save_tags = function() {
96         module.progress_dialog.attr("title", localeStrings.SAVING_TAGS);
97         module.progress_dialog.show(); /* sic */
98
99         uvus_progress = 0;
100
101         /* Note we're not using openils.PermaCrud, which is inadequate
102          * when you need one big transaction. Thanks for figuring it
103          * out Bill. */
104         var pcrud_raw = new OpenSRF.ClientSession("open-ils.pcrud");
105
106         pcrud_raw.connect();
107
108         pcrud_raw.request({
109             "method": "open-ils.pcrud.transaction.begin",
110             "params": [openils.User.authtoken],
111             "oncomplete": function(r) {
112                 module._create_uvus_one_at_a_time(
113                     pcrud_raw,
114                     module.tag_and_subfields.generate_uvus(module.session_id)
115                 );
116             }
117         }).send();
118     };
119
120     /* 2b */
121     module._create_uvus_one_at_a_time = function(pcrud_raw, uvus_list) {
122         pcrud_raw.request({
123             "method": "open-ils.pcrud.create.uvus",
124             "params": [openils.User.authtoken, uvus_list[0]],
125             "oncomplete": function(r) {
126                 var new_uvus = openils.Util.readResponse(r);
127                 module.progress_dialog.update(
128                     {"maximum": uvus_list.length, "progress": ++uvus_progress}
129                 );
130
131                 uvus_list.shift();  /* /now/ actually shorten working list */
132
133                 if (uvus_list.length < 1) {
134                     pcrud_raw.request({
135                         "method": "open-ils.pcrud.transaction.commit",
136                         "params": [openils.User.authtoken],
137                         "oncomplete": function(r) {
138                             pcrud_raw.disconnect();
139                             module.perform_search();
140                         }
141                     }).send();
142
143                 } else {
144                     module._create_uvus_one_at_a_time(
145                         pcrud_raw, uvus_list
146                     );
147                 }
148              }
149         }).send();
150     };
151
152     /* 3) search and populate the container (API call). */
153     module.perform_search = function() {
154         var search_result_count = 0;
155
156         module.progress_dialog.attr("title", localeStrings.PERFORMING_SEARCH);
157         module.progress_dialog.show(true);
158
159         fieldmapper.standardRequest(
160             ["open-ils.url_verify",
161                 "open-ils.url_verify.session.search_and_extract"], {
162                 "params": [openils.User.authtoken, module.session_id],
163                 "async": true,
164                 "onresponse": function(r) {
165                     r = openils.Util.readResponse(r);
166                     if (!search_result_count) {
167                         search_result_count = Number(r);
168
169                         module.progress_dialog.show(); /* sic */
170                         module.progress_dialog.attr(
171                             "title", localeStrings.EXTRACTING_URLS
172                         );
173                         module.progress_dialog.update(
174                             {"maximum": search_result_count, "progress": 0}
175                         );
176                     } else {
177                         module.progress_dialog.update({"progress": r.length})
178                     }
179                 },
180                 "oncomplete": function() {
181                     module.progress_dialog.attr(
182                         "title", localeStrings.REDIRECTING
183                     );
184                     module.progress_dialog.show(true);
185
186                     if (no_url_selection.checked) {
187                         /* verify URLs and ultimately redirect to review page */
188                         openils.URLVerify.Verify.go(
189                             module.session_id, null, module.progress_dialog
190                         );
191                     } else {
192                         /* go to the URL selection page, allowing users to
193                          * selectively verify URLs */
194                         location.href = oilsBasePath +
195                             "/url_verify/select_urls?session_id=" +
196                             module.session_id;
197                     }
198                 }
199             }
200         );
201     };
202
203     /* At least in Dojo 1.3.3 (I know, I know), dijit.form.MultiSelect does
204      * not behave like FilteringSelect, like you might expect, or work from a
205      * data store.  So we'll use a native <select> control, which will have
206      * fewer moving parts that can go haywire anyway.
207      */
208     module._populate_saved_searches = function(node) {
209         var list = module.pcrud.retrieveAll(
210             "asq", {"order_by": {"asq": "label"}}
211         );
212
213         dojo.forEach(
214             list, function(o) {
215                 dojo.create(
216                     "option", {
217                         "innerHTML": o.label(),
218                         "value": o.id(),
219                         "title": o.query_text()
220                     }, node, "last"
221                 );
222             }
223         );
224     };
225
226     /* set up an all-org-units-in-the-tree selector */
227     module._prepare_org_selector = function(node) {
228         var widget = new openils.widget.FilteringTreeSelect(null, node);
229         widget.searchAttr = "name";
230         widget.labelAttr = "name";
231         widget.tree = fieldmapper.aou.globalOrgTree;
232         widget.parentField = 'parent_ou';
233         widget.startup();
234         widget.attr("value", openils.User.user.ws_ou());
235
236         module.org_selector = widget;
237     };
238
239     /* Can only be called by setup() */
240     module._clone = function(id) {
241         module.progress_dialog.attr("title", localeStrings.CLONING);
242         var old_session = module.pcrud.retrieve(
243             "uvs", id, {"flesh": 1, "flesh_fields": {"uvs": ["selectors"]}}
244         );
245
246         /* Set name to "Copy of [old name]" */
247         uv_session_name.attr(
248             "value", dojo.string.substitute(
249                 localeStrings.CLONE_SESSION_NAME, [old_session.name()]
250             )
251         );
252
253         /* Set search field. */
254         uv_search.attr("value", old_session.search());
255
256         /* Explain to user why we don't affect the saved searches picker. */
257         if (old_session.search().match(/saved_query/))
258             openils.Util.show("clone-saved-search-warning");
259
260         /* Add related xpaths (URL selectors) to TagAndSubfieldsMgr. */
261         module.tag_and_subfields.add_xpaths(old_session.selectors());
262     };
263
264     module.setup = function(saved_search_id, org_selector_id, progress_dialog) {
265         module.pcrud = new openils.PermaCrud(); /* only used for setup */
266
267         module.progress_dialog = progress_dialog;
268
269         module.progress_dialog.attr("title", localeStrings.INTERFACE_SETUP);
270         module.progress_dialog.show(true);
271
272         module._populate_saved_searches(dojo.byId(saved_search_id));
273         module._prepare_org_selector(dojo.byId(org_selector_id));
274
275         var cgi = new openils.CGI();
276         if (cgi.param("clone"))
277             module._clone(cgi.param("clone"));
278
279         module.pcrud.disconnect();
280
281         module.progress_dialog.hide();
282     };
283
284     /* This is the thing that lets you add/remove rows of tab/subfield pairs */
285     function TagAndSubfieldsMgr(container_id) {
286         var self = this;
287
288         this.container_id = container_id;
289         this.counter = 0;
290
291         this.read_new = function() {
292             var controls = dojo.query(".tag-and-subfield-add-another input");
293
294             return {
295                 "tag": controls[0].value,
296                 "subfields": openils.Util.uniqueElements(
297                     controls[1].value.replace(/[^0-9a-z]/g, "").split("")
298                 ).sort().join("")
299             };
300         };
301
302         this.add = function() {
303             var newdata = this.read_new();
304             var newid = "t-and-s-row-" + String(this.counter++);
305             var div = dojo.create(
306                 "div", {
307                     "id": newid,
308                     "innerHTML": "<span class='t-and-s-tag'>" +
309                         newdata.tag +
310                         "</span> \u2021<span class='t-and-s-subfields'>" +
311                         newdata.subfields + "</span> "
312                 }, this.container_id, "last"
313             );
314             dojo.create(
315                 "a", {
316                     "href": "javascript:void(0);",
317                     "onclick": function() {
318                         var me = dojo.byId(newid);
319                         me.parentNode.removeChild(me);
320                     },
321                     "innerHTML": "[X]" /* XXX i18n */
322                 }, div, "last"
323             );
324         };
325
326         this.add_xpaths = function(xpaths) {
327             if (!dojo.isArray(xpaths)) {
328                 console.info("No xpaths to add");
329                 return;
330             }
331
332             dojo.forEach(
333                 xpaths, dojo.hitch(this, function(xpath) {
334                     var newid = "t-and-s-row-" + String(this.counter++);
335                     var div = dojo.create(
336                         "div", {
337                             "id": newid,
338                             "innerHTML": localeStrings.XPATH +
339                                 " <span class='t-and-s-xpath'>" +
340                                 xpath.xpath() + "</span>"
341                         }, this.container_id, "last"
342                     );
343                     dojo.create(
344                         "a", {
345                             "href": "javascript:void(0);",
346                             "onclick": function() {
347                                 var me = dojo.byId(newid);
348                                 me.parentNode.removeChild(me);
349                             },
350                             "innerHTML": "[X]" /* XXX i18n */
351                         }, div, "last"
352                     );
353                 })
354             );
355         };
356
357         /* return a boolean indicating whether or not we have any rows */
358         this.any = function() {
359             return Boolean(
360                 dojo.query(
361                     '[id^="t-and-s-row-"]', dojo.byId(this.container_id)
362                 ).length
363             );
364         };
365
366         /* Return one uvus object for each unique tag we have a row for,
367          * and use the given session_id for the uvus.session field. */
368         this.generate_uvus = function(session_id) {
369             var uniquely_grouped = {};
370             dojo.query(
371                 '[id^="t-and-s-row-"]', dojo.byId(this.container_id)
372             ).forEach(
373                 function(row) {
374                     var holds_xpath = dojo.query(".t-and-s-xpath", row);
375                     if (holds_xpath.length) {
376                         uniquely_grouped.xpath = uniquely_grouped.xpath || [];
377                         uniquely_grouped.xpath.push(holds_xpath[0].innerHTML);
378                     } else {
379                         var tag = dojo.query(".t-and-s-tag", row)[0].innerHTML;
380                         var subfield =
381                             dojo.query(".t-and-s-subfields", row)[0].innerHTML;
382
383                         var existing;
384                         if ((existing = uniquely_grouped[tag])) { // assignment
385                             existing = openils.Util.uniqueElements(
386                                 (existing + subfield).split("")
387                             ).sort().join("");
388                         } else {
389                             uniquely_grouped[tag] = subfield;
390                         }
391                     }
392                 }
393             );
394
395             var uvus_list = [];
396             /* Handle things that are already in XPath form first (these
397              * come from cloning link checker sessions. */
398             if (uniquely_grouped.xpath) {
399                 dojo.forEach(
400                     uniquely_grouped.xpath,
401                     function(xpath) {
402                         var obj = new uvus();
403
404                         obj.session(session_id);
405                         obj.xpath(xpath);
406                         uvus_list.push(obj);
407                     }
408                 );
409                 delete uniquely_grouped.xpath;
410             }
411
412             /* Now handle anything entered by hand. */
413             for (var tag in uniquely_grouped) {
414                 var obj = new uvus();
415
416                 obj.session(session_id);
417
418                 /* XXX TODO Handle control fields (No subfields. but would
419                  * control fields ever contain URLs? Don't know.) */
420                 obj.xpath(
421                     "//*[@tag='" + tag + "']/*[" +
422                     uniquely_grouped[tag].split("").map(
423                         function(c) { return "@code='" + c + "'"; }
424                     ).join(" or ") +
425                     "]"
426                 );
427
428                 uvus_list.push(obj);
429             }
430
431             return uvus_list;
432         };
433
434     }
435
436     module.tag_and_subfields =
437         new TagAndSubfieldsMgr("uv-tags-and-subfields");
438
439 }());
440
441 }