LT Copy Book (fixed) - LibraryThing

Copies book data and automatically pastes it to a manual entry.

  1. // ==UserScript==
  2. // @name LT Copy Book (fixed) - LibraryThing
  3. // @namespace http://userscripts.org/users/brightcopy
  4. // @description Copies book data and automatically pastes it to a manual entry.
  5. // @include http*://*.librarything.tld/work*/details/*
  6. // @include http*://*.librarything.tld/work*/workdetails*
  7. // @include http*://*.librarything.tld/addnew.php
  8. // @grant GM_setValue
  9. // @grant GM_getValue
  10. // @grant GM_deleteValue
  11. // @version 2.2
  12. // @license Public domain
  13. // ==/UserScript==
  14. var ltcbTitle = { key:'ltcbTitle' , id:'bookedit_title' , field:'form_title' };
  15. var ltcbAuthor = { key:'ltcbAuthor' , id:'bookedit_authorunflip' , field:'form_authorunflip' };
  16. var ltcbDate = { key:'ltcbDate' , id:'bookedit_date' , field:'form_date' };
  17. var ltcbPublication = { key:'ltcbPublication' , id:'bookedit_publication' , field:'form_publication' };
  18. var ltcbISBN = { key:'ltcbISBN' , id:'bookedit_ISBN' , field:'form_ISBN' };
  19. var ltcbLCCN = { key:'ltcbLCCN' , id:'bookedit_lccallnumber' , field:'form_lccallnumber' };
  20. var ltcbDewey = { key:'ltcbDewey' , id:'bookedit_dewey' , field:'form_dewey' };
  21. var ltcbLanguage = { key:'ltcbLanguage' , id:'bookedit_lang' , field:'field_lang' };
  22. var ltcbLanguage2 = { key:'ltcbLanguage2' , id:'bookedit_lang2' , field:'field_lang2' };
  23. var ltcbLanguageO = { key:'ltcbLanguageO' , id:'bookedit_lang_original' , field:'field_lang_original' };
  24. //var ltcbVolumes = { key:'ltcbVolumes' , id:'bookedit_numVolumes' , field:'numVolumes' , path:'//td[text()="Number of Volumes"]/../td[@class="bookeditfield"]'};
  25. //var ltcbPages = { key:'ltcbPages' , id:'bookedit_pagecount' , field:'pagecount' , path:'//td[text()="Pages"]/../td[@class="bookeditfield"]'};
  26. var ltcbCollection = { key:'ltcbCollection' };
  27. var ltcbAddToLibrary = { key:'ltcbAddToLibrary' };
  28. var ltcbAddToWishlist = { key:'ltcbAddToWishlist' };
  29. var ltcbOtherAuthorCount = { key:'ltcbOtherAuthorCount' };
  30. var ltcbOtherAuthorRole = { key:'ltcbOtherAuthorRole' , field:'person_role-' };
  31. var ltcbOtherAuthorName = { key:'ltcbOtherAuthorName' , field:'person_name-' };
  32. var ltcbAuthorRole = { key:'ltcbAuthorRole' , field:'person_role_main' };
  33. function getById(setting) {
  34. var e = document.getElementById(setting.id);
  35. // kludge for title on work page
  36. if (e == null && setting === ltcbTitle) {
  37. e = $x1('//table[@id="book_bookInformationTable"]/tbody/tr[1]/td[2]/b');
  38. }
  39. return e ? e.textContent : '';
  40. }
  41. function save(setting, callback) {
  42. var value = getById(setting);
  43. if (callback)
  44. value = callback(value);
  45. GM_setValue(setting.key, value);
  46. }
  47. function setNonGreen(setting) {
  48. var e = document.getElementById(setting.id);
  49. var value = (e && e.innerHTML == e.textContent) ? e.textContent : '';
  50. GM_setValue(setting.key, value);
  51. }
  52. function load(form, setting, opt) {
  53. var key = setting.key + (opt != undefined ? opt : '');
  54. var field = setting.field + (opt != undefined ? opt : '');
  55. var value = GM_getValue(key);
  56. var elem = form.elements.namedItem(field);
  57. // console.log('load: ' + key + ', ' + field + ', ' + value);
  58. if (elem)
  59. elem.value = value;
  60. }
  61. function loadRole(form, setting, opt) {
  62. if (!loadOption(form, setting, opt)) {
  63. var key = setting.key + (opt != undefined ? opt : '');
  64. var field = setting.field + (opt != undefined ? opt : '');
  65. var menu = form.elements.namedItem(field);
  66. if (menu) {
  67. var value = GM_getValue(key);
  68. var lastoption = menu.options.length;
  69. menu.options[lastoption - 2] = new Option(value, value);
  70. menu.options[lastoption - 1] = new Option("--------------", "");
  71. menu.options[lastoption] = new Option("Other...", "");
  72. menu.options.selectedIndex = lastoption - 2;
  73. }
  74. }
  75. }
  76. function loadOption(form, setting, opt) {
  77. var key = setting.key + (opt != undefined ? opt : '');
  78. var field = setting.field + (opt != undefined ? opt : '');
  79. var value = GM_getValue(key);
  80. var select = form.elements.namedItem(field);
  81. if (select == null)
  82. return false;
  83. var option = $x1('option[text() = "' + value + '"]', select);
  84. if (option) {
  85. select.value = option.value;
  86. return true;
  87. }
  88. else
  89. return false;
  90. }
  91. function fixAuthorName(value) {
  92. var newvalue = value.replace(
  93. /^(.+) ([^ ,]+),? (JR|SR|III|IV|V|VI|VII|VIII|IX)(.?)$/i, '$2, $1, $3$4');
  94. if (newvalue != value)
  95. value = newvalue;
  96. else
  97. value = value.replace(/^(.+) ([^ ]+)$/, '$2, $1');
  98. return value;
  99. }
  100. function addToLibraryClick(e) {
  101. addToClick(1);
  102. }
  103. function addToWishlistClick() {
  104. addToClick(4)
  105. }
  106. function fixLang(value) {
  107. if (value == '')
  108. value = '(blank)';
  109. return value;
  110. }
  111. function addToClick(c) {
  112. GM_setValue(ltcbCollection.key, c);
  113. save(ltcbTitle);
  114. save(ltcbPublication);
  115. save(ltcbLanguage, fixLang);
  116. save(ltcbLanguage2, fixLang);
  117. save(ltcbLanguageO, fixLang);
  118. save(ltcbDate,
  119. function (value) {
  120. if (value == '?')
  121. value = '';
  122. return value;
  123. }
  124. );
  125. save(ltcbISBN,
  126. function (value) {
  127. if (value == '') {
  128. var elem = $x1('/html/head/meta[@property="books:isbn"]/@content');
  129. if (elem != null) {
  130. value = elem.textContent;
  131. }
  132. }
  133. return (value + ' / ').split(' / ')[0];
  134. }
  135. );
  136. var authorElem = document.getElementById(ltcbAuthor.id);
  137. var authorName = null;
  138. var authorRole = '';
  139. if (authorElem != null) {
  140. authorName = authorElem.firstChild.textContent;
  141. var elem = authorElem.lastChild;
  142. if (elem.nodeType == 3) {//Node.TEXT_NODE
  143. authorRole = elem.textContent;
  144. }
  145. }
  146. // workdetails page with no user book
  147. else {
  148. authorElem = $x1('//div[@class="headsummary"]/h2');
  149. if (authorElem != null) {
  150. authorName = $x1('//div[@class="headsummary"]/h2/a').textContent;
  151. var authorRoleElem = $x1('//div[@class="headsummary"]/h2/text()[2]');
  152. if (authorRoleElem != null) {
  153. authorRole = authorRoleElem.textContent();
  154. }
  155. else {
  156. }
  157. }
  158. }
  159. console.log("author", "name=", authorName, "role=", authorRole);
  160. if (authorName != null) {
  161. console.log("setting author name", authorName);
  162. authorRole = authorRole.replace(/^ \((.+)\)$/, '$1');
  163. GM_setValue(ltcbAuthor.key, fixAuthorName(authorName));
  164. GM_setValue(ltcbAuthorRole.key, authorRole)
  165. }
  166. // fields with possible green text
  167. setNonGreen(ltcbLCCN);
  168. setNonGreen(ltcbDewey);
  169. // Other Authors
  170. var others = $x("//div[@class='bookeditPerson']/span[@class='book_langLabel']");
  171. GM_setValue(ltcbOtherAuthorCount.key, others.snapshotLength);
  172. for (var i = 0; i < others.snapshotLength; i++) {
  173. var role = others.snapshotItem(i);
  174. var roleText = role.textContent;
  175. GM_setValue(ltcbOtherAuthorRole.key + i, roleText.substring(0, roleText.length - 3));
  176. var author = role.nextSibling;
  177. while (author && author.tagName != 'SPAN') {
  178. author = author.nextSibling;
  179. }
  180. if (author)
  181. GM_setValue(ltcbOtherAuthorName.key + i, author.textContent);
  182. }
  183. }
  184. function createAddTo(id, text, bg) {
  185. return '<span class="ltbtn ltbtn-inline-block sp16 ltbtn-ff3 " style="margin-left: 0.5em;">'+
  186. '<a id="' + id + '" href="/addnew.php">'+
  187. '<div class="ltbtn-outer-box ltbtn-inline-block">'+
  188. '<div class="ltbtn-inner-box ltbtn-inline-block">'+
  189. '<div class="ltbtn-pos">'+
  190. '<div class="ltbtn-top-shadow"></div>' +
  191. '<div class="ltbtn-content">'+
  192. '<div style="margin-right: 2px;" class="ltbtn-body ">'+
  193. '<span style="background-position: ' + bg + ';" class="sp_c sp16 "></span>'+
  194. 'Copy to ' + text +
  195. '</div>'+
  196. '</div>'+
  197. '</div>'+
  198. '</div>'+
  199. '</div>'+
  200. '</a>' +
  201. '</span>';
  202. }
  203. function readData() {
  204. if (document.getElementById('ltcbButtons') == null) {
  205. // Create Buttons
  206. var elem = $x1('//div[@class="book_bitHeadContent"]/table[@class="book_bitTable"]/tbody/tr');
  207. if (elem == null) {
  208. elem = $x1('//table[@id="book_bookInformationTable"]/tbody/tr');
  209. }
  210. if (elem) {
  211. var td = document.createElement('td');
  212. var div = document.createElement('div');
  213. div.setAttribute('style', 'float: right');
  214. div.setAttribute('id', 'ltcbButtons');
  215. td.appendChild(div);
  216. elem.appendChild(td);
  217. div.innerHTML =
  218. '<span style="font-size: 9px; font-weight: normal; white-space: nowrap">' +
  219. createAddTo(ltcbAddToLibrary.key, 'your library', '-17px -68px') +
  220. createAddTo(ltcbAddToWishlist.key, 'your wishlist', '-34px -68px') +
  221. '</span>';
  222. document.getElementById(ltcbAddToLibrary.key).addEventListener('click', addToLibraryClick, false);
  223. document.getElementById(ltcbAddToWishlist.key).addEventListener('click', addToWishlistClick, false);
  224. }
  225. }
  226. }
  227. /* ===== Click on an element (borrowed from Facebook Fixer, @namespace http://userscripts.org/people/14536) ===== */
  228. function click(elm) {
  229. try {
  230. elm.click();
  231. }
  232. catch (e) { }
  233. }
  234. function writeData() {
  235. var collection = GM_getValue(ltcbCollection.key);
  236. if (collection != undefined) {
  237. var f = document.getElementById('book_editForm');
  238. click($x1('//div[@class="collectionListFooter"]/span[@id!=""]/button'));
  239. var collections = $x('//td[@id="bookedit_tags"]//input');
  240. for (var i = 0; i < collections.snapshotLength; i++) {
  241. var collectionInput = collections.snapshotItem(i);
  242. collectionInput.checked = collection == collectionInput.value;
  243. }
  244. load(f, ltcbTitle);
  245. load(f, ltcbAuthor);
  246. load(f, ltcbDate);
  247. load(f, ltcbPublication);
  248. load(f, ltcbISBN);
  249. load(f, ltcbLCCN);
  250. load(f, ltcbDewey);
  251. loadRole(f, ltcbAuthorRole);
  252. var otherAuthorCount = GM_getValue(ltcbOtherAuthorCount.key);
  253. if (otherAuthorCount)
  254. unsafeWindow.pcount = 1;
  255. for (i = 0; i < otherAuthorCount; i++) {
  256. if (i)
  257. unsafeWindow.addPerson();
  258. load(f, ltcbOtherAuthorName, i);
  259. loadRole(f, ltcbOtherAuthorRole, i);
  260. }
  261. writeLangs();
  262. }
  263. }
  264. var langLoadCalled = false;
  265. function writeLangs() {
  266. var f = document.getElementById('book_editForm');
  267. var success = loadOption(f, ltcbLanguage)
  268. && loadOption(f, ltcbLanguage2) && loadOption(f, ltcbLanguageO);
  269. if (success)
  270. GM_deleteValue(ltcbCollection.key);
  271. else {
  272. if (!langLoadCalled) {
  273. langLoadCalled = true;
  274. unsafeWindow.book_updateLangMenus.call(unsafeWindow, 1);
  275. }
  276. // console.log('setting timeout');
  277. setTimeout(writeLangs, 100);
  278. }
  279. }
  280. function $x(x, t, r) {
  281. if (t && t.nodeType)
  282. var h = r, r = t, t = h;
  283. var d = r ? r.ownerDocument || r : r = document, p;
  284. switch (t) {
  285. case XPathResult.NUMBER_TYPE:
  286. p = 'numberValue';
  287. break;
  288. case XPathResult.STRING_TYPE:
  289. p = 'stringValue';
  290. break;
  291. case XPathResult.BOOLEAN_TYPE:
  292. p = 'booleanValue';
  293. break;
  294. case XPathResult.ANY_UNORDERED_NODE_TYPE:
  295. case XPathResult.FIRST_ORDERED_NODE_TYPE:
  296. p = 'singleNodeValue';
  297. break;
  298. default:
  299. return d.evaluate(x, r, null,
  300. t || XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  301. }
  302. var result = d.evaluate(x, r, null, t, null);
  303. if (result != null)
  304. result = result[p];
  305. return result;
  306. }
  307. function $x1(x, r) {
  308. return $x(x, XPathResult.ANY_UNORDERED_NODE_TYPE, r)
  309. }
  310. try {
  311. // find the values from the screen
  312. if (window.location.pathname.substring(0, '/work/'.length) == '/work/')
  313. readData()
  314. else if (window.location.pathname == '/addnew.php')
  315. writeData()
  316. } catch (e) {
  317. console.log(e);
  318. }