Annotation of kupu/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>