Changeset 3560

Show
Ignore:
Timestamp:
01/21/07 00:33:50 (2 years ago)
Author:
timothy
Message:

Fixes up many things about the Web Interface plugin. Now has cleaner JavaScript? and uses Prototype.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Chat Core.xcodeproj/project.pbxproj

    r3539 r3560  
    396396                        isa = PBXProject; 
    397397                        buildConfigurationList = 1C041DDE08553AD200A5A5BA /* Build configuration list for PBXProject "Chat Core" */; 
    398                         compatibilityVersion = "Xcode 2.4"; 
    399398                        hasScannedForEncodings = 1; 
    400399                        knownRegions = ( 
     
    418417                        projectDirPath = ""; 
    419418                        projectRoot = ""; 
    420                         shouldCheckCompatibility = 1; 
    421419                        targets = ( 
    422420                                1C51B46E052DE0CB00BB459B /* Chat Core (Framework) */, 
  • trunk/Colloquy.xcodeproj/project.pbxproj

    r3465 r3560  
    19161916                        isa = PBXProject; 
    19171917                        buildConfigurationList = 1C041A700854E97700A5A5BA /* Build configuration list for PBXProject "Colloquy" */; 
    1918                         compatibilityVersion = "Xcode 2.4"; 
    19191918                        hasScannedForEncodings = 1; 
    19201919                        knownRegions = ( 
     
    19661965                        ); 
    19671966                        projectRoot = ""; 
    1968                         shouldCheckCompatibility = 1; 
    19691967                        targets = ( 
    19701968                                1CB2CCF5052DDC560094AAA4 /* Colloquy (Application) */, 
  • trunk/Plug-Ins/Web Interface/JVWebInterfacePlugin.m

    r3552 r3560  
    284284        NSString *shell = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"template" ofType:@"html"] encoding:NSUTF8StringEncoding error:NULL]; 
    285285 
    286         NSURL *bodyShellLocation = [[panel style] bodyTemplateLocationWithName:[[panel display] bodyTemplate]]; 
    287  
    288         NSString *bodyShell = @""; 
    289         if( bodyShellLocation ) 
    290                 bodyShell = [NSString stringWithContentsOfURL:bodyShellLocation encoding:NSUTF8StringEncoding error:NULL]; 
    291  
    292         bodyShell = ( [bodyShell length] ? [NSString stringWithFormat:bodyShell, @"/resources", ( content ? content : @"" )] : ( content ? content : @"" ) ); 
     286        NSString *bodyTemplate = [[panel style] contentsOfBodyTemplateWithName:[[panel display] bodyTemplate]]; 
     287        if( [bodyTemplate length] && [content length] ) { 
     288                if( [bodyTemplate rangeOfString:@"%@"].location != NSNotFound ) 
     289                        bodyTemplate = [NSString stringWithFormat:bodyTemplate, content]; 
     290                else bodyTemplate = [bodyTemplate stringByAppendingString:content]; 
     291        } else if( ! [bodyTemplate length] && [content length] ) { 
     292                bodyTemplate = content; 
     293        } 
    293294 
    294295        int fontSize = [[[panel display] preferences] defaultFontSize]; 
     
    296297        NSString *header = [NSString stringWithFormat:@"<style type=\"text/css\">body { font-size: %dpx; font-family: %@ }</style>", fontSize, fontFamily]; 
    297298 
    298         return [NSString stringWithFormat:shell, [panel description], header, @"/resources", emoticonStyleSheet, mainStyleSheet, variant, baseLocation, bodyShell]; 
     299        return [NSString stringWithFormat:shell, [panel description], header, @"/resources", emoticonStyleSheet, mainStyleSheet, variant, baseLocation, bodyTemplate]; 
    299300} 
    300301 
     
    367368                [styles setObject:[[panel style] identifier] forKey:[panel uniqueIdentifier]]; 
    368369 
    369                 DOMHTMLDocument *document = (DOMHTMLDocument *)[[[panel display] mainFrame] DOMDocument]; 
     370                DOMHTMLDocument *document = (DOMHTMLDocument *)[[[[panel display] mainFrame] findFrameNamed:@"content"] DOMDocument]; 
    370371                DOMHTMLElement *bodyNode = (DOMHTMLElement *)[document getElementById:@"contents"]; 
    371372                if( ! bodyNode ) bodyNode = (DOMHTMLElement *)[document body]; 
     
    397398 
    398399        if( panel ) { 
    399                 NSString *text = [[[NSString alloc] initWithData:[arguments objectForKey:JVWebInterfaceRequestContent] encoding:NSUTF8StringEncoding] autorelease]; 
     400                NSString *text = [[NSString alloc] initWithData:[arguments objectForKey:JVWebInterfaceRequestContent] encoding:NSUTF8StringEncoding]; 
    400401                NSArray *strings = [text componentsSeparatedByString:@"\n"]; 
    401402                NSEnumerator *enumerator = [strings objectEnumerator]; 
     403                [text release]; 
    402404 
    403405                while( ( text = [enumerator nextObject] ) ) { 
     
    415417 
    416418                                arguments = [text substringWithRange:NSMakeRange( [scanner scanLocation], [text length] - [scanner scanLocation] )]; 
    417                                 arguments = [[[NSAttributedString alloc] initWithString:arguments] autorelease]; 
     419                                arguments = [[NSAttributedString alloc] initWithString:arguments]; 
    418420 
    419421                                if( ! ( handled = [panel processUserCommand:command withArguments:arguments] ) && [[panel connection] isConnected] ) 
    420422                                        [[panel connection] sendRawMessage:[command stringByAppendingFormat:@" %@", [arguments string]]]; 
     423 
     424                                [arguments release]; 
    421425                        } else { 
    422426                                if( [text hasPrefix:@"//"] ) text = [text substringWithRange:NSMakeRange( 1, [text length] - 1 )]; 
     
    497501        [element setAttributesAsDictionary:attributes]; 
    498502 
     503        NSMutableDictionary *styleParams = [[[view display] styleParameters] mutableCopy]; 
     504 
     505        if( [message consecutiveOffset] > 0 ) 
     506                [styleParams setObject:@"'yes'" forKey:@"consecutiveMessage"]; 
     507 
    499508        NSEnumerator *enumerator = [_clients objectEnumerator]; 
    500509        NSDictionary *info = nil; 
     
    505514 
    506515                JVStyle *style = [JVStyle styleWithIdentifier:[[info objectForKey:@"originalStyles"] objectForKey:[view uniqueIdentifier]]]; 
    507                 NSString *tmessage = [style transformChatMessage:message withParameters:[[view display] styleParameters]]; // this will break once styles use custom styleParameters!! 
    508  
    509                 NSXMLNode *body = [[[NSXMLNode alloc] initWithKind:NSXMLTextKind options:NSXMLNodeIsCDATA] autorelease]; 
     516                NSString *tmessage = [style transformChatMessage:message withParameters:styleParams]; // this will break once styles use custom styleParameters!! 
     517 
     518                NSXMLNode *body = [[NSXMLNode alloc] initWithKind:NSXMLTextKind options:NSXMLNodeIsCDATA]; 
    510519                [body setStringValue:tmessage]; 
    511520 
     
    513522                [copy addChild:body]; 
    514523                [[doc rootElement] addChild:copy]; 
     524 
     525                [body release]; 
    515526                [copy release]; 
    516527        } 
     528 
     529        [styleParams release]; 
    517530} 
    518531 
  • trunk/Plug-Ins/Web Interface/Resources/base.css

    r3026 r3560  
    8686 
    8787.listItem.member:before { 
    88         content: url( /resources/person.tif ); 
     88        content: url( /resources/person.png ); 
    8989} 
    9090 
    9191.listItem.member.server.operator:before { 
    92         content: url( /resources/admin.tif ); 
     92        content: url( /resources/admin.png ); 
    9393} 
    9494 
    9595.listItem.member.operator:before { 
    96         content: url( /resources/op.tif ); 
     96        content: url( /resources/op.png ); 
    9797} 
    9898 
    9999.listItem.member.half.operator:before { 
    100         content: url( /resources/op.tif ); 
     100        content: url( /resources/half-op.png ); 
    101101} 
    102102 
    103103.listItem.member.voice:before { 
    104         content: url( /resources/voice.tif ); 
     104        content: url( /resources/voice.png ); 
    105105} 
    106106 
  • trunk/Plug-Ins/Web Interface/Resources/common.js

    r3037 r3560  
    1 var panels = new Array(); 
    2 var queueCheckInterval = null; 
    3 var queueCheckSpeed = 4000; 
     1function extendClass( subClass, baseClass ) { 
     2        function inheritance() {} 
     3        inheritance.prototype = baseClass.prototype; 
     4 
     5        subClass.prototype = new inheritance(); 
     6        subClass.prototype.constructor = subClass; 
     7        subClass.baseConstructor = baseClass; 
     8        subClass.superClass = baseClass.prototype; 
     9
     10 
     11var activityCheckInterval = null; 
     12var activityCheckSpeed = 4000; 
    413var scrollBackLimit = 300; 
    514var activePanel = null; 
    615var foreground = true; 
    7 var currentRequest = null; 
    8  
    9 function createRequestObject() { 
    10         if( navigator.appName == "Microsoft Internet Explorer" ) 
    11                 return new ActiveXObject( "Microsoft.XMLHTTP" ); 
    12         return new XMLHttpRequest(); 
    13 
    14  
    15 function setup() { 
    16         document.body.addEventListener( "keypress", documentKeyInput, true ); 
    17         document.getElementById( "input" ).addEventListener( "keypress", inputKeyPressed, false ); 
    18         document.body.addEventListener( "blur", windowBlured, false ); 
    19         document.body.addEventListener( "focus", windowFocused, false ); 
    20  
    21         currentRequest = createRequestObject(); 
    22         currentRequest.onreadystatechange = processSetup; 
    23         currentRequest.open( "GET", "/command/setup" ); 
    24         currentRequest.send( null ); 
    25 
    26  
    27 function windowBlured() { 
    28         foreground = false; 
    29         document.getElementById( "timer" ).innerText = "blured"; 
    30 
    31  
    32 function windowFocused() { 
    33         foreground = true; 
    34         activePanel.newMessage = 0; 
    35         activePanel.newHighlightMessage = 0; 
    36         activePanel.listItem.className = activePanel.listItem.className.replace( /\s*newMessage/g, "" ); 
    37         activePanel.listItem.className = activePanel.listItem.className.replace( /\s*newHighlight/g, "" ); 
    38         activePanel.listItem.title = "No messages waiting"; 
    39         document.getElementById( "timer" ).innerText = "focused"; 
    40 
    41  
    42 function checkQueue() { 
    43         currentRequest = createRequestObject(); 
    44         currentRequest.onreadystatechange = processQueue; 
    45         currentRequest.open( "GET", "/command/checkActivity" ); 
    46         currentRequest.send( null );     
    47 
    48  
    49 function panelForIdentifier( id ) { 
    50         for( var i = 0; i < panels.length; i++ ) 
    51                 if( panels[i].id == id ) 
    52                         return panels[i]; 
    53         return null; 
    54 
    55  
    56 function switchPanel( id ) { 
    57         for( var i = 0; i < panels.length; i++ ) { 
    58                 var panel = panels[i]; 
    59                 if( panel.id == id ) { 
     16 
     17var ChatController = { 
     18        panels: new Array() 
     19}; 
     20 
     21ChatController.createPanel = function( node ) { 
     22        var type = node.getAttribute( "class" ); 
     23        if( type == "JVDirectChatPanel" ) 
     24                return new DirectChatPanel( node ); 
     25        else if( type == "JVChatRoomPanel" ) 
     26                return new ChatRoomPanel( node ); 
     27        return undefined; 
     28}; 
     29 
     30ChatController.panel = function( id ) { 
     31        for( var i = 0, l = this.panels.length; i < l; ++i ) 
     32                if( this.panels[i].id == id ) return this.panels[i]; 
     33        return undefined; 
     34
     35 
     36ChatController.checkActivity = function() { 
     37        new Ajax.Request( "/command/checkActivity", { 
     38                method: "get", 
     39                onSuccess: function( transport ) { 
     40                        var updateIntervalDelta = 100; 
     41 
     42                        if( transport.responseText && transport.responseXML ) { 
     43                                var children = transport.responseXML.documentElement.childNodes; 
     44                                for( var i = 0; i < children.length; ++i ) { 
     45                                        switch( children[i].tagName ) { 
     46                                        case "open": 
     47                                                ChatController.createPanel( children[i] ); 
     48                                                break; 
     49                                        case "close": 
     50                                                var panel = ChatController.panel( children[i].getAttribute( "identifier" ) ); 
     51                                                panel.close(); 
     52                                                break; 
     53                                        case "message": 
     54                                                var message = children[i]; 
     55                                                if( message.firstChild ) { 
     56                                                        var panel = ChatController.panel( message.getAttribute( "panel" ) ); 
     57                                                        panel.appendMessage( message.firstChild.nodeValue ); 
     58                                                        if( ( ( ! foreground && panel.active ) || ! panel.active ) && ! panel.listItem.hasClassName( "newMessage" ) ) { 
     59                                                                panel.listItem.addClassName( "newMessage" ); 
     60                                                                panel.newMessage++; 
     61                                                                panel.listItem.title = panel.newMessage + " messages waiting"; 
     62                                                        } 
     63                                                } 
     64                                                break; 
     65                                        } 
     66                                } 
     67 
     68                                if( children.length >= 1 ) 
     69                                        updateIntervalDelta = ( -500 * children.length ) - 100; 
     70                        } 
     71 
     72                        var newActivityCheckSpeed = Math.max( Math.min( ( activityCheckSpeed + updateIntervalDelta ), 4000 ), 500 ); 
     73                        if( newActivityCheckSpeed != activityCheckSpeed ) { 
     74                                activityCheckSpeed = newActivityCheckSpeed; 
     75 
     76                                clearInterval( activityCheckInterval ); 
     77                                activityCheckInterval = setInterval( ChatController.checkActivity, activityCheckSpeed ); 
     78 
     79                                $("timer").innerText = activityCheckSpeed / 1000 + " secs"; 
     80                        } 
     81                }, 
     82                onFailure: function( transport ) { 
     83                        clearInterval( activityCheckInterval ); 
     84                        activityCheckInterval = setInterval( ChatController.checkActivity, 1000 ); 
     85                }, 
     86                onException: function( transport, exception ) { 
     87                        throw exception; 
     88                } 
     89        } ); 
     90}; 
     91 
     92function Panel( node ) { 
     93        var panel = this; 
     94 
     95        this.id = node.getAttribute( "identifier" ); 
     96        this.name = node.getAttribute( "name" ); 
     97        this.server = node.getAttribute( "server" ); 
     98        this.type = node.getAttribute( "class" ); 
     99        this.active = false; 
     100 
     101        this.listItem = $(document.createElement( "li" )); 
     102        this.listItem.className = "listItem"; 
     103        this.listItem.addEventListener( "click", function( event ) { panel.show(); }, false ); 
     104        this.listItem.appendChild( document.createTextNode( this.name ) ); 
     105 
     106        this.frame = $(document.createElement( "iframe" )); 
     107        this.frame.className = "panel"; 
     108 
     109        if( ChatController.panels.length ) 
     110                this.frame.style.setProperty( "visibility", "hidden", "" ); 
     111 
     112        ChatController.panels.push( this ); 
     113        $("panelList").appendChild( this.listItem ); 
     114        $("panels").appendChild( this.frame ); 
     115 
     116        if( ChatController.panels.length == 1 ) 
     117                this.show(); 
     118
     119 
     120Panel.prototype.toString = function() { 
     121        return this.name + " (" + this.type + ":" + this.id + ")"; 
     122
     123 
     124Panel.prototype.show = function() { 
     125        for( var i = 0, l = ChatController.panels.length; i < l; ++i ) { 
     126                var panel = ChatController.panels[i]; 
     127                if( panel.id == this.id ) { 
    60128                        if( ! panel.active ) { 
    61129                                panel.frame.style.setProperty( "visibility", "visible", "" ); 
    62                                 panel.listItem.className += " selected"
     130                                panel.listItem.addClassName( "selected" )
    63131                                panel.active = true; 
    64132                                panel.newMessage = 0; 
    65133                                panel.newHighlightMessage = 0; 
    66                                 panel.listItem.className = panel.listItem.className.replace( /\s*newMessage/g, "" ); 
    67                                 panel.listItem.className = panel.listItem.className.replace( /\s*newHighlight/g, "" ); 
     134                                panel.listItem.removeClassName( "newMessage" ); 
     135                                panel.listItem.removeClassName( "newHighlight" ); 
    68136                                panel.listItem.title = "No messages waiting"; 
    69137                                activePanel = panel; 
     
    71139                } else { 
    72140                        panel.frame.style.setProperty( "visibility", "hidden", "" ); 
    73                         panel.listItem.className = panel.listItem.className.replace( /\s*selected/g, "" ); 
     141                        panel.listItem.removeClassName( "selected" ); 
    74142                        panel.active = false; 
    75143                } 
     
    77145} 
    78146 
    79 function toggleMemberList( event, id ) { 
    80         var panel = panelForIdentifier( id ); 
    81         panel.memberListVisible = ! panel.memberListVisible; 
    82         if( panel.memberListVisible ) panel.memberList.style.setProperty( "display", "none", "" ); 
    83         else panel.memberList.style.setProperty( "display", "block", "" ); 
    84         event.preventDefault(); 
    85         event.stopPropagation(); 
    86 
    87  
    88 function createPanel( node ) { 
    89         if( panelForIdentifier( node.getAttribute( "identifier" ) ) ) return; 
    90  
    91         var panel = new Object(); 
    92         panel.id = node.getAttribute( "identifier" ); 
    93         panel.name = node.getAttribute( "name" ); 
    94         panel.server = node.getAttribute( "server" ); 
    95         panel.type = node.getAttribute( "class" ); 
    96         panel.newMessage = 0; 
    97         panel.newHighlightMessage = 0; 
    98         panel.active = false; 
    99         panel.memberListVisible = false; 
    100         panel.frame = document.createElement( "iframe" ); 
    101         panel.listItem = document.createElement( "li" ); 
    102         panels.push( panel ); 
    103  
    104         panel.frame.id = "panel" + panel.id; 
    105         panel.frame.className = "panel"; 
    106         panel.frame.src = "/command/panelContents?panel=" + panel.id; 
    107         if( panels.length > 1 ) panel.frame.style.setProperty( "visibility", "hidden", "" ); 
    108         document.getElementById( "panels" ).appendChild( panel.frame ); 
    109  
    110         panel.listItem.id = "listItem" + panel.id; 
    111         panel.listItem.className = "listItem"; 
    112  
    113         if( panel.type == "JVChatRoomPanel" ) { 
    114                 panel.listItem.className += " chatRoom"; 
    115                 panel.members = new Array(); 
    116                 panel.memberList = document.createElement( "ol" ); 
    117                 panel.memberList.className = "memberList"; 
    118                 panel.memberList.style.setProperty( "display", "none", "" ); 
    119  
    120                 var memberNode = null; 
    121                 var members = node.childNodes; 
    122                 for( var i = 0; i < members.length; i++ ) { 
    123                         memberNode = members[i]; 
    124  
    125                         var member = new Object(); 
    126                         member.name = memberNode.firstChild.nodeValue; 
    127                         member.nickname = memberNode.getAttribute( "nickname" ); 
    128                         member.hostmask = memberNode.getAttribute( "hostmask" ); 
    129                         member.identifier = memberNode.getAttribute( "identifier" ); 
    130                         member.buddy = memberNode.getAttribute( "buddy" ); 
    131                         member.type = memberNode.getAttribute( "class" ); 
    132                         member.self = ( memberNode.getAttribute( "self" ) == "yes" ); 
    133                         panel.members.push( member ); 
    134  
    135                         member.listItem = document.createElement( "li" ); 
    136                         member.listItem.title = member.hostmask; 
    137                         member.listItem.className = "listItem member" + ( member.type ? " " + member.type : "" ); 
    138                         member.listItem.appendChild( document.createTextNode( member.name ) ); 
    139                         panel.memberList.appendChild( member.listItem ); 
     147Panel.prototype.close = function() { 
     148        for( var i = 0, l = ChatController.panels.length; i < l; ++i ) 
     149                if( ChatController.panels[i].id == this.id ) break; 
     150 
     151        if( i < ChatController.panels.length ) 
     152                ChatController.panels.slice( i, 1 ); 
     153 
     154        this.frame.parentNode.removeChild( this.frame ); 
     155        this.listItem.parentNode.removeChild( this.listItem ); 
     156 
     157        ChatController.panels[0].show(); 
     158
     159 
     160function DirectChatPanel( node ) { 
     161        DirectChatPanel.baseConstructor.call( this, node ); 
     162 
     163        this.newMessage = 0; 
     164        this.newHighlightMessage = 0; 
     165 
     166        this.listItem.addClassName( "directChat" ); 
     167 
     168        var panel = this; 
     169        this.frame.onload = function() { 
     170                panel.contentFrame = $(panel.frame.document.getElementById( "content" )); 
     171                panel.contentFrame.onload = function() { panel.scrollToBottom() }; 
     172                panel.contentFrame.src = "/command/panelContents?panel=" + panel.id; 
     173        }; 
     174 
     175        this.frame.src = "/resources/base.html"; 
     176
     177 
     178extendClass( DirectChatPanel, Panel ); 
     179 
     180DirectChatPanel.prototype.sendMessage = function( html ) { 
     181        if( ! html.length ) return; 
     182 
     183        new Ajax.Request( "/command/send?panel=" + this.id, { 
     184                method: "post", 
     185                contentType: "text/html", 
     186                postBody: html, 
     187                onSuccess: function( transport ) { 
     188                        clearInterval( activityCheckInterval ); 
     189                        activityCheckInterval = setInterval( ChatController.checkActivity, 250 ); 
     190                }, 
     191                onException: function( transport, exception ) { 
     192                        throw exception; 
    140193                } 
    141         } else if( panel.type == "JVDirectChatPanel" ) panel.listItem.className += " directChat"; 
    142  
    143         panel.listItem.setAttribute( "onclick", "switchPanel(" + panel.id + ")" ); 
    144         panel.listItem.setAttribute( "ondblclick", "toggleMemberList(event," + panel.id + ")" ); 
    145         panel.listItem.appendChild( document.createTextNode( panel.name ) ); 
    146         document.getElementById( "panelList" ).appendChild( panel.listItem ); 
    147         if( panel.memberList ) document.getElementById( "panelList" ).appendChild( panel.memberList ); 
    148  
    149         setTimeout( scrollToBottom, 50, panel.frame ); 
    150  
    151         if( panels.length == 1 ) switchPanel( panel.id ); 
    152 
    153  
    154 function closePanel( id ) { 
    155         for( var i = 0; i < panels.length; i++ ) 
    156                 if( panels[i].id == id ) break; 
    157  
    158         if( i >= panels.length ) return; 
    159  
    160         var panel = panels[i]; 
    161         panels.slice( i, 1 ); 
    162  
    163         panel.frame.parentNode.removeChild( panel.frame ); 
    164         panel.listItem.parentNode.removeChild( panel.listItem ); 
    165  
    166         switchPanel( panels[0].id ); 
    167 
    168  
    169 function processSetup() { 
    170         if( currentRequest.readyState == 4 && currentRequest.status == 200 ) { 
    171                 var xml = currentRequest.responseXML; 
    172                 var children = xml.documentElement.getElementsByTagName( "panels" ).item( 0 ).childNodes; 
    173  
    174                 for( var i = 0; i < children.length; i++ ) 
    175                         createPanel( children[i] ); 
    176  
    177                 checkQueue(); 
    178                 queueCheckInterval = setInterval( checkQueue, queueCheckSpeed ); 
    179         } 
    180 
    181  
    182 function processQueue() { 
    183         if( currentRequest.readyState == 4 && currentRequest.status == 200 && currentRequest.responseText.length ) { 
    184                 var xml = currentRequest.responseXML; 
    185                 var children = xml.documentElement.childNodes; 
    186  
    187                 var messages = 0; 
    188                 for( var i = 0; i < children.length; i++ ) { 
    189                         switch( children[i].tagName ) { 
    190                         case "open": 
    191                                 createPanel( children[i] ); 
    192                                 break; 
    193                         case "close": 
    194                                 closePanel( children[i].getAttribute( "identifier" ) ); 
    195                                 break; 
    196                         case "message": 
    197                                 messages++; 
    198                                 var message = children[i]; 
    199                                 var id = message.getAttribute( "panel" ); 
    200                                 if( message.firstChild ) { 
    201                                         appendMessage( id, message.firstChild.nodeValue ); 
    202                                         var panel = panelForIdentifier( id ); 
    203                                         if( ( ( ! foreground && panel.active ) || ! panel.active ) && panel.listItem.className.indexOf( "newMessage" ) == -1 ) { 
    204                                                 panel.listItem.className += " newMessage"; 
    205                                                 panel.newMessage++; 
    206                                                 panel.listItem.title = panel.newMessage + " messages waiting"; 
    207                                         } 
    208                                 } 
    209                                 break; 
    210                         } 
    211                 } 
    212  
    213                 if( messages >= 1 ) { 
    214                         queueCheckSpeed -= ( 500 * messages ); 
    215                         if( queueCheckSpeed < 500 ) queueCheckSpeed = 500; 
    216                         clearInterval( queueCheckInterval ); 
    217                         queueCheckInterval = setInterval( checkQueue, queueCheckSpeed ); 
    218                         document.getElementById( "timer" ).innerText = queueCheckSpeed / 1000 + " secs"; 
    219                 } 
    220         } else if( currentRequest.readyState == 4 ) { 
    221                 if( queueCheckSpeed < 4000 ) { 
    222                         queueCheckSpeed += 100; 
    223                         if( queueCheckSpeed > 4000 ) queueCheckSpeed = 4000; 
    224                         clearInterval( queueCheckInterval ); 
    225                         queueCheckInterval = setInterval( checkQueue, queueCheckSpeed ); 
    226                         document.getElementById( "timer" ).innerText = queueCheckSpeed / 1000 + " secs"; 
    227                 } 
    228         } 
    229 
    230  
    231 function documentKeyInput( event ) { 
    232         if( event.target.id == "input" || event.target.parentNode.id == "input" ) return; 
    233         if( event.keyCode == 13 && ! event.altKey ) inputKeyPressed( event ); 
    234         else if( event.keyCode == 32 ) input.innerHTML += "&nbsp;"; 
    235         else input.innerHTML += String.fromCharCode( event.keyCode ); 
    236 
    237  
    238 function inputKeyPressed( event ) { 
    239         if( event.keyCode == 13 && ! event.altKey ) { 
    240                 var input = document.getElementById( "input" ); 
    241                 sendMessage( activePanel.id, input.innerText ); 
    242                 input.innerHTML = ""; 
    243         } 
    244 
    245  
    246 function sendMessage( panel, html ) { 
    247         if( ! html.length ) return; 
    248         currentRequest = createRequestObject(); 
    249         currentRequest.onreadystatechange = processQueue; 
    250         currentRequest.open( "POST", "/command/send?panel=" + panel ); 
    251         currentRequest.send( html ); 
    252         setTimeout( checkQueue, 250 ); 
    253 
    254  
    255 function appendMessage( panel, html ) { 
    256         var frame = document.getElementById( "panel" + panel ); 
    257         if( html.indexOf( "<?message type=\"subsequent\"?>" ) != -1 && frame.document.getElementById( "consecutiveInsert" ) ) { 
    258                 appendConsecutiveMessage( panel, html ); 
     194        } ); 
     195
     196 
     197DirectChatPanel.prototype.appendMessage = function( html ) { 
     198        var frame = this.contentFrame; 
     199 
     200        var consecutive = ( html.indexOf( "<?message type=\"consecutive\"?>" ) != -1 ); 
     201        if( ! consecutive ) consecutive = ( html.indexOf( "<?message type=\"subsequent\"?>" ) != -1 ); 
     202        if( consecutive && frame.document.getElementById( "consecutiveInsert" ) ) { 
     203                this.appendConsecutiveMessage( html ); 
    259204                return; 
    260205        } 
    261206 
    262         var needed = checkIfScrollToBottomIsNeeded( frame ); 
     207        var needed = this.checkIfScrollToBottomIsNeeded(); 
    263208 
    264209        var bodyNode = frame.document.getElementById( "contents" ); 
     
    273218        bodyNode.appendChild( documentFragment ); 
    274219 
    275         enforceScrollBackLimit( frame ); 
    276         if( needed ) scrollToBottom( frame ); 
    277 } 
    278  
    279 function appendConsecutiveMessage( panel, html ) { 
    280         var needed = checkIfScrollToBottomIsNeeded( frame )
    281  
    282         var frame = document.getElementById( "panel" + panel ); 
     220        this.enforceScrollBackLimit(); 
     221        if( needed ) this.scrollToBottom(); 
     222} 
     223 
     224DirectChatPanel.prototype.appendConsecutiveMessage = function( html ) { 
     225        var frame = this.contentFrame
     226        var needed = this.checkIfScrollToBottomIsNeeded(); 
     227 
    283228        var insert = frame.document.getElementById( "consecutiveInsert" ); 
    284229        if( ! insert ) { 
    285                 appendMessage( panel, html ); 
     230                this.appendMessage( html ); 
    286231                return; 
    287232        } 
     
    292237        insert.parentNode.replaceChild( documentFragment, insert ); 
    293238 
    294         enforceScrollBackLimit( frame ); 
    295         if( needed ) scrollToBottom( frame ); 
    296 
    297  
    298 function enforceScrollBackLimit( frame ) { 
     239        this.enforceScrollBackLimit(); 
     240        if( needed ) this.scrollToBottom(); 
     241
     242 
     243DirectChatPanel.prototype.enforceScrollBackLimit = function() { 
     244        var frame = this.contentFrame; 
    299245        var bodyNode = frame.document.getElementById( "contents" ); 
    300246        if( ! bodyNode ) bodyNode = frame.document.body; 
    301247        if( scrollBackLimit > 0 && bodyNode.childNodes.length > scrollBackLimit ) 
    302                 for( var i = 0; bodyNode.childNodes.length > scrollBackLimit && i < ( bodyNode.childNodes.length - scrollBackLimit ); i++
     248                for( var i = 0; bodyNode.childNodes.length > scrollBackLimit && i < ( bodyNode.childNodes.length - scrollBackLimit ); ++i
    303249                        bodyNode.removeChild( bodyNode.childNodes[0] ); 
    304250} 
    305251 
    306 function scrollToBottom( frame ) { 
     252DirectChatPanel.prototype.scrollToBottom = function() { 
     253        var frame = this.contentFrame; 
    307254        var bodyNode = frame.document.getElementById( "contents" ); 
    308255        if( ! bodyNode ) bodyNode = frame.document.body; 
     
    310257} 
    311258 
    312 function checkIfScrollToBottomIsNeeded( frame ) { 
     259DirectChatPanel.prototype.checkIfScrollToBottomIsNeeded = function() { 
     260//      var frame = this.contentFrame; 
    313261        return true; 
    314262/*      var bodyNode = frame.document.getElementById( "contents" ); 
     
    316264        scrollToBottomIsNeeded = ( bodyNode.scrollTop >= ( bodyNode.offsetHeight - ( window.innerHeight * 1.1 ) ) ); */ 
    317265} 
     266 
     267function ChatRoomPanel( node ) { 
     268        ChatRoomPanel.baseConstructor.call( this, node ); 
     269 
     270        this.memberListVisible = false; 
     271 
     272        this.listItem.removeClassName( "directChat" ); 
     273        this.listItem.addClassName( "chatRoom" ); 
     274 
     275        this.members = new Array(); 
     276 
     277        this.memberList = $(document.createElement( "ol" )); 
     278        this.memberList.className = "memberList"; 
     279        this.memberList.style.setProperty( "display", "none", "" ); 
     280        $("panelList").appendChild( this.memberList ); 
     281 
     282        var memberNodes = node.childNodes; 
     283        for( var i = 0; i < memberNodes.length; ++i ) { 
     284                var memberNode = memberNodes[i]; 
     285 
     286                var member = new Object(); 
     287                member.name = memberNode.firstChild.nodeValue; 
     288                member.nickname = memberNode.getAttribute( "nickname" ); 
     289                member.hostmask = memberNode.getAttribute( "hostmask" ); 
     290                member.identifier = memberNode.getAttribute( "identifier" ); 
     291                member.buddy = memberNode.getAttribute( "buddy" ); 
     292                member.type = memberNode.getAttribute( "class" ); 
     293                member.self = ( memberNode.getAttribute( "self" ) == "yes" ); 
     294 
     295                this.members.push( member ); 
     296 
     297                member.listItem = $(document.createElement( "li" )); 
     298                member.listItem.title = member.hostmask; 
     299                member.listItem.className = "listItem member" + ( member.type ? " " + member.type : "" ); 
     300                member.listItem.appendChild( document.createTextNode( member.name ) ); 
     301 
     302                this.memberList.appendChild( member.listItem ); 
     303        } 
     304 
     305        var panel = this; 
     306        this.listItem.addEventListener( "dblclick", function( event ) { panel.toggleMemberList(); event.preventDefault(); event.stopPropagation(); }, false ); 
     307} 
     308 
     309extendClass( ChatRoomPanel, DirectChatPanel ); 
     310 
     311ChatRoomPanel.prototype.toggleMemberList = function() { 
     312        this.memberListVisible = ! this.memberListVisible; 
     313        if( this.memberListVisible ) this.memberList.style.setProperty( "display", "none", "" ); 
     314        else this.memberList.style.setProperty( "display", "block", "" ); 
     315} 
     316 
     317ChatRoomPanel.prototype.close = function() { 
     318        ChatRoomPanel.superClass.close.call(this); 
     319        this.memberList.parentNode.removeChild( this.memberList ); 
     320} 
     321 
     322window.addEventListener( "load", setup, false ); 
     323 
     324function setup() { 
     325        $("input").addEventListener( "keydown", inputKeyDown, false ); 
     326        window.addEventListener( "blur", windowBlured, false ); 
     327        window.addEventListener( "focus", windowFocused, false ); 
     328 
     329        new Ajax.Request( "/command/setup", { 
     330                method: "get", 
     331                onSuccess: function( transport ) { 
     332                        var xml = transport.responseXML; 
     333                        var children = xml.documentElement.getElementsByTagName( "panels" ).item( 0 ).childNodes; 
     334 
     335                        for( var i = 0; i < children.length; ++i ) 
     336                                ChatController.createPanel( children[i] ); 
     337 
     338                        ChatController.checkActivity(); 
     339                        activityCheckInterval = setInterval( ChatController.checkActivity, activityCheckSpeed ); 
     340                }, 
     341                onException: function( transport, exception ) { 
     342                        throw exception; 
     343                } 
     344        } ); 
     345} 
     346 
     347function windowBlured() { 
     348        foreground = false; 
     349} 
     350 
     351function windowFocused() { 
     352        foreground = true; 
     353        if( ! activePanel ) return; 
     354 
     355        activePanel.newMessage = 0; 
     356        activePanel.newHighlightMessage = 0; 
     357        activePanel.listItem.removeClassName( "newMessage" ); 
     358        activePanel.listItem.removeClassName( "newHighlight" ); 
     359        activePanel.listItem.title = "No messages waiting"; 
     360} 
     361 
     362function inputKeyDown( event ) { 
     363        if( event.keyCode == 13 && ! event.altKey ) { 
     364                var input = $("input"); 
     365                activePanel.sendMessage( input.innerText ); 
     366                input.innerHTML = ""; 
     367                event.preventDefault(); 
     368        } 
     369} 
  • trunk/Plug-Ins/Web Interface/Resources/index.html

    r3552 r3560  
    99        <link rel="icon" href="smallIcon.png" type="image/png" /> 
    1010        <link rel="stylesheet" type="text/css" href="base.css" encoding="utf-8" /> 
    11         <script type="text/ecmascript" defer="defer" src="common.js" encoding="utf-8"></script> 
     11        <script type="text/ecmascript" src="prototype.js" encoding="utf-8"></script> 
     12        <script type="text/ecmascript" src="utilities.js" encoding="utf-8"></script> 
     13        <script type="text/ecmascript" src="common.js" encoding="utf-8"></script> 
    1214</head> 
    13 <body onload="setup()" oncontextmenu="return false"
     15<body
    1416<div id="main"> 
    1517<div id="panels"></div> 
     
    1719<div id="drawer" onselectstart="return false"><ul id="panelList"></ul></div> 
    1820</div> 
    19 <div id="timer">4.0 secs</div> 
     21<div id="timer">4 secs</div> 
    2022</body> 
    2123</html> 
  • trunk/Plug-Ins/Web Interface/Web Interface.xcodeproj/project.pbxproj

    r3556 r3560  
    2121                1C3699C608FF768900F34892 /* url_map.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C3699BA08FF768900F34892 /* url_map.c */; }; 
    2222                1C3699C708FF768900F34892 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C3699BB08FF768900F34892 /* utils.c */; }; 
     23                1C7F7CC90B5FF71700D8676C /* utilities.js in Resources */ = {isa = PBXBuildFile; fileRef = 1C7F7CC70B5FF71000D8676C /* utilities.js */; }; 
     24                1CAB90660B606FA90051E0E7 /* prototype.js in Resources */ = {isa = PBXBuildFile; fileRef = 1CAB90650B606FA10051E0E7 /* prototype.js */; }; 
    2325                1CC7250C0901A775004651F8 /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = 1CC7250B0901A775004651F8 /* index.html */; }; 
    2426                1CC726710901BBD2004651F8 /* common.js in Resources */ = {isa = PBXBuildFile; fileRef = 1CC7265F0901BAAE004651F8 /* common.js */; }; 
     
    4648                1C3699BA08FF768900F34892 /* url_map.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = url_map.c; path = nanohttpd/url_map.c; sourceTree = "<group>"; }; 
    4749                1C3699BB08FF768900F34892 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utils.c; path = nanohttpd/utils.c; sourceTree = "<group>"; }; 
     50                1C7F7CC70B5FF71000D8676C /* utilities.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = utilities.js; sourceTree = "<group>"; }; 
    4851                1C9AE8FB086A552A008ED7AD /* Common Settings.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "Common Settings.xcconfig"; path = "../../Settings/Common Settings.xcconfig"; sourceTree = "<group>"; }; 
     52                1CAB90650B606FA10051E0E7 /* prototype.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = prototype.js; sourceTree = "<group>"; }; 
    4953                1CC7250B0901A775004651F8 /* index.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = index.html; sourceTree = "<group>"; }; 
    5054                1CC7265F0901BAAE004651F8 /* common.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = common.js; sourceTree = "<group>"; }; 
     
    9397                                8D5B49B7048680CD000E48DA /* Info.plist */, 
    9498                                1CC7250B0901A775004651F8 /* index.html */, 
     99                                1C3458F10905FC4800AC2C16 /* base.css */, 
    95100                                1CC7265F0901BAAE004651F8 /* common.js */, 
    96                                 1C3458F10905FC4800AC2C16 /* base.css */, 
     101                                1CAB90650B606FA10051E0E7 /* prototype.js */, 
     102                                1C7F7CC70B5FF71000D8676C /* utilities.js */, 
    97103                                1CF3AE6F0B5B05B100183925 /* smallIcon.png */, 
    98104                        ); 
     
    196202                        isa = PBXProject; 
    197203                        buildConfigurationList = 1C7F30420855482D00D41FB0 /* Build configuration list for PBXProject "Web Interface" */; 
    198                         compatibilityVersion = "Xcode 2.4"; 
    199204                        hasScannedForEncodings = 1; 
    200205<