Annotation of kupuMPIWG/common/kupudrawers.js, revision 1.1
1.1 ! dwinter 1: /*****************************************************************************
! 2: *
! 3: * Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
! 4: *
! 5: * This software is distributed under the terms of the Kupu
! 6: * License. See LICENSE.txt for license text. For a list of Kupu
! 7: * Contributors see CREDITS.txt.
! 8: *
! 9: *****************************************************************************/
! 10:
! 11: // $Id: kupudrawers.js 14575 2005-07-12 20:18:12Z duncan $
! 12:
! 13: function DrawerTool() {
! 14: /* a tool to open and fill drawers
! 15:
! 16: this tool has to (and should!) only be instantiated once
! 17: */
! 18: this.drawers = {};
! 19: this.current_drawer = null;
! 20:
! 21: this.initialize = function(editor) {
! 22: this.editor = editor;
! 23: this.isIE = this.editor.getBrowserName() == 'IE';
! 24: // this essentially makes the drawertool a singleton
! 25: window.drawertool = this;
! 26: };
! 27:
! 28: this.registerDrawer = function(id, drawer, editor) {
! 29: this.drawers[id] = drawer;
! 30: drawer.initialize(editor || this.editor, this);
! 31: };
! 32:
! 33: this.openDrawer = function(id) {
! 34: /* open a drawer */
! 35: if (this.current_drawer) {
! 36: this.closeDrawer();
! 37: };
! 38: var drawer = this.drawers[id];
! 39: if (this.isIE) {
! 40: drawer.editor._saveSelection();
! 41: }
! 42: drawer.createContent();
! 43: drawer.editor.suspendEditing();
! 44: this.current_drawer = drawer;
! 45: };
! 46:
! 47: this.updateState = function(selNode) {
! 48: };
! 49:
! 50: this.closeDrawer = function(button) {
! 51: if (!this.current_drawer) {
! 52: return;
! 53: };
! 54: this.current_drawer.hide();
! 55: this.current_drawer.editor.resumeEditing();
! 56: this.current_drawer = null;
! 57: };
! 58:
! 59: // this.getDrawerEnv = function(iframe_win) {
! 60: // var drawer = null;
! 61: // for (var id in this.drawers) {
! 62: // var ldrawer = this.drawers[id];
! 63: // // Note that we require drawers to provide us with an
! 64: // // element property!
! 65: // if (ldrawer.element.contentWindow == iframe_win) {
! 66: // drawer = ldrawer;
! 67: // };
! 68: // };
! 69: // if (!drawer) {
! 70: // this.editor.logMessage("Drawer not found", 1);
! 71: // return;
! 72: // };
! 73: // return {
! 74: // 'drawer': drawer,
! 75: // 'drawertool': this,
! 76: // 'tool': drawer.tool
! 77: // };
! 78: // };
! 79: };
! 80:
! 81: DrawerTool.prototype = new KupuTool;
! 82:
! 83: function Drawer(elementid, tool) {
! 84: /* base prototype for drawers */
! 85:
! 86: this.element = getFromSelector(elementid);
! 87: this.tool = tool;
! 88:
! 89: this.initialize = function(editor, drawertool) {
! 90: this.editor = editor;
! 91: this.drawertool = drawertool;
! 92: };
! 93:
! 94: this.createContent = function() {
! 95: /* fill the drawer with some content */
! 96: // here's where any intelligence and XSLT transformation and such
! 97: // is done
! 98: this.element.style.display = 'block';
! 99: this.focusElement();
! 100: };
! 101:
! 102: this.hide = function() {
! 103: this.element.style.display = 'none';
! 104: this.focussed = false;
! 105: };
! 106:
! 107: this.focusElement = function() {
! 108: // IE can focus the drawer element, but Mozilla needs more help
! 109: this.focussed = false;
! 110: var iterator = new NodeIterator(this.element);
! 111: var currnode = iterator.next();
! 112: while (currnode) {
! 113: if (currnode.tagName && (currnode.tagName.toUpperCase()=='BUTTON' ||
! 114: (currnode.tagName.toUpperCase()=='INPUT' && !(/nofocus/.test(currnode.className)))
! 115: )) {
! 116: this.focussed = true;
! 117: function focusit() {
! 118: currnode.focus();
! 119: }
! 120: timer_instance.registerFunction(this, focusit, 100);
! 121: return;
! 122: }
! 123: currnode = iterator.next();
! 124: }
! 125: }
! 126: };
! 127:
! 128: function LinkDrawer(elementid, tool, wrap) {
! 129: /* Link drawer */
! 130: this.element = getFromSelector(elementid);
! 131: this.tool = tool;
! 132: function wrap(id, tag) {
! 133: return '#'+this.element.id+' '+tag+'.'+id;
! 134: }
! 135: var input = getBaseTagClass(this.element, 'input', 'kupu-linkdrawer-input');
! 136: var preview = getBaseTagClass(this.element, 'iframe', 'kupu-linkdrawer-preview');
! 137:
! 138: this.createContent = function() {
! 139: /* display the drawer */
! 140: var currnode = this.editor.getSelectedNode();
! 141: var linkel = this.editor.getNearestParentOfType(currnode, 'a');
! 142: input.value = "";
! 143: this.preview();
! 144: if (linkel) {
! 145: input.value = linkel.getAttribute('href');
! 146: } else {
! 147: input.value = 'http://';
! 148: };
! 149: this.element.style.display = 'block';
! 150: this.focusElement();
! 151: };
! 152:
! 153: this.save = function() {
! 154: /* add or modify a link */
! 155: this.editor.resumeEditing();
! 156: var url = input.value;
! 157: var target = '_self';
! 158: if (this.target) target = this.target;
! 159: this.tool.createLink(url, null, null, target);
! 160: input.value = '';
! 161:
! 162: // XXX when reediting a link, the drawer does not close for
! 163: // some weird reason. BUG! Close the drawer manually until we
! 164: // find a fix:
! 165: this.drawertool.closeDrawer();
! 166: };
! 167:
! 168: this.preview = function() {
! 169: preview.src = input.value;
! 170: if (this.editor.getBrowserName() == 'IE') {
! 171: preview.width = "800";
! 172: preview.height = "365";
! 173: preview.style.zoom = "60%";
! 174: };
! 175: }
! 176: this.preview_loaded = function() {
! 177: if (input.value != preview.src) {
! 178: input.value = preview.src;
! 179: }
! 180: }
! 181: };
! 182:
! 183: LinkDrawer.prototype = new Drawer;
! 184:
! 185: function TableDrawer(elementid, tool) {
! 186: /* Table drawer */
! 187: this.element = getFromSelector(elementid);
! 188: this.tool = tool;
! 189:
! 190: this.addpanel = getBaseTagClass(this.element, 'div', 'kupu-tabledrawer-addtable');
! 191: this.editpanel = getBaseTagClass(this.element, 'div', 'kupu-tabledrawer-edittable');
! 192: var classselect = getBaseTagClass(this.element, 'select', 'kupu-tabledrawer-classchooser');
! 193: var alignselect = getBaseTagClass(this.element, 'select', 'kupu-tabledrawer-alignchooser');
! 194: var newrowsinput = getBaseTagClass(this.element, 'input', 'kupu-tabledrawer-newrows');
! 195: var newcolsinput = getBaseTagClass(this.element, 'input', 'kupu-tabledrawer-newcols');
! 196: var makeheadercheck = getBaseTagClass(this.element, 'input', 'kupu-tabledrawer-makeheader');
! 197:
! 198: this.createContent = function() {
! 199: var selNode = this.editor.getSelectedNode();
! 200: if (this.editor.config.table_classes) {
! 201: var classes = this.editor.config.table_classes['class'];
! 202: while (classselect.hasChildNodes()) {
! 203: classselect.removeChild(classselect.firstChild);
! 204: };
! 205: for (var i=0; i < classes.length; i++) {
! 206: var classname = classes[i];
! 207: var option = document.createElement('option');
! 208: var content = document.createTextNode(classname);
! 209: option.appendChild(content);
! 210: option.setAttribute('value', classname);
! 211: classselect.appendChild(option);
! 212: };
! 213: };
! 214:
! 215: var table = this.editor.getNearestParentOfType(selNode, 'table');
! 216:
! 217: if (!table) {
! 218: // show add table drawer
! 219: show = this.addpanel;
! 220: hide = this.editpanel;
! 221: } else {
! 222: // show edit table drawer
! 223: show = this.editpanel;
! 224: hide = this.addpanel;
! 225: var align = this.tool._getColumnAlign(selNode);
! 226: selectSelectItem(alignselect, align);
! 227: selectSelectItem(classselect, table.className);
! 228: };
! 229: hide.style.display = 'none';
! 230: show.style.display = 'block';
! 231: this.element.style.display = 'block';
! 232: this.focusElement();
! 233: };
! 234:
! 235: this.createTable = function() {
! 236: this.editor.resumeEditing();
! 237: var rows = newrowsinput.value;
! 238: var cols = newcolsinput.value;
! 239: var style = classselect.value;
! 240: var add_header = makeheadercheck.checked;
! 241: this.tool.createTable(parseInt(rows), parseInt(cols), add_header, style);
! 242: this.drawertool.closeDrawer();
! 243: };
! 244: this.delTableRow = function() {
! 245: this.editor.resumeEditing();
! 246: this.tool.delTableRow();
! 247: this.editor.suspendEditing();
! 248: };
! 249: this.addTableRow = function() {
! 250: this.editor.resumeEditing();
! 251: this.tool.addTableRow();
! 252: this.editor.suspendEditing();
! 253: };
! 254: this.delTableColumn = function() {
! 255: this.editor.resumeEditing();
! 256: this.tool.delTableColumn();
! 257: this.editor.suspendEditing();
! 258: };
! 259: this.addTableColumn = function() {
! 260: this.editor.resumeEditing();
! 261: this.tool.addTableColumn();
! 262: this.editor.suspendEditing();
! 263: };
! 264: this.fixTable = function() {
! 265: this.editor.resumeEditing();
! 266: this.tool.fixTable();
! 267: this.editor.suspendEditing();
! 268: };
! 269: this.fixAllTables = function() {
! 270: this.editor.resumeEditing();
! 271: this.tool.fixAllTables();
! 272: this.editor.suspendEditing();
! 273: };
! 274: this.setTableClass = function(className) {
! 275: this.editor.resumeEditing();
! 276: this.tool.setTableClass(className);
! 277: this.editor.suspendEditing();
! 278: };
! 279: this.setColumnAlign = function(align) {
! 280: this.editor.resumeEditing();
! 281: this.tool.setColumnAlign(align);
! 282: this.editor.suspendEditing();
! 283: };
! 284: };
! 285:
! 286: TableDrawer.prototype = new Drawer;
! 287:
! 288: function LibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement) {
! 289: /* a drawer that loads XSLT and XML from the server
! 290: and converts the XML to XHTML for the drawer using the XSLT
! 291:
! 292: there are 2 types of XML file loaded from the server: the first
! 293: contains a list of 'libraries', partitions for the data items,
! 294: and the second a list of data items for a certain library
! 295:
! 296: all XML loading is done async, since sync loading can freeze Mozilla
! 297: */
! 298:
! 299: this.init = function(tool, xsluri, libsuri, searchuri, baseelement) {
! 300: /* This method is there to thin out the constructor and to be
! 301: able to inherit it in sub-prototypes. Don't confuse this
! 302: method with the component initializer (initialize()).
! 303: */
! 304: // these are used in the XSLT. Maybe they should be
! 305: // parameterized or something, but we depend on so many other
! 306: // things implicitly anyway...
! 307: this.drawerid = 'kupu-librarydrawer';
! 308: this.librariespanelid = 'kupu-librariespanel';
! 309: this.resourcespanelid = 'kupu-resourcespanel';
! 310: this.propertiespanelid = 'kupu-propertiespanel';
! 311:
! 312: if (baseelement) {
! 313: this.baseelement = getFromSelector(baseelement);
! 314: } else {
! 315: this.baseelement = getBaseTagClass(document.body, 'div', 'kupu-librarydrawer-parent');
! 316: }
! 317:
! 318: this.tool = tool;
! 319: this.element = document.getElementById(this.drawerid);
! 320: if (!this.element) {
! 321: var e = document.createElement('div');
! 322: e.id = this.drawerid;
! 323: e.className = 'kupu-drawer '+this.drawerid;
! 324: this.baseelement.appendChild(e);
! 325: this.element = e;
! 326: }
! 327: this.shared.xsluri = xsluri;
! 328: this.shared.libsuri = libsuri;
! 329: this.shared.searchuri = searchuri;
! 330:
! 331: // marker that gets set when a new image has been uploaded
! 332: this.shared.newimages = null;
! 333:
! 334: // the following vars will be available after this.initialize()
! 335: // has been called
! 336:
! 337: // this will be filled by this._libXslCallback()
! 338: this.shared.xsl = null;
! 339: // this will be filled by this.loadLibraries(), which is called
! 340: // somewhere further down the chain starting with
! 341: // this._libsXslCallback()
! 342: this.shared.xmldata = null;
! 343:
! 344: };
! 345: if (tool) {
! 346: this.init(tool, xsluri, libsuri, searchuri);
! 347: }
! 348:
! 349: this.initialize = function(editor, drawertool) {
! 350: this.editor = editor;
! 351: this.drawertool = drawertool;
! 352: this.selecteditemid = '';
! 353:
! 354: // load the xsl and the initial xml
! 355: var wrapped_callback = new ContextFixer(this._libsXslCallback, this);
! 356: this._loadXML(this.shared.xsluri, wrapped_callback.execute);
! 357: };
! 358:
! 359: /*** bootstrapping ***/
! 360:
! 361: this._libsXslCallback = function(dom) {
! 362: /* callback for when the xsl for the libs is loaded
! 363:
! 364: this is called on init and since the initial libs need
! 365: to be loaded as well (and everything is async with callbacks
! 366: so there's no way to wait until the XSL is loaded) this
! 367: will also make the first loadLibraries call
! 368: */
! 369: this.shared.xsl = dom;
! 370:
! 371: // Change by Paul to have cached xslt transformers for reuse of
! 372: // multiple transforms and also xslt params
! 373: try {
! 374: var xsltproc = new XSLTProcessor();
! 375: this.shared.xsltproc = xsltproc;
! 376: xsltproc.importStylesheet(dom);
! 377: xsltproc.setParameter("", "drawertype", this.drawertype);
! 378: xsltproc.setParameter("", "drawertitle", this.drawertitle);
! 379: xsltproc.setParameter("", "showupload", this.showupload);
! 380: if (this.editor.config.captions) {
! 381: xsltproc.setParameter("", "usecaptions", 'yes');
! 382: }
! 383: } catch(e) {
! 384: return; // No XSLT Processor, maybe IE 5.5?
! 385: }
! 386: };
! 387:
! 388: this.createContent = function() {
! 389: // Make sure the drawer XML is in the current Kupu instance
! 390: if (this.element.parentNode != this.baseelement) {
! 391: this.baseelement.appendChild(this.element);
! 392: }
! 393: // load the initial XML
! 394: if(!this.shared.xmldata) {
! 395: // Do a meaningful test to see if this is IE5.5 or some other
! 396: // editor-enabled version whose XML support isn't good enough
! 397: // for the drawers
! 398: if (!window.XSLTProcessor) {
! 399: alert("This function requires better XML support in your browser.");
! 400: return;
! 401: }
! 402: this.loadLibraries();
! 403: } else {
! 404: if (this.shared.newimages) {
! 405: this.reloadCurrent();
! 406: this.shared.newimages = null;
! 407: };
! 408: this.updateDisplay();
! 409: this.initialSelection();
! 410: };
! 411:
! 412: // display the drawer div
! 413: this.element.style.display = 'block';
! 414: };
! 415:
! 416: this._singleLibsXslCallback = function(dom) {
! 417: /* callback for then the xsl for single libs (items) is loaded
! 418:
! 419: nothing special needs to be called here, since initially the
! 420: items pane will be empty
! 421: */
! 422: this.singlelibxsl = dom;
! 423: };
! 424:
! 425: this.loadLibraries = function() {
! 426: /* load the libraries and display them in a redrawn drawer */
! 427: var wrapped_callback = new ContextFixer(this._libsContentCallback, this);
! 428: this._loadXML(this.shared.libsuri, wrapped_callback.execute);
! 429: };
! 430:
! 431: this._libsContentCallback = function(dom) {
! 432: /* this is called when the libs xml is loaded
! 433:
! 434: does the xslt transformation to set up or renew the drawer's full
! 435: content and adds the content to the drawer
! 436: */
! 437: this.shared.xmldata = dom;
! 438: this.shared.xmldata.setProperty("SelectionLanguage", "XPath");
! 439:
! 440: // replace whatever is in there with our stuff
! 441: this.updateDisplay(this.drawerid);
! 442: this.initialSelection();
! 443: };
! 444:
! 445: this.initialSelection = function() {
! 446: var libnode_path = '/libraries/library[@selected]';
! 447: var libnode = this.shared.xmldata.selectSingleNode(libnode_path);
! 448: if (libnode) {
! 449: var id = libnode.getAttribute('id');
! 450: this.selectLibrary(id);
! 451: }
! 452: }
! 453:
! 454: this.updateDisplay = function(id) {
! 455: /* (re-)transform XML and (re-)display the necessary part
! 456: */
! 457: if(!id) {
! 458: id = this.drawerid;
! 459: };
! 460: try {
! 461: this.shared.xsltproc.setParameter("", "showupload", this.showupload);
! 462: } catch(e) {};
! 463: var doc = this._transformXml();
! 464: var sourcenode = doc.selectSingleNode('//*[@id="'+id+'"]');
! 465: var targetnode = document.getElementById(id);
! 466: sourcenode = document.importNode(sourcenode, true);
! 467: Sarissa.copyChildNodes(sourcenode, targetnode);
! 468: if (!this.focussed) {
! 469: this.focusElement();
! 470: }
! 471:
! 472: if (this.editor.getBrowserName() == 'IE' && id == this.resourcespanelid) {
! 473: this.updateDisplay(this.drawerid);
! 474: };
! 475: };
! 476:
! 477: this.deselectActiveCollection = function() {
! 478: /* Deselect the currently active collection or library */
! 479: while (1) {
! 480: // deselect selected DOM node
! 481: var selected = this.shared.xmldata.selectSingleNode('//*[@selected]');
! 482: if (!selected) {
! 483: return;
! 484: };
! 485: selected.removeAttribute('selected');
! 486: };
! 487: };
! 488:
! 489: /*** Load a library ***/
! 490:
! 491: this.selectLibrary = function(id) {
! 492: /* unselect the currently selected lib and select a new one
! 493:
! 494: the selected lib (libraries pane) will have a specific CSS class
! 495: (selected)
! 496: */
! 497: // remove selection in the DOM
! 498: this.deselectActiveCollection();
! 499: // as well as visual selection in CSS
! 500: // XXX this is slow, but we can't do XPath, unfortunately
! 501: var divs = this.element.getElementsByTagName('div');
! 502: for (var i=0; i<divs.length; i++ ) {
! 503: if (divs[i].className == 'kupu-libsource-selected') {
! 504: divs[i].className = 'kupu-libsource';
! 505: };
! 506: };
! 507:
! 508: var libnode_path = '/libraries/library[@id="' + id + '"]';
! 509: var libnode = this.shared.xmldata.selectSingleNode(libnode_path);
! 510: libnode.setAttribute('selected', '1');
! 511:
! 512: var items_xpath = "items";
! 513: var items_node = libnode.selectSingleNode(items_xpath);
! 514:
! 515: if (items_node && !this.shared.newimages) {
! 516: // The library has already been loaded before or was
! 517: // already provided with an items list. No need to do
! 518: // anything except for displaying the contents in the
! 519: // middle pane. Newimages is set if we've lately
! 520: // added an image.
! 521: this.updateDisplay(this.resourcespanelid);
! 522: this.updateDisplay(this.propertiespanelid);
! 523: } else {
! 524: // We have to load the library from XML first.
! 525: var src_uri = libnode.selectSingleNode('src/text()').nodeValue;
! 526: src_uri = src_uri.strip(); // needs kupuhelpers.js
! 527: // Now load the library into the items pane. Since we have
! 528: // to load the XML, do this via a call back
! 529: var wrapped_callback = new ContextFixer(this._libraryContentCallback, this);
! 530: this._loadXML(src_uri, wrapped_callback.execute, null);
! 531: this.shared.newimages = null;
! 532: };
! 533: // instead of running the full transformations again we get a
! 534: // reference to the element and set the classname...
! 535: var newseldiv = document.getElementById(id);
! 536: newseldiv.className = 'kupu-libsource-selected';
! 537: };
! 538:
! 539: this._libraryContentCallback = function(dom, src_uri) {
! 540: /* callback for when a library's contents (item list) is loaded
! 541:
! 542: This is also used as he handler for reloading a standard
! 543: collection.
! 544: */
! 545: var libnode = this.shared.xmldata.selectSingleNode('//*[@selected]');
! 546: var itemsnode = libnode.selectSingleNode("items");
! 547: var newitemsnode = dom.selectSingleNode("//items");
! 548:
! 549: // IE does not support importNode on XML document nodes. As an
! 550: // evil hack, clonde the node instead.
! 551:
! 552: if (this.editor.getBrowserName() == 'IE') {
! 553: newitemsnode = newitemsnode.cloneNode(true);
! 554: } else {
! 555: newitemsnode = this.shared.xmldata.importNode(newitemsnode, true);
! 556: }
! 557: if (!itemsnode) {
! 558: // We're loading this for the first time
! 559: libnode.appendChild(newitemsnode);
! 560: } else {
! 561: // User has clicked reload
! 562: libnode.replaceChild(newitemsnode, itemsnode);
! 563: };
! 564: this.updateDisplay(this.resourcespanelid);
! 565: this.updateDisplay(this.propertiespanelid);
! 566: };
! 567:
! 568: /*** Load a collection ***/
! 569:
! 570: this.selectCollection = function(id) {
! 571: this.deselectActiveCollection();
! 572:
! 573: // First turn off current selection, if any
! 574: this.removeSelection();
! 575:
! 576: var leafnode_path = "//collection[@id='" + id + "']";
! 577: var leafnode = this.shared.xmldata.selectSingleNode(leafnode_path);
! 578:
! 579: // Case 1: We've already loaded the data, so we just need to
! 580: // refer to the data by id.
! 581: var loadedInNode = leafnode.getAttribute('loadedInNode');
! 582: if (loadedInNode) {
! 583: var collnode_path = "/libraries/collection[@id='" + loadedInNode + "']";
! 584: var collnode = this.shared.xmldata.selectSingleNode(collnode_path);
! 585: if (collnode) {
! 586: collnode.setAttribute('selected', '1');
! 587: this.updateDisplay(this.resourcespanelid);
! 588: this.updateDisplay(this.propertiespanelid);
! 589: return;
! 590: };
! 591: };
! 592:
! 593: // Case 2: We've already loaded the data, but there hasn't
! 594: // been a reference made yet. So, make one :)
! 595: uri = leafnode.selectSingleNode('uri/text()').nodeValue;
! 596: uri = (new String(uri)).strip(); // needs kupuhelpers.js
! 597: var collnode_path = "/libraries/collection/uri[text()='" + uri + "']/..";
! 598: var collnode = this.shared.xmldata.selectSingleNode(collnode_path);
! 599: if (collnode) {
! 600: id = collnode.getAttribute('id');
! 601: leafnode.setAttribute('loadedInNode', id);
! 602: collnode.setAttribute('selected', '1');
! 603: this.updateDisplay(this.resourcespanelid);
! 604: this.updateDisplay(this.propertiespanelid);
! 605: return;
! 606: };
! 607:
! 608: // Case 3: We've not loaded the data yet, so we need to load it
! 609: // this is just so we can find the leafnode much easier in the
! 610: // callback.
! 611: leafnode.setAttribute('selected', '1');
! 612: var src_uri = leafnode.selectSingleNode('src/text()').nodeValue;
! 613: src_uri = src_uri.strip(); // needs kupuhelpers.js
! 614: var wrapped_callback = new ContextFixer(this._collectionContentCallback, this);
! 615: this._loadXML(src_uri, wrapped_callback.execute, null);
! 616: };
! 617:
! 618: this._collectionContentCallback = function(dom, src_uri) {
! 619: // Unlike with libraries, we don't have to find a node to hook
! 620: // our results into (UNLESS we've hit the reload button, but
! 621: // that is handled in _libraryContentCallback anyway).
! 622: // We need to give the newly retrieved data a unique ID, we
! 623: // just use the time.
! 624: date = new Date();
! 625: time = date.getTime();
! 626:
! 627: // attach 'loadedInNode' attribute to leaf node so Case 1
! 628: // applies next time.
! 629: var leafnode = this.shared.xmldata.selectSingleNode('//*[@selected]');
! 630: leafnode.setAttribute('loadedInNode', time);
! 631: this.deselectActiveCollection()
! 632:
! 633: var collnode = dom.selectSingleNode('/collection');
! 634: collnode.setAttribute('id', time);
! 635: collnode.setAttribute('selected', '1');
! 636:
! 637: var libraries = this.shared.xmldata.selectSingleNode('/libraries');
! 638:
! 639: // IE does not support importNode on XML documet nodes
! 640: if (this.editor.getBrowserName() == 'IE') {
! 641: collnode = collnode.cloneNode(true);
! 642: } else {
! 643: collnode = this.shared.xmldata.importNode(collnode, true);
! 644: }
! 645: libraries.appendChild(collnode);
! 646: this.updateDisplay(this.resourcespanelid);
! 647: this.updateDisplay(this.propertiespanelid);
! 648: };
! 649:
! 650: /*** Reloading a collection or library ***/
! 651:
! 652: this.reloadCurrent = function() {
! 653: // Reload current collection or library
! 654: this.showupload = '';
! 655: var current = this.shared.xmldata.selectSingleNode('//*[@selected]');
! 656: // make sure we're dealing with a collection even though a
! 657: // resource might be selected
! 658: if (current.tagName == "resource") {
! 659: current.removeAttribute("selected");
! 660: current = current.parentNode;
! 661: current.setAttribute("selected", "1");
! 662: };
! 663: var src_node = current.selectSingleNode('src');
! 664: if (!src_node) {
! 665: // simply do nothing if the library cannot be reloaded. This
! 666: // is currently the case w/ search result libraries.
! 667: return;
! 668: };
! 669:
! 670: var src_uri = src_node.selectSingleNode('text()').nodeValue;
! 671:
! 672: src_uri = src_uri.strip(); // needs kupuhelpers.js
! 673:
! 674: var wrapped_callback = new ContextFixer(this._libraryContentCallback, this);
! 675: this._loadXML(src_uri, wrapped_callback.execute);
! 676: };
! 677:
! 678: this.removeSelection = function() {
! 679: // turn off current selection, if any
! 680: var oldselxpath = '/libraries/*[@selected]//resource[@selected]';
! 681: var oldselitem = this.shared.xmldata.selectSingleNode(oldselxpath);
! 682: if (oldselitem) {
! 683: oldselitem.removeAttribute("selected");
! 684: };
! 685: if (this.selecteditemid) {
! 686: var item = document.getElementById(this.selecteditemid);
! 687: if (item) {
! 688: var span = item.getElementsByTagName('span');
! 689: if (span.length > 0) {
! 690: span = span[0];
! 691: span.className = span.className.replace(' selected-item', '');
! 692: }
! 693: }
! 694: this.selecteditemid = '';
! 695: }
! 696: this.showupload = '';
! 697: }
! 698:
! 699: this.selectUpload = function() {
! 700: this.removeSelection();
! 701: this.showupload = 'yes';
! 702: this.updateDisplay(this.resourcespanelid);
! 703: this.updateDisplay(this.propertiespanelid);
! 704: }
! 705: /*** Selecting a resource ***/
! 706:
! 707: this.selectItem = function (item, id) {
! 708: /* select an item in the item pane, show the item's metadata */
! 709:
! 710: // First turn off current selection, if any
! 711: this.removeSelection();
! 712:
! 713: // Grab XML DOM node for clicked "resource" and mark it selected
! 714: var newselxpath = '/libraries/*[@selected]//resource[@id="' + id + '"]';
! 715: var newselitem = this.shared.xmldata.selectSingleNode(newselxpath);
! 716: newselitem.setAttribute("selected", "1");
! 717: //this.updateDisplay(this.resourcespanelid);
! 718: this.updateDisplay(this.propertiespanelid);
! 719:
! 720: // Don't want to reload the resource panel xml as it scrolls to
! 721: // the top.
! 722: var span = item.getElementsByTagName('span');
! 723: if (span.length > 0) {
! 724: span = span[0];
! 725: span.className += ' selected-item';
! 726: }
! 727: this.selecteditemid = id;
! 728: if (this.editor.getBrowserName() == 'IE') {
! 729: var ppanel = document.getElementById(this.propertiespanelid)
! 730: var height = ppanel.clientHeight;
! 731: if (height > ppanel.scrollHeight) height = ppanel.scrollHeight;
! 732: if (height < 260) height = 260;
! 733: document.getElementById(this.resourcespanelid).style.height = height+'px';
! 734: }
! 735: return;
! 736: }
! 737:
! 738:
! 739: this.search = function() {
! 740: /* search */
! 741: var searchvalue = getFromSelector('kupu-searchbox-input').value;
! 742: //XXX make search variable configurable
! 743: var body = 'SearchableText=' + escape(searchvalue);
! 744:
! 745: // the search uri might contain query parameters in HTTP GET
! 746: // style. We want to do a POST though, so find any possible
! 747: // parameters, trim them from the URI and append them to the
! 748: // POST body instead.
! 749: var chunks = this.shared.searchuri.split('?');
! 750: var searchuri = chunks[0];
! 751: if (chunks[1]) {
! 752: body += "&" + chunks[1];
! 753: };
! 754: var wrapped_callback = new ContextFixer(this._searchCallback, this);
! 755: this._loadXML(searchuri, wrapped_callback.execute, body);
! 756: };
! 757:
! 758: this._searchCallback = function(dom) {
! 759: var resultlib = dom.selectSingleNode("/library");
! 760:
! 761: var items = resultlib.selectNodes("items/*");
! 762: if (!items.length) {
! 763: alert("No results found.");
! 764: return;
! 765: };
! 766:
! 767: // we need to give the newly retrieved data a unique ID, we
! 768: // just use the time.
! 769: date = new Date();
! 770: time = date.getTime();
! 771: resultlib.setAttribute("id", time);
! 772:
! 773: // deselect the previous collection and mark the result
! 774: // library as selected
! 775: this.deselectActiveCollection();
! 776: resultlib.setAttribute("selected", "1");
! 777:
! 778: // now hook the result library into our DOM
! 779: if (this.editor.getBrowserName() == 'IE') {
! 780: resultlib = resultlib.cloneNode(true);
! 781: } else {
! 782: this.shared.xmldata.importNode(resultlib, true);
! 783: }
! 784: var libraries = this.shared.xmldata.selectSingleNode("/libraries");
! 785: libraries.appendChild(resultlib);
! 786:
! 787: this.updateDisplay(this.drawerid);
! 788: var newseldiv = getFromSelector(time);
! 789: newseldiv.className = 'selected';
! 790: };
! 791:
! 792: this.save = function() {
! 793: /* save the element, should be implemented on subclasses */
! 794: throw "Not yet implemented";
! 795: };
! 796:
! 797: /*** Auxiliary methods ***/
! 798:
! 799: this._transformXml = function() {
! 800: /* transform this.shared.xmldata to HTML using this.shared.xsl and return it */
! 801: var doc = Sarissa.getDomDocument();
! 802: var result = this.shared.xsltproc.transformToDocument(this.shared.xmldata);
! 803: return result;
! 804: };
! 805:
! 806: this._loadXML = function(uri, callback, body) {
! 807: /* load the XML from a uri
! 808:
! 809: calls callback with one arg (the XML DOM) when done
! 810: the (optional) body arg should contain the body for the request
! 811: */
! 812: var xmlhttp = new XMLHttpRequest();
! 813: var method = 'GET';
! 814: if (body) {
! 815: method = 'POST';
! 816: } else {
! 817: // be sure that body is null and not an empty string or
! 818: // something
! 819: body = null;
! 820: };
! 821: xmlhttp.open(method, uri, true);
! 822: // use ContextFixer to wrap the Sarissa callback, both for isolating
! 823: // the 'this' problem and to be able to pass in an extra argument
! 824: // (callback)
! 825: var wrapped_callback = new ContextFixer(this._sarissaCallback, xmlhttp,
! 826: callback, uri);
! 827: xmlhttp.onreadystatechange = wrapped_callback.execute;
! 828: if (method == "POST") {
! 829: // by default, we would send a 'text/xml' request, which
! 830: // is a dirty lie; explicitly set the content type to what
! 831: // a web server expects from a POST.
! 832: xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
! 833: };
! 834: xmlhttp.send(body);
! 835: };
! 836:
! 837: this._sarissaCallback = function(user_callback, uri) {
! 838: /* callback for Sarissa
! 839: when the callback is called because the data's ready it
! 840: will get the responseXML DOM and call user_callback
! 841: with the DOM as the first argument and the uri loaded
! 842: as the second
! 843:
! 844: note that this method should be called in the context of an
! 845: xmlhttp object
! 846: */
! 847: var errmessage = 'Error loading XML: ';
! 848: if (uri) {
! 849: errmessage = 'Error loading ' + uri + ':';
! 850: };
! 851: if (this.readyState == 4) {
! 852: if (this.status && this.status != 200) {
! 853: alert(errmessage + this.status);
! 854: throw "Error loading XML";
! 855: };
! 856: var dom = this.responseXML;
! 857: user_callback(dom, uri);
! 858: };
! 859: };
! 860: };
! 861:
! 862: LibraryDrawer.prototype = new Drawer;
! 863: LibraryDrawer.prototype.shared = {}; // Shared data
! 864:
! 865: function ImageLibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement) {
! 866: /* a specific LibraryDrawer for images */
! 867:
! 868: this.drawertitle = "Insert Image";
! 869: this.drawertype = "image";
! 870: this.showupload = '';
! 871: if (tool) {
! 872: this.init(tool, xsluri, libsuri, searchuri, baseelement);
! 873: }
! 874:
! 875:
! 876: // upload, on submit/insert press
! 877: this.uploadImage = function() {
! 878: var form = document.kupu_upload_form;
! 879: if (!form || form.node_prop_image.value=='') return;
! 880:
! 881: if (form.node_prop_caption.value == "") {
! 882: alert("Please enter a title for the image you are uploading");
! 883: return;
! 884: };
! 885:
! 886: var targeturi = this.shared.xmldata.selectSingleNode('/libraries/*[@selected]/uri/text()').nodeValue
! 887: document.kupu_upload_form.action = targeturi + "/kupuUploadImage";
! 888: document.kupu_upload_form.submit();
! 889: };
! 890:
! 891: // called for example when no permission to upload for some reason
! 892: this.cancelUpload = function(msg) {
! 893: var s = this.shared.xmldata.selectSingleNode('/libraries/*[@selected]');
! 894: s.removeAttribute("selected");
! 895: this.updateDisplay();
! 896: if (msg != '') {
! 897: alert(msg);
! 898: };
! 899: };
! 900:
! 901: // called by onLoad within document sent by server
! 902: this.finishUpload = function(url) {
! 903: this.editor.resumeEditing();
! 904: var imgclass = 'image-inline';
! 905: if (this.editor.config.captions) {
! 906: imgclass += " captioned";
! 907: };
! 908: this.tool.createImage(url, null, imgclass);
! 909: this.shared.newimages = 1;
! 910: this.drawertool.closeDrawer();
! 911: };
! 912:
! 913:
! 914: this.save = function() {
! 915: this.editor.resumeEditing();
! 916: /* create an image in the iframe according to collected data
! 917: from the drawer */
! 918: var selxpath = '//resource[@selected]';
! 919: var selnode = this.shared.xmldata.selectSingleNode(selxpath);
! 920:
! 921: // If no image resource is selected, check for upload
! 922: if (!selnode) {
! 923: var uploadbutton = this.shared.xmldata.selectSingleNode("/libraries/*[@selected]//uploadbutton");
! 924: if (uploadbutton) {
! 925: this.uploadImage();
! 926: };
! 927: return;
! 928: };
! 929:
! 930: var uri = selnode.selectSingleNode('uri/text()').nodeValue;
! 931: uri = uri.strip(); // needs kupuhelpers.js
! 932: var alt = getFromSelector('image_alt').value;
! 933:
! 934: var radios = document.getElementsByName('image-align');
! 935: for (var i = 0; i < radios.length; i++) {
! 936: if (radios[i].checked) {
! 937: var imgclass = radios[i].value;
! 938: };
! 939: };
! 940:
! 941: var caption = document.getElementsByName('image-caption');
! 942: if (caption && caption.length>0 && caption[0].checked) {
! 943: imgclass += " captioned";
! 944: };
! 945:
! 946: this.tool.createImage(uri, alt, imgclass);
! 947: this.drawertool.closeDrawer();
! 948: };
! 949: };
! 950:
! 951: ImageLibraryDrawer.prototype = new LibraryDrawer;
! 952: ImageLibraryDrawer.prototype.shared = {}; // Shared data
! 953:
! 954: function LinkLibraryDrawer(tool, xsluri, libsuri, searchuri, baseelement) {
! 955: /* a specific LibraryDrawer for links */
! 956:
! 957: this.drawertitle = "Insert Link";
! 958: this.drawertype = "link";
! 959: this.showupload = '';
! 960: if (tool) {
! 961: this.init(tool, xsluri, libsuri, searchuri, baseelement);
! 962: }
! 963:
! 964: this.save = function() {
! 965: this.editor.resumeEditing();
! 966: /* create a link in the iframe according to collected data
! 967: from the drawer */
! 968: var selxpath = '//resource[@selected]';
! 969: var selnode = this.shared.xmldata.selectSingleNode(selxpath);
! 970: if (!selnode) {
! 971: return;
! 972: };
! 973:
! 974: var uri = selnode.selectSingleNode('uri/text()').nodeValue;
! 975: uri = uri.strip(); // needs kupuhelpers.js
! 976: var title = '';
! 977: title = selnode.selectSingleNode('title/text()').nodeValue;
! 978: title = title.strip();
! 979:
! 980: // XXX requiring the user to know what link type to enter is a
! 981: // little too much I think. (philiKON)
! 982: var type = null;
! 983: var name = getFromSelector('link_name').value;
! 984: var target = null;
! 985: if (getFromSelector('link_target') && getFromSelector('link_target').value != '')
! 986: target = getFromSelector('link_target').value;
! 987:
! 988: this.tool.createLink(uri, type, name, target, title);
! 989: this.drawertool.closeDrawer();
! 990: };
! 991: };
! 992:
! 993: LinkLibraryDrawer.prototype = new LibraryDrawer;
! 994: LinkLibraryDrawer.prototype.shared = {}; // Shared data
! 995:
! 996: /* Function to suppress enter key in drawers */
! 997: function HandleDrawerEnter(event, clickid) {
! 998: var key;
! 999: event = event || window.event;
! 1000: key = event.which || event.keyCode;
! 1001:
! 1002: if (key==13) {
! 1003: if (clickid) {
! 1004: var button = document.getElementById(clickid);
! 1005: if (button) {
! 1006: button.click();
! 1007: }
! 1008: }
! 1009: event.cancelBubble = true;
! 1010: if (event.stopPropogation) event.stopPropogation();
! 1011:
! 1012: return false;
! 1013: }
! 1014: return true;
! 1015: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>