SelKwds.xsl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. <?xml version="1.0" encoding="iso-8859-1"?> <!-- SelKwds.xsl -->
  2. <!-- 2005/04/14 -->
  3. <!-- Copyright (C) 2005 rene.haentjens@UGent.be - see note at end of text -->
  4. <!-- Released under the GNU GPL V2, see http://www.gnu.org/licenses/gpl.html -->
  5. <!-- W3C browsers only; Moz1.7,NN7: security popup (UniversalXPConnect) -->
  6. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  7. <xsl:template match="/*">
  8. <html>
  9. <head><title><xsl:value-of select="@title"/></title>
  10. <style>
  11. body {font-family: sans-serif; font-size: x-small}
  12. .kwl {width: 92%; color: black; font-size: x-small; font-weight: bold}
  13. .dvc {display: none; margin-left: 3ex}
  14. .dvo {display: block; margin-left: 3ex}
  15. .btm {height: 3.5ex; width: 5ex; font-family: monospace; font-size: xx-small}
  16. .btn {height: 3.5ex; width: 3ex; font-family: monospace; font-size: xx-small}
  17. .lfn {height: 3.5ex; width: 3ex; font-family: monospace; font-size: xx-small; visibility: hidden}
  18. .lbl {background-color: white; cursor: pointer}
  19. .lbs {background-color: white; cursor: pointer; font-weight: bold; color: red}
  20. .pup {position:absolute; visibility:hidden; width: 50%; border: 1px solid black; overflow:auto; background-color: #FFF8DC}
  21. .pul {background-color: #FFF8DC}
  22. </style>
  23. <script language="JavaScript"><![CDATA[
  24. String.prototype.trim = function()
  25. {
  26. return this.replace(/^\s*/,"").replace(/\s*$/,""); // \f\n\r\t\v
  27. } // Dave Anderson, dbforums.com/arch/195/2003/3/724117
  28. String.prototype.removeExtraSpaces = function()
  29. {
  30. return this.replace(/\s+/g, ' ').trim();
  31. }
  32. function makeWindow(url, htmlText)
  33. {
  34. var newWindow = window.open(url, '',
  35. 'toolbar=no, location=no, directories=no, status=yes, '+
  36. 'menubar=yes, scrollbars=yes, resizable=yes, ' +
  37. 'width=800, height=600, left=10, top=10');
  38. if (url == '') newWindow.document.write('<html><body>' +
  39. htmlText + '</body></html>');
  40. return newWindow;
  41. }
  42. function isNotW3C()
  43. {
  44. if (!document.getElementById)
  45. alert('Sorry, the buttons only work with W3C browsers. ' +
  46. 'Use Moz1.7 or IE6 or NN7 or type in keywords manually...');
  47. return !document.getElementById;
  48. }
  49. function openOrCloseHelp(btn)
  50. {
  51. if (isNotW3C()) return false;
  52. document.getElementById('moreHelp').className =
  53. (btn.value == "?") ? "dvo" : "dvc";
  54. btn.value = (btn.value == "?") ? "¿" : "?";
  55. }
  56. function hasTagAndClass(obj, tag, cl)
  57. {
  58. return obj.tagName && (obj.tagName.toUpperCase() == tag) &&
  59. (obj.className == cl);
  60. }
  61. function openOrClose(btn) // show or hide part of keyword-tree
  62. {
  63. var oldcl = (btn.value == "-") ? "dvo" : "dvc";
  64. var newcl = (oldcl == "dvo") ? "dvc" : "dvo";
  65. btn.value = (oldcl == "dvo") ? "+" : "-" ;
  66. var ch = btn.parentNode.childNodes; // opera crashes on with()
  67. for (var i = 0; i < ch.length; i++) // netscape requires .item
  68. if (hasTagAndClass(ch.item(i), 'DIV', oldcl))
  69. ch.item(i).className = newcl;
  70. }
  71. function openOrCloseHere(div, wrong) // show or hide recursively
  72. {
  73. var ch = div.childNodes;
  74. for (var i = 0; i < ch.length; i++)
  75. {
  76. var thisCh = ch.item(i);
  77. if (thisCh.className == 'btn' && thisCh.value == wrong)
  78. openOrClose(thisCh)
  79. else if (thisCh.className == 'dvo' || thisCh.className == 'dvc')
  80. openOrCloseHere(thisCh, wrong);
  81. }
  82. }
  83. function openOrCloseAll(btn) // show or hide whole keyword-tree
  84. {
  85. if (isNotW3C()) return false;
  86. var wrong = (btn.value == "--") ? "-" : "+" ;
  87. btn.value = (wrong == "-") ? "++" : "--";
  88. openOrCloseHere(btn.parentNode, wrong);
  89. }
  90. var selspans = new Array; // selected SPANs with keywords
  91. function deselect(span)
  92. {
  93. for (var s in selspans) if (selspans[s] == span) delete selspans[s];
  94. }
  95. function copyToClipboard(allKwds)
  96. {
  97. if (window.clipboardData)
  98. {
  99. window.clipboardData.setData("Text", '<' + allKwds + '>\r\n');
  100. return;
  101. }
  102. netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
  103. var gClipboardHelper = Components.classes['@mozilla.org/widget/clipboardhelper;1']
  104. .getService(Components.interfaces.nsIClipboardHelper);
  105. gClipboardHelper.copyString('<' + allKwds + '>\n');
  106. }
  107. function getSelectedKeywords()
  108. {
  109. var sortedKwds = new Array, allKwds = '';
  110. for (var s in selspans)
  111. sortedKwds.push(selspans[s].parentNode.getAttribute('level')
  112. + '.' + selspans[s].innerHTML)
  113. sortedKwds.sort(); // according to level, which follows the tree
  114. for (var k in sortedKwds)
  115. {
  116. var someWords = sortedKwds[k];
  117. allKwds += ', ' + someWords.substr(someWords.indexOf('.')+1);
  118. }
  119. return allKwds.replace(/[,_\s]+/g, ', ').substr(2); // strip ', '
  120. }
  121. var orkwds; // array of ', kw, ' strings
  122. function selectOriginal(div)
  123. {
  124. var ch = div.childNodes;
  125. for (var i = 0; i < ch.length; i++)
  126. {
  127. var thisCh = ch.item(i); if (!thisCh.tagName) continue;
  128. thisTag = thisCh.tagName.toUpperCase();
  129. if (thisTag == 'SPAN')
  130. {
  131. var parkwds = ','+ thisCh.innerHTML.replace(/\s*/g,"") +',';
  132. for (var k = 0; k < orkwds.length; k++)
  133. if (parkwds.indexOf(orkwds[k]) >=0 )
  134. {
  135. deselect(thisCh); selspans.push(thisCh);
  136. thisCh.className = "lbs";
  137. openToTop(div, div.className); break;
  138. }
  139. }
  140. else if (thisTag == 'DIV')
  141. {
  142. selectOriginal(thisCh);
  143. }
  144. }
  145. }
  146. function openToTop(div, divclass)
  147. {
  148. if (!div.parentNode) return; var pdiv = div.parentNode;
  149. if (!pdiv.className) return; var pclass = pdiv.className;
  150. if (pclass != 'dvo' && pclass != 'dvc') return;
  151. if (divclass == 'dvc')
  152. {
  153. var ch = pdiv.childNodes;
  154. for (var i = 0; i < ch.length; i++)
  155. {
  156. var btn = ch.item(i);
  157. if (hasTagAndClass(btn, 'INPUT', 'btn'))
  158. if (btn.value == '+') openOrClose(btn);
  159. }
  160. }
  161. openToTop(pdiv, pclass);
  162. }
  163. function deselectAll(ev, btn)
  164. {
  165. if (isNotW3C()) return false;
  166. if (!ev) var ev = window.event;
  167. var kws = document.getElementById('kwds_string');
  168. for (var s in selspans) selspans[s].className = "lbl";
  169. selspans = new Array;
  170. document.getElementById('btnOpenOrCloseAll').value = "--";
  171. if (!ev.altKey) { kws.value = ''; return; }
  172. if (ev.ctrlKey) kws.value = getPptKw();
  173. var kwdswere = kws.value; // typed in by user or fetched from PPT
  174. var kwdsarray = kwdswere.split(','), allKwds = '';
  175. for (var k = 0; k < kwdsarray.length; k++)
  176. {
  177. var kwd = kwdsarray[k].trim();
  178. if (kwd.substr(0,1) == '-') kwd = kwd.substr(1);
  179. if (kwd != '') allKwds += '§,' + kwd + ',';
  180. }
  181. if (allKwds == '') return;
  182. orkwds = allKwds.substr(1).split('§');
  183. selectOriginal(btn.parentNode);
  184. allKwds = getSelectedKeywords(); kws.value = allKwds;
  185. copyToClipboard(allKwds);
  186. allKwds = ','+ allKwds.replace(/\s*/g,"") +','; var missing = '';
  187. for (k = 0; k < orkwds.length; k++)
  188. if (allKwds.indexOf(orkwds[k]) < 0 ) missing += orkwds[k];
  189. if (missing != '') alert('!= ' + missing.replace(/,+/g," "));
  190. }
  191. function selectOrDeselect(span, newcl)
  192. {
  193. span.className = newcl; deselect(span);
  194. if (newcl == "lbs") selspans.push(span);
  195. }
  196. function alsoParents(div, oldcl, newcl)
  197. {
  198. while (div.parentNode)
  199. {
  200. div = div.parentNode; var ch = div.childNodes;
  201. for (var i = 0; i < ch.length; i++)
  202. if (hasTagAndClass(ch.item(i), 'SPAN', oldcl))
  203. selectOrDeselect(ch.item(i), newcl);
  204. }
  205. }
  206. function spanClick(span, ev)
  207. {
  208. if (!ev) ev = window.event;
  209. if (ev.shiftKey && ev.altKey)
  210. {
  211. makeWindow('', '<pre>' + span.parentNode.innerHTML
  212. .replace(/&/g, "&amp;").replace(/"/g, "&quot;")
  213. .replace(/</g, "&lt;") .replace(/>/g, "&gt;") + '</pre>');
  214. return; // debugging...
  215. }
  216. if (ev.ctrlKey || span.className == "lbs")
  217. {
  218. selectOrDeselect(span, "lbl"); // deselect
  219. if (document.selection) document.selection.empty();
  220. if (ev.altKey) alsoParents(span.parentNode, "lbs", "lbl");
  221. }
  222. else
  223. {
  224. selectOrDeselect(span, "lbs"); // select
  225. if (!ev.altKey) alsoParents(span.parentNode, "lbl", "lbs");
  226. //
  227. // in md_script, there is some code here
  228. // to negate keywords for search
  229. //
  230. }
  231. var allKwds = getSelectedKeywords(); copyToClipboard(allKwds);
  232. document.getElementById('kwds_string').value = allKwds;
  233. }
  234. var KWDS_ARRAY = new Array, nkw = 0, pU; // alphabetic list popup
  235. function makeAlphaList(div)
  236. {
  237. var ch = div.childNodes;
  238. for (var i = 0; i < ch.length; i++)
  239. {
  240. var thisCh = ch.item(i); if (!thisCh.tagName) continue;
  241. thisTag = thisCh.tagName.toUpperCase();
  242. if (thisTag == 'SPAN')
  243. {
  244. var parkwds= thisCh.innerHTML.replace(/\s*/g,"").split(',');
  245. for (k in parkwds) KWDS_ARRAY[nkw++] = parkwds[k];
  246. }
  247. else if (thisTag == 'DIV') makeAlphaList(thisCh);
  248. }
  249. }
  250. function pU_show(anchor, offsetX, offsetY, defH) // XY: rel. to anchor
  251. {
  252. if (!anchor) return;
  253. thisx = anchor.offsetLeft; thisy = anchor.offsetTop;
  254. while ((anchor = anchor.offsetParent))
  255. {
  256. thisx += anchor.offsetLeft; thisy += anchor.offsetTop;
  257. }
  258. thisx += offsetX; thisy += offsetY;
  259. pU.style.left = thisx + "px";
  260. pU.style.top = thisy + "px";
  261. pU.style.height = defH; var maxH = pU.offsetHeight;
  262. for (var curH = 20; curH <= maxH; curH += 20)
  263. {
  264. pU.style.height = curH + 'px';
  265. if (curH >= pU.scrollHeight) break;
  266. }
  267. // scrollHeight can be smaller than current in IE, not in Moz
  268. pU.style.visibility = "visible";
  269. }
  270. function pU_hide()
  271. {
  272. if (pU) pU.style.visibility = "hidden";
  273. }
  274. function takeTypeIn(kws, oX, oY, defH)
  275. {
  276. if (isNotW3C()) return;
  277. if (!pU)
  278. {
  279. pU = document.getElementById('popup');
  280. makeAlphaList(document.getElementById('maindiv'));
  281. KWDS_ARRAY.sort();
  282. }
  283. var curValue = kws.value.toLowerCase(), kwLines = '';
  284. for (pos = 0; pos < KWDS_ARRAY.length; pos++)
  285. if (KWDS_ARRAY[pos].toLowerCase().indexOf(curValue) == 0)
  286. kwLines += '<div class="pul" onMouseOver="this.className=' +
  287. "'lbl'" + '"; onMouseOut="this.className=' + "'pul'" +
  288. '">' + KWDS_ARRAY[pos] + '</div>';
  289. if (kwLines == '') {pU_hide(); return; }
  290. pU.innerHTML = kwLines; pU_show(kws, oX, oY, defH);
  291. }
  292. function pU_clicked(ev)
  293. {
  294. if (!pU) return false; if (!ev) var ev = window.event;
  295. var t = (ev.srcElement) ? ev.srcElement : ev.originalTarget;
  296. try {var kw = t.innerHTML;} catch(exc) {return false;} // Moz
  297. while (true) try
  298. {
  299. if (t.id == pU.id) return kw ? kw : true; t = t.parentNode;
  300. }
  301. catch(exc) {return false;} // Moz: t.parentNode uncatched exc.
  302. }
  303. function pU_select(kw)
  304. {
  305. if (kw === true) return;
  306. var kws = document.getElementById('kwds_string');
  307. var maindiv = document.getElementById('maindiv');
  308. var ch = maindiv.childNodes;
  309. for (var i = 0; i < ch.length; i++)
  310. {
  311. var btn = ch.item(i);
  312. if (hasTagAndClass(btn, 'INPUT', 'btn'))
  313. if (btn.value == '+') openOrClose(btn);
  314. }
  315. orkwds = new Array(',' + kw + ','); selectOriginal(maindiv);
  316. kws.value = getSelectedKeywords(); copyToClipboard(kws.value);
  317. pU_hide();
  318. }
  319. function getPptKw() // SelKwds specific, IE only!
  320. {
  321. if (typeof window.ActiveXObject == 'undefined') return '';
  322. with (new ActiveXObject('Powerpoint.Application'))
  323. {
  324. if (Presentations.Count == 0) return '';
  325. var slKw = ActiveWindow.View.Slide.NotesPage(1)
  326. .Shapes.Placeholders(2).TextFrame.TextRange.Text
  327. .replace(/[\x00-\x1F\x7F-\x9F]/g, ' ')
  328. .replace(/\s+/g, ' ').trim();
  329. }
  330. if (slKw.substr(0,1) == '<')
  331. {
  332. var slKwEnd = slKw.indexOf('>');
  333. if (slKwEnd <= 0) return '';
  334. return slKw.substr(1, slKwEnd - 1);
  335. }
  336. else
  337. {
  338. var slKwLen = slKw.length;
  339. if (slKw.substr(slKwLen - 1) != '>') return '';
  340. var slKwBegin = slKw.lastIndexOf('<');
  341. if (slKwBegin <= 0) return '';
  342. return slKw.substr(slKwBegin + 1, slKwLen - slKwBegin - 2);
  343. }
  344. }
  345. ]]></script>
  346. </head>
  347. <body onMouseUp="if ((kw = pU_clicked(event))) pU_select(kw); else pU_hide();">
  348. <!-- Note: style on DIV in TD, but keep vertical-align on TD -->
  349. <h3><xsl:value-of select="@title"/></h3>
  350. <div>
  351. <input type="button" class="btn" value="?" onClick="openOrCloseHelp(this)"/>
  352. &#xa0;Click a keyword in the tree to select or deselect it.
  353. </div>
  354. <div id='moreHelp' class='dvc'>
  355. <br/>
  356. Click '+' button to open, '-' button to close, '++' button to open all, '--' button to close all.<br/>
  357. <br/>
  358. Clear all selected keywords by closing the tree and opening it again with the '+' button.<br/>
  359. Alt-click '+' searches the current keywords in the tree.<br/>
  360. Control-Alt-click '+' searches the keywords of the current slide.<br/>
  361. <br/>
  362. Alt-click keyword selects a keyword without broader terms or
  363. deselects a keyword with broader terms.<br/><br/>
  364. Selected keywords are available in the Clipboard.<br/>
  365. <br/>
  366. 'nei' stands for 'not elswhere included'.<br/><br/>
  367. </div>
  368. <div noWrap="1" id="maindiv">
  369. <input type="button" class="btn" value="+" onClick="if (this.value == '+') deselectAll(event, this); openOrClose(this);"/>
  370. <input type="button" class="btm" id="btnOpenOrCloseAll" value="++" onClick="openOrCloseAll(this);"/>
  371. &#xa0;
  372. <input type="text" id="kwds_string" class="kwl"
  373. onKeyUp="takeTypeIn(this, 200, 30, '60%'); return true;"/><br/>
  374. <xsl:apply-templates/>
  375. </div>
  376. <div id="popup" noWrap="1" class="pup">
  377. Working...
  378. </div>
  379. </body>
  380. </html>
  381. </xsl:template>
  382. <!-- par(ent) lev(el) and cur(rent) lev(el): '001', '002', '002001', ... -->
  383. <xsl:template match="*"><xsl:param name="parlev" select="''"/>
  384. <xsl:variable name="tmplev" select="concat('00', position())"/>
  385. <xsl:variable name="curlev" select="concat($parlev, substring($tmplev, string-length($tmplev) - 2))"/>
  386. <div noWrap="1" class="dvc">
  387. <xsl:attribute name="level"><xsl:value-of select="$curlev"/></xsl:attribute>
  388. <xsl:if test="*">
  389. <input type="button" class="btn" value="+" onClick="openOrClose(this);"/>
  390. </xsl:if>
  391. <xsl:if test="not(*)">
  392. <input type="button" class="lfn" value=" "/>
  393. </xsl:if>
  394. &#xa0;
  395. <span class="lbl" onClick="spanClick(this, event);">
  396. <xsl:if test="@postit">
  397. <xsl:attribute name="title"><xsl:value-of select="@postit"/></xsl:attribute>
  398. </xsl:if>
  399. <xsl:value-of select="translate(name(), '_', ',')"/>
  400. </span>
  401. <xsl:if test="@comment">
  402. <i><xsl:value-of select="@comment"/></i>
  403. </xsl:if>
  404. <br/>
  405. <xsl:apply-templates>
  406. <xsl:with-param name="parlev" select="$curlev"/>
  407. </xsl:apply-templates>
  408. </div>
  409. </xsl:template>
  410. </xsl:stylesheet>
  411. <!--
  412. This program is free software; you can redistribute it and/or
  413. modify it under the terms of the GNU General Public License
  414. as published by the Free Software Foundation; either version 2
  415. of the License, or (at your option) any later version.
  416. This program is distributed in the hope that it will be useful,
  417. but WITHOUT ANY WARRANTY; without even the implied warranty of
  418. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  419. GNU General Public License for more details.
  420. -->