Commits

Tomas Brabenec committed e261899

init

  • Participants

Comments (0)

Files changed (14)

+content sites jar:sites.jar!/content/ xpcnativewrappers=yes
+skin sites classic/1.0 jar:sites.jar!/skin/
+overlay chrome://komodo/content/komodo.xul chrome://sites/content/overlay.xul
+<?xml version="1.0"?>
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+    <Description about="urn:mozilla:install-manifest">
+        <em:id>{e98dde1f-b8ab-49cc-a634-00d32adc7cc3}</em:id>
+        <em:name>Sites</em:name>
+        <em:version>0.1</em:version>
+        <em:description>Remote and local file browser</em:description>
+        <em:creator>Tomas Brabenec</em:creator>
+        <em:creator>Joker</em:creator>
+        <em:homepageURL>http://community.activestate.com/xpi/sites</em:homepageURL>
+        <em:type>2</em:type> <!-- type=extension -->
+
+        <em:targetApplication>
+            <Description>
+                <!-- Komodo IDE's uuid -->
+                <em:id>{36E66FA0-F259-11D9-850E-000D935D3368}</em:id>
+                <em:minVersion>4.1</em:minVersion>
+                <em:maxVersion>7.*</em:maxVersion>
+            </Description>
+        </em:targetApplication>
+        <em:targetApplication>
+            <Description>
+                <!-- Komodo Edit's uuid -->
+                <em:id>{b1042fb5-9e9c-11db-b107-000d935d3368}</em:id>
+                <em:minVersion>4.1</em:minVersion>
+                <em:maxVersion>7.*</em:maxVersion>
+            </Description>
+        </em:targetApplication>
+    </Description>
+</RDF>

sites.jar/content/dinamicTree.js

+/* ***** BEGIN LICENSE BLOCK *****
+   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   *
+   * The contents of this file are subject to the Mozilla Public License Version
+   * 1.1 (the "License"); you may not use this file except in compliance with
+   * the License. You may obtain a copy of the License at
+   * http://www.mozilla.org/MPL/
+   *
+   * Software distributed under the License is distributed on an "AS IS" basis,
+   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   * for the specific language governing rights and limitations under the
+   * License.
+   *
+   * The Initial Developer of the Original Code
+   * Portions created by the Initial Developer are Copyright (C) 2008
+   * the Initial Developer. All Rights Reserved.
+   *
+   * Tomas Brabenec - http://brabenec.net
+   * Based on code JSTreeDrive originally developed by Joker <deck@joker.exnet.su>
+   *
+   * Alternatively, the contents of this file may be used under the terms of
+   * either the GNU General Public License Version 2 or later (the "GPL"), or
+   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   * in which case the provisions of the GPL or the LGPL are applicable instead
+   * of those above. If you wish to allow use of your version of this file only
+   * under the terms of either the GPL or the LGPL, and not to allow others to
+   * use your version of this file under the terms of the MPL, indicate your
+   * decision by deleting the provisions above and replace them with the notice
+   * and other provisions required by the LGPL or the GPL. If you do not delete
+   * the provisions above, a recipient may use your version of this file under
+   * the terms of any one of the MPL, the GPL or the LGPL.
+   *
+   * ***** END LICENSE BLOCK ***** */
+
+function $(el) { return document.getElementById(el); }
+
+
+if(typeof(ko) == "undefined") { var ko = {}; }
+if(typeof(ko.extensions) == "undefined") { ko.extensions = {}; }
+
+
+ko.extensions.Sites = {
+    osSvc        : Components.classes["@activestate.com/koOs;1"].getService(),
+    prefsSvc     : Components.classes["@activestate.com/koPrefService;1"].
+                         getService(Components.interfaces.koIPrefService),
+    rConnectSvc  : Components.classes["@activestate.com/koRemoteConnectionService;1"].
+                         getService(Components.interfaces.koIRemoteConnectionService),
+    docSvc       : Components.classes["@activestate.com/koDocumentService;1"].
+                         getService(Components.interfaces.koIDocumentService),
+
+    servers_list : null,
+    links        : [],
+
+    prefs_deleteIt : function(num) {
+        var prefs = this.prefsSvc.prefs;
+        this.links.splice(num,1)
+
+        if(this.links.length == 0)
+            prefs.deletePref("ko.extensions.Sites.links");
+        else
+            prefs.setStringPref("ko.extensions.Sites.links", this.links.join(';'));
+        // ko.extensions.Sites.prefsSvc.prefs.deletePref('ko.extensions.Sites.links')
+    },
+    prefs_loadFrom : function() {
+        var prefs = this.prefsSvc.prefs;
+
+        if (prefs.hasStringPref("ko.extensions.Sites.links")) {
+            var str = prefs.getStringPref("ko.extensions.Sites.links")
+            if(str.length > 5)
+                return str;
+            else
+                return false;
+        }else{
+            return false;
+        }
+    },
+    prefs_saveTo : function(lk) {
+        var prefs = this.prefsSvc.prefs;
+        this.links.splice(0,0,lk)
+
+        prefs.setStringPref("ko.extensions.Sites.links", this.links.join(';'));
+    }
+}
+
+
+ko.extensions.Sites.S_nsITreeView = function (){
+    var atomService          = Components.classes["@mozilla.org/atom-service;1"].
+                                getService(Components.interfaces.nsIAtomService);
+
+    this.mServerAtom         = atomService.getAtom("server");
+    this.mComputerAtom       = atomService.getAtom("computer");
+    this.mLinkAtom           = atomService.getAtom("link");
+    this.mDirectoryOpen      = atomService.getAtom("directory-open");
+    this.mDirectoryClose     = atomService.getAtom("directory-close");
+    this.mFilenameColumnAtom = atomService.getAtom("FilenameColumn");
+
+    this.tree_rows    = [];
+}
+ko.extensions.Sites.S_nsITreeView.prototype = {
+// nsITreeView
+    set rowCount(c) { throw "readonly property"; },
+    get rowCount()  { return this.tree_rows.length;  },
+    /* attribute nsITreeSelection selection; */
+    set selection(s) { this.mSelection = s   ; },
+    get selection()  { return this.mSelection; },
+    tree                : null,
+    performAction       : function(action) {},
+    cycleCell           : function(num, colId) {},
+    cycleHeader         : function() {},
+    selectionChanged    : function() {},
+    isSorted            : function()    { return false; },
+    isSeparator         : function(num) { return false; },
+    isContainer         : function(num) { return true ; },
+    isContainerEmpty    : function(num) { return false; },
+    isContainerOpen     : function(num)         { return this.tree_rows[num].open; },
+    getLevel            : function(num)         { return this.tree_rows[num].depth; },
+    getParentIndex      : function(num)         { return this.tree_rows[num].parent_idx; },
+    getCellText         : function(num, column) { return this.tree_rows[num].name; },
+    getImageSrc         : function(){return null;},
+    getRowProperties    : function(num,    prop){},
+    getColumnProperties : function(column, prop){},
+    setTree             : function(out) { this.tree = out; },
+
+    hasNextSibling      : function(num, after) {
+        var level = this.getLevel(num);
+        // March on!
+        var l;
+        while (++num < this.tree_rows.length) {
+            l = this.getLevel(num);
+            if (l < level)
+                return false;
+            else if (l == level && num > after)
+                return true;
+        }
+        return false;
+    },
+
+    getCellProperties   : function(num, column, properties) {
+        if (this.tree_rows[num].depth == 0) {                   // Depth is 0, it's a server
+            if(this.tree_rows[num].link)
+                properties.AppendElement(this.mLinkAtom);
+            else if(this.tree_rows[num].path)
+                properties.AppendElement(this.mComputerAtom);
+            else
+                properties.AppendElement(this.mServerAtom);
+        } else {
+            if(this.tree_rows[num].open)
+                properties.AppendElement(this.mDirectoryOpen);
+            else
+                properties.AppendElement(this.mDirectoryClose);
+        }
+        properties.AppendElement(this.mFilenameColumnAtom);
+    },
+
+    toggleOpenState     : function(num) {
+        window.setCursor("wait");
+        try {
+            var aRow = this.tree_rows[num];
+
+            if (aRow.open) {  // It's open
+                this.clear_subRows(num);
+            } else {
+                this.tree.rowCountChanged(num + 1, aRow.setDirList(num, this.tree_rows)); // dircount -> aRow.setDirList(num, this.tree_rows)
+            }
+
+            aRow.open = !aRow.open
+            this.tree.invalidateRow(num); // �������������� ������ ����������  (expand/collapse)
+        }catch(e){
+            alert( 'toggleOpenState - ' + e);
+        }
+        window.setCursor("auto");
+    },
+// nsITreeView
+
+    init_List_forView : function(list){
+        this.selection.clearSelection();
+
+        this.tree.rowCountChanged(0, -this.tree_rows.length);  // Using rowCountChanged to notify rows were removed
+        this.tree_rows = ko.extensions.Sites.init_rowsList();
+        this.tree.rowCountChanged(0,  this.tree_rows.length);  // Using rowCountChanged to notify rows were added
+    },
+
+    update_fileTree_fromDirRow : function(num) {
+        window.setCursor("wait");
+        if (num >= 0 && num < this.tree_rows.length){
+            ko.extensions.Sites.F.set_filesList(this.tree_rows[num].getFileList());
+        }
+        window.setCursor("auto");
+    },
+    clear_subRows   : function(num) {
+        var deletecount = 0;
+        for (var t = num + 1; t < this.tree_rows.length; t++) {
+            if (this.getLevel(t) > this.tree_rows[num].depth) deletecount++;
+            else break;
+        }
+        if (deletecount) {
+                this.tree_rows.splice(num + 1,  deletecount);
+            this.tree.rowCountChanged(num + 1, -deletecount);
+        }
+    },
+
+
+    edit_rowItems   : function(action, start_num, data) {
+        this.selection.clearSelection();
+
+        this.tree.rowCountChanged(0, -this.tree_rows.length);
+            switch(action)
+            {
+                case 'add':
+                    this.tree_rows.splice(start_num, 0, data);
+                break;
+                case 'del':
+                    this.tree_rows.splice(start_num, 1);
+                break;
+                case 'link':
+                    this.tree_rows.splice(start_num, 0, this.tree_rows[data].mkLink());
+                break;
+            }
+        this.tree.rowCountChanged(0,  this.tree_rows.length);
+    }
+};
+
+
+ko.extensions.Sites.F_nsITreeView = function () {
+    // Date service, used to turn timestamp into pretty date string
+    this._dateSvc   = Components.classes["@mozilla.org/intl/scriptabledateformat;1"].
+                           getService(Components.interfaces.nsIScriptableDateFormat);
+    // Remote Connection service
+    this.rfService  = Components.classes["@activestate.com/koRemoteConnectionService;1"]
+                          .getService(Components.interfaces.koIRemoteConnectionService);
+
+    var atomService = Components.classes["@mozilla.org/atom-service;1"]
+                     .getService(Components.interfaces.nsIAtomService);
+    this.mFileAtom              = atomService.getAtom("file-icon");
+    this.mFilenameColumnAtom    = atomService.getAtom("FilenameColumn");
+
+    this.mFileXml               = atomService.getAtom("xml-icon");
+    this.mFileXul               = atomService.getAtom("xul-icon");
+    this.mFileHtml              = atomService.getAtom("html-icon");
+    this.mFileHtm               = atomService.getAtom("htm-icon");
+    this.mFileTpl               = atomService.getAtom("tpl-icon");
+    this.mFileCss               = atomService.getAtom("css-icon");
+    this.mFileJs                = atomService.getAtom("js-icon");
+    this.mFileRb                = atomService.getAtom("rb-icon");
+    this.mFilePhp               = atomService.getAtom("php-icon");
+    this.mFilePy                = atomService.getAtom("py-icon");
+    this.mFileC                 = atomService.getAtom("c-icon");
+    this.mFileImage             = atomService.getAtom("image-icon");
+    this.mFilePng               = atomService.getAtom("png-icon");
+    this.mFileGif               = atomService.getAtom("gif-icon");
+    this.mFileJpg               = atomService.getAtom("jpg-icon");
+    this.mFileArh               = atomService.getAtom("arh-icon");
+    this.mFileCmd               = atomService.getAtom("cmd-icon");
+    this.mFileXpi               = atomService.getAtom("xpi-icon");
+    this.mFileKpf               = atomService.getAtom("kpf-icon");
+
+    this.file_rows = [];
+}
+ko.extensions.Sites.F_nsITreeView.prototype = {
+    // nsITreeView
+    get rowCount() { return this.file_rows.length; },
+
+    tree                : null,
+    cycleCell           : function(row, colId) {},
+    cycleHeader         : function() {},
+    selectionChanged    : function() {},
+    toggleOpenState     : function(row)   {},
+    performAction       : function(action){},
+    isSorted            : function()    { return false; },
+    isSeparator         : function(row) { return false; },
+    isContainer         : function(row) { return false; },
+    isContainerOpen     : function(row) { return false; },
+    isContainerEmpty    : function(row) { return false; },
+    hasNextSibling      : function(row, after) { return false; },
+    setTree             : function(out) { this.tree = out; },
+    getLevel            : function(row) { return  0; },
+    getParentIndex      : function(row) { return -1; },
+    getImageSrc         : function()    { return null; },
+    getRowProperties    : function(row,prop)   {},
+    getColumnProperties : function(column,prop){},
+    getCellProperties   : function(row, column, properties) {
+        if (column.id == "file_tree_col_name") {
+            if(this.file_rows[row].ext){
+                switch(this.file_rows[row].ext)
+                {
+                    case 'xml':
+                    properties.AppendElement(this.mFileXml);
+                    break;
+                    case 'xul':
+                    properties.AppendElement(this.mFileXul);
+                    break;
+                    case 'html':
+                    properties.AppendElement(this.mFileHtml);
+                    break;
+                    case 'htm':
+                    properties.AppendElement(this.mFileHtm);
+                    break;
+                    case 'tpl':
+                    properties.AppendElement(this.mFileTpl);
+                    break;
+                    case 'css':
+                    properties.AppendElement(this.mFileCss);
+                    break;
+                    case 'js':
+                    properties.AppendElement(this.mFileJs);
+                    break;
+                    case 'rb':
+                    properties.AppendElement(this.mFileRb);
+                    break;
+                    case 'php':
+                    properties.AppendElement(this.mFilePhp);
+                    break;
+                    case 'py':
+                    properties.AppendElement(this.mFilePy);
+                    break;
+                    case 'c':
+                    properties.AppendElement(this.mFileC);
+                    break;
+                    case 'jpg':
+                    case 'jpeg':
+                    properties.AppendElement(this.mFileJpg);
+                    break;
+                    case 'png':
+                    properties.AppendElement(this.mFilePng);
+                    break;
+                    case 'gif':
+                    properties.AppendElement(this.mFileGif);
+                    break;
+                    case 'ico':
+                    case 'bmp':
+                    properties.AppendElement(this.mFileImage);
+                    break;
+                    case 'zip':
+                    case 'rar':
+                    case 'tar':
+                    case 'jar':
+                    case 'bz2':
+                    case 'kpz':
+                    case 'gz':
+                    case '7z':
+                    properties.AppendElement(this.mFileArh);
+                    break;
+                    case 'cmd':
+                    case 'bat':
+                    case 'csh':
+                    case 'sh':
+                    properties.AppendElement(this.mFileCmd);
+                    break;
+                    case 'xpi':
+                    properties.AppendElement(this.mFileXpi);
+                    break;
+                    case 'kpf':
+                    properties.AppendElement(this.mFileKpf);
+                    break;
+                    default:
+                    properties.AppendElement(this.mFileAtom);
+                }
+            }else{
+                properties.AppendElement(this.mFileAtom);
+            }
+            properties.AppendElement(this.mFilenameColumnAtom);
+        }
+    },
+    getCellText         : function(row, column) {
+        var rfInfo = this.file_rows[row];
+        switch (column.id) {
+            case 'file_tree_col_name':
+                return rfInfo.name;
+            case 'file_tree_col_size':
+                return rfInfo.size;
+            case 'file_tree_col_date':
+                // pretty date string
+                var modDate = new Date(rfInfo.time * 1000);
+                return this._dateSvc.FormatDateTime("", this._dateSvc.dateFormatShort,
+                                                        this._dateSvc.timeFormatNoSecondsForce24Hour,
+                                                        modDate.getFullYear(),
+                                                        modDate.getMonth()+1,
+                                                        modDate.getDate(),
+                                                        modDate.getHours(),
+                                                        modDate.getMinutes(),
+                                                        modDate.getSeconds() );
+        }
+        return "(Unknown column)";
+    },
+
+
+    set_filesList : function(files) {
+        this.selection.clearSelection();
+
+        this.tree.rowCountChanged(0, -this.file_rows.length);
+        this.file_rows = files;
+        this.tree.rowCountChanged(0,  this.file_rows.length);
+    }
+};
+
+ko.extensions.Sites.S = new ko.extensions.Sites.S_nsITreeView();
+ko.extensions.Sites.F = new ko.extensions.Sites.F_nsITreeView();

sites.jar/content/imageView.js

+/* ***** BEGIN LICENSE BLOCK *****
+   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   *
+   * The contents of this file are subject to the Mozilla Public License Version
+   * 1.1 (the "License"); you may not use this file except in compliance with
+   * the License. You may obtain a copy of the License at
+   * http://www.mozilla.org/MPL/
+   *
+   * Software distributed under the License is distributed on an "AS IS" basis,
+   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   * for the specific language governing rights and limitations under the
+   * License.
+   *
+   * The Initial Developer of the Original Code
+   * Portions created by the Initial Developer are Copyright (C) 2008
+   * the Initial Developer. All Rights Reserved.
+   *
+   * Tomas Brabenec - http://brabenec.net
+   * Based on code JSTreeDrive originally developed by Joker <deck@joker.exnet.su>
+   *
+   * Alternatively, the contents of this file may be used under the terms of
+   * either the GNU General Public License Version 2 or later (the "GPL"), or
+   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   * in which case the provisions of the GPL or the LGPL are applicable instead
+   * of those above. If you wish to allow use of your version of this file only
+   * under the terms of either the GPL or the LGPL, and not to allow others to
+   * use your version of this file under the terms of the MPL, indicate your
+   * decision by deleting the provisions above and replace them with the notice
+   * and other provisions required by the LGPL or the GPL. If you do not delete
+   * the provisions above, a recipient may use your version of this file under
+   * the terms of any one of the MPL, the GPL or the LGPL.
+   *
+   * ***** END LICENSE BLOCK ***** */
+
+
+ko.extensions.Sites.imageView = function (Img, tab_name, type) {
+
+    function encode64(input) {
+        var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+        var output = "";
+        var chr1, chr2, chr3;
+        var enc1, enc2, enc3, enc4;
+        var i = 0;
+        do {
+            chr1 = input.charCodeAt(i++);
+            chr2 = input.charCodeAt(i++);
+            chr3 = input.charCodeAt(i++);
+            enc1 = chr1 >> 2;
+            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+            enc4 = chr3 & 63;
+            if (isNaN(chr2)) {
+                enc3 = enc4 = 64;
+            } else {
+                if (isNaN(chr3)) {
+                    enc4 = 64;
+                }
+            }
+            output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
+        } while (i < input.length);
+        return output;
+    }
+    function create( name, attributes ){
+        var el = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", name );
+        if ( typeof attributes == 'object' ) {
+            for ( var i in attributes ){
+                el.setAttribute( i, attributes[i] );
+            }
+        }
+        for ( var i = 2; i<arguments.length; i++ ) {
+            var child = arguments[i];
+                if ( typeof child == 'string' )
+                            child = document.createTextNode( child );
+                el.appendChild( child );
+        }
+        return el;
+    }
+
+    try {
+        ko.views.manager.topView.currentView.setAttribute("collapsed", "false");
+
+        var v, tab, tabbox = ko.views.manager.topView.currentView.tabbox;
+        var uu = Components.classes['@mozilla.org/uuid-generator;1'].getService(Components.interfaces.nsIUUIDGenerator);
+        var tabpanelId = uu.generateUUID();
+
+        var img_doc = ko.extensions.Sites.docSvc.createDocumentFromURI(Img);
+
+        if(type){
+            window.setCursor("wait");
+            img_doc.load();
+            Img = 'data:image/' + type + ';base64,' + encode64(img_doc.encodedText);
+            window.setCursor("auto");
+        }
+
+        var tabpanel =  create( "tabpanel", {flex : "1" },
+                        v = create( "view", {flex : '1', type : 'xul'},
+                                create( "vbox", {flex : '1'},
+                                    create( "separator", {flex : '1'}),
+                                    create( "hbox", {},
+                                        create( "separator", {flex : '1'}),
+                                        create( "image"    , {src  : Img, style : "max-height:600px; max-width:800px;"}),
+                                        create( "separator", {flex : '1'})
+                                    ),
+                                    create( "separator", {flex : '1'})
+                                )
+                            )
+                        );
+
+            tabpanel.id     = tabpanelId;
+            tabpanel._tab   = tab = create( "tab",{ type    : "file-tab",
+                                                    label   : tab_name,
+                                                    onclick : "this.parentNode.parentNode.parentNode.tabClicked(this,event);",
+                                                    id      : uu.generateUUID()
+                                                  }
+                                    );
+                              tab.linkedPanel = tabpanelId;
+
+        tabbox._tabs.appendChild(tab);
+        tabbox._tabpanels.appendChild(tabpanel);
+        tabbox.firstChild.removeAttribute("closedisabled");
+        tabbox.handleCtrlTab = "false";
+
+        v.parentView = ko.views.manager.topView.currentView;
+        v.document = img_doc;
+
+        v.init();
+        v.makeCurrent();
+    } catch (e) { alert(e); }
+
+    return v;
+}
+
+//function decode64(input) {
+//    var output = "";
+//    var chr1, chr2, chr3;
+//    var enc1, enc2, enc3, enc4;
+//    var i = 0;
+//    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+//    do {
+//        enc1 = keyStr.indexOf(input.charAt(i++));
+//        enc2 = keyStr.indexOf(input.charAt(i++));
+//        enc3 = keyStr.indexOf(input.charAt(i++));
+//        enc4 = keyStr.indexOf(input.charAt(i++));
+//        chr1 = (enc1 << 2) | (enc2 >> 4);
+//        chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+//        chr3 = ((enc3 & 3) << 6) | enc4;
+//        output = output + String.fromCharCode(chr1);
+//        if (enc3 != 64) {
+//            output = output + String.fromCharCode(chr2);
+//        }
+//        if (enc4 != 64) {
+//            output = output + String.fromCharCode(chr3);
+//        }
+//    } while (i < input.length);
+//    return output;
+//}

sites.jar/content/overlay.xul

+<?xml version="1.0"?>
+<!DOCTYPE overlay PUBLIC "-//MOZILLA//DTD XUL V1.0//EN" "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+<!-- ***** BEGIN LICENSE BLOCK *****
+   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   *
+   * The contents of this file are subject to the Mozilla Public License Version
+   * 1.1 (the "License"); you may not use this file except in compliance with
+   * the License. You may obtain a copy of the License at
+   * http://www.mozilla.org/MPL/
+   *
+   * Software distributed under the License is distributed on an "AS IS" basis,
+   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   * for the specific language governing rights and limitations under the
+   * License.
+   *
+   * The Initial Developer of the Original Code
+   * Portions created by the Initial Developer are Copyright (C) 2008
+   * the Initial Developer. All Rights Reserved.
+   *
+   * Tomas Brabenec - http://brabenec.net
+   * Based on code JSTreeDrive originally developed by Joker <deck@joker.exnet.su>
+   *
+   * Alternatively, the contents of this file may be used under the terms of
+   * either the GNU General Public License Version 2 or later (the "GPL"), or
+   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   * in which case the provisions of the GPL or the LGPL are applicable instead
+   * of those above. If you wish to allow use of your version of this file only
+   * under the terms of either the GPL or the LGPL, and not to allow others to
+   * use your version of this file under the terms of the MPL, indicate your
+   * decision by deleting the provisions above and replace them with the notice
+   * and other provisions required by the LGPL or the GPL. If you do not delete
+   * the provisions above, a recipient may use your version of this file under
+   * the terms of any one of the MPL, the GPL or the LGPL.
+   *
+   * ***** END LICENSE BLOCK ***** -->
+
+<?xml-stylesheet href="chrome://komodo/skin/global/global.css"       type="text/css"?>
+<?xml-stylesheet href="chrome://komodo/skin/bindings/scrolltabs.css" type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/filepicker.css"          type="text/css"?>
+<?xml-stylesheet href="chrome://global/skin/global.css"              type="text/css"?>
+<?xml-stylesheet href="chrome://sites/skin/sites.css"    type="text/css"?>
+
+<overlay id="SitesOverlay"
+         xmlns:html="http://www.w3.org/1999/xhtml"
+         xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+    <script src="chrome://sites/content/dinamicTree.js"   type="application/x-javascript"/>
+    <script src="chrome://sites/content/imageView.js"     type="application/x-javascript"/>
+    <script src="chrome://sites/content/servers.js"       type="application/x-javascript"/>
+
+
+
+    <tabs id="project_toolbox_tabs" minimizeleftcollapsed="false">
+        <tab id="sites_tab" label="Sites"
+             insertafter="codebrowser_tab"
+             tooltiptext="Local or remote files"
+             linkedpanel="sitesviewbox"
+             onmovetab_load="ko.extensions.Sites.servers_tree.focus();"
+              />
+    </tabs>
+
+
+    <tabpanels id="project_toolbox_tabpanels">
+
+        <!--<popupset>-->
+            <menupopup id="sites_edit_Smenu" onpopupshowing="ko.extensions.Sites.on_popupShowing(event)" >
+                <menuitem id="menu_rename_S" label="Rename"       class="menuitem-iconic-wide rename-iconz"   oncommand="ko.extensions.Sites.on_rename('S');"/>
+                <menuitem id="menu_link_S"   label="Make favorite" class="menuitem-iconic-wide link-iconz"     oncommand="ko.extensions.Sites.on_link();"/>
+                <menuitem id="menu_reload_S" label="Reload"       class="menuitem-iconic-wide reload-iconz"   oncommand="ko.extensions.Sites.S.init_List_forView();"/>
+                <menuitem id="menu_delete_S" label="Delete"       class="menuitem-iconic-wide delete-iconz"   oncommand="ko.extensions.Sites.on_delete('S');"/>
+            </menupopup>
+        <!--</popupset>        -->
+            <menupopup id="sites_edit_Fmenu">
+                <menuitem id="menu_rename_F" label="Rename" class="menuitem-iconic-wide rename-iconz" oncommand="ko.extensions.Sites.on_rename('F');"/>
+                <menuitem id="menu_delete_F" label="Delete" class="menuitem-iconic-wide delete-iconz" oncommand="ko.extensions.Sites.on_delete('F');"/>
+            </menupopup>
+
+        <tabpanel flex="1" id="sitesviewbox" insertafter="codebrowserviewbox">
+            <vbox flex="1" id="sites_main">
+                <hbox align="center" id="sites_button_panel" style="padding: 2px; padding-top: 0px;">
+                    <toolbarbutton
+                        id="sites_refresh_button"
+                        tooltiptext="Refresh"
+                        label="Refresh"
+                        buttonstyle="pictures"
+                        class="all-reload-icon"
+                        oncommand="ko.extensions.Sites.on_reload();" />
+                    <toolbarbutton
+                        id="sites_refresh_button"
+                        tooltiptext="Create Directory"
+                        label="Create Directory"
+                        buttonstyle="pictures"
+                        class="newfolder-iconz"
+                        oncommand="ko.extensions.Sites.on_mkDir();" />
+                    <toolbarbutton
+                        id="sites_refresh_button"
+                        tooltiptext="Create File"
+                        label="Create File"
+                        buttonstyle="pictures"
+                        class="newfile-iconz"
+                        oncommand="ko.extensions.Sites.on_mkFile();" />
+
+                    <spacer flex="1"/>
+
+                    <toolbarbutton
+                        id="sites_accounts_button"
+                        tooltiptext="Accounts"
+                        label="Accounts"
+                        buttonstyle="pictures"
+                        class="server-pref-icon"
+                        oncommand="ko.windowManager.getMainWindow().prefs_doGlobalPrefs('serversItem');" />
+                </hbox>
+
+                <tree id="sites_S_tree"
+                      flex="1" seltype="single" flags="dont-build-content"
+                      onselect="ko.extensions.Sites.on_directorySelect(event);"
+                      hidecolumnpicker="true"
+                      style="margin: 0px; padding: 0px;">
+                    <treecols>
+                        <treecol id="tree_col_folder_name"
+                                 primary="true" flex="1"
+                                 hideheader="true"/>
+                    </treecols>
+                    <treechildren  flex="1" context="sites_edit_Smenu" />
+                </tree>
+
+                <splitter id="sites_splitter"
+                          collapse="after"
+                          class="grippy_splitter_collapsable"
+                          orient="vertical"
+                          persist="state"
+                          style="margin: 0px; padding: 0px;"><!-- border: none;  -->
+                </splitter>
+
+                <tree id="sites_F_tree"
+                      flex="1"
+                      seltype="single"
+                      onclick="ko.extensions.Sites.on_Open(event);"
+                      onkeypress="ko.extensions.Sites.on_Open(event);"
+                      style="margin: 0px; padding: 0px;"><!--seltype="multiple"-->
+                    <treecols>
+                        <treecol id="file_tree_col_name"
+                                 label="Files name"
+                                 flex="3"
+                                 crop="center"
+                                 persist="width ordinal hidden sortActive sortDirection"
+                                 class="sortDirectionIndicator"
+                                 sortActive="true"/>
+                        <splitter class="tree-splitter" />
+                        <treecol id="file_tree_col_size"
+                                 label="Size"
+                                 flex="1"
+                                 persist="width ordinal hidden sortActive sortDirection"
+                                 class="sortDirectionIndicator"/>
+                        <splitter class="tree-splitter" />
+                        <treecol id="file_tree_col_date"
+                                 label="Date"
+                                 flex="1"
+                                 persist="width ordinal hidden sortActive sortDirection"
+                                 class="sortDirectionIndicator"/>
+                    </treecols>
+                    <treechildren flex="1" context="sites_edit_Fmenu" />
+                </tree>
+            </vbox>
+        </tabpanel>
+    </tabpanels>
+
+</overlay>

sites.jar/content/servers.js

+/* ***** BEGIN LICENSE BLOCK *****
+   * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+   *
+   * The contents of this file are subject to the Mozilla Public License Version
+   * 1.1 (the "License"); you may not use this file except in compliance with
+   * the License. You may obtain a copy of the License at
+   * http://www.mozilla.org/MPL/
+   *
+   * Software distributed under the License is distributed on an "AS IS" basis,
+   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+   * for the specific language governing rights and limitations under the
+   * License.
+   *
+   * The Initial Developer of the Original Code
+   * Portions created by the Initial Developer are Copyright (C) 2008
+   * the Initial Developer. All Rights Reserved.
+   *
+   * Tomas Brabenec - http://brabenec.net
+   * Based on code JSTreeDrive originally developed by Joker <deck@joker.exnet.su>
+   *
+   * Alternatively, the contents of this file may be used under the terms of
+   * either the GNU General Public License Version 2 or later (the "GPL"), or
+   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+   * in which case the provisions of the GPL or the LGPL are applicable instead
+   * of those above. If you wish to allow use of your version of this file only
+   * under the terms of either the GPL or the LGPL, and not to allow others to
+   * use your version of this file under the terms of the MPL, indicate your
+   * decision by deleting the provisions above and replace them with the notice
+   * and other provisions required by the LGPL or the GPL. If you do not delete
+   * the provisions above, a recipient may use your version of this file under
+   * the terms of any one of the MPL, the GPL or the LGPL.
+   *
+   * ***** END LICENSE BLOCK ***** */
+
+
+(function() {
+this.init_serverList = function(){
+    var Self = ko.extensions.Sites;
+
+    function Server(protocol, alias, hostname, port, path, username, password){
+        this.protocol = protocol;
+        this.alias    = alias;
+        this.hostname = hostname;
+        this.port     = port;
+        this.path     = path;
+        this.username = username;
+        this.password = password;
+
+        this.connection     = null;
+        this.rf_info        = null;
+    }
+    Server.prototype.connect = function(){
+        window.setCursor("wait");
+        // Try and connect to this server now
+        try {
+            if(!this.connection){
+                var lastErrorSvc = Components.classes["@activestate.com/koLastErrorService;1"].
+                                         getService(Components.interfaces.koILastErrorService);
+                    lastErrorSvc.setLastError(0, ""); // Clear the last error
+
+
+                var connection = Self.rConnectSvc.getConnection(this.protocol.toLowerCase(),
+                                                                this.hostname,
+                                                                this.port,
+                                                                this.username,
+                                                                this.password,
+                                                                "");
+
+                if (!this.path) this.path = connection.getHomeDirectory();
+                this.username             = connection.username;
+                this.connection           = connection;
+                this.rf_info              = connection.list(this.path, 0);  // 0 for NO refresh
+                this.connection.alias     = this.alias;
+            }
+        } catch (ex) {
+            alert("Connection error: " + lastErrorSvc.getLastErrorMessage());
+        }
+        window.setCursor("auto");
+        return this.connection;
+    }
+    Server.prototype.disconnect = function(){
+        if (this.connection) {
+            this.connection.close();
+            this.connection = null;
+        }
+    }
+
+
+    function get_serversListKo4(){
+        try {
+            var passwd  = Components.classes["@mozilla.org/passwordmanager;1"].
+                          getService(Components.interfaces.nsIPasswordManager);
+            var e       = passwd.enumerator;
+
+            var list = [];
+            var count = 0;
+            while (e.hasMoreElements()) {
+                count++;
+                var nspassword = e.getNext().QueryInterface(Components.interfaces.nsIPassword);
+                var server_info = new String(nspassword.host).split(":");
+
+                list.push(   new Server(server_info[0],
+                                        server_info[1],
+                                        server_info[2],
+                                        server_info[3],
+                                        server_info[4],
+                                        new String(nspassword.user),
+                                        new String(nspassword.password)
+                                        )
+                         );
+                list.sort( function (a,b) { if (a.alias==b.alias) return 0; if (a.alias<b.alias) return -1; return 1; });
+            }
+
+        } catch(e) {
+            log.exception(e);
+        }
+
+        return list;
+    }
+    function get_serversListKo5(){
+        try {
+            var list  = [];
+            var server_infoList = Self.rConnectSvc.getServerInfoList( {} );
+
+            for (var i=0; i < server_infoList.length; i++){
+
+                list.push(  new Server(server_infoList[i].protocol,
+                                       server_infoList[i].alias,
+                                       server_infoList[i].hostname,
+                                       server_infoList[i].port,
+                                       server_infoList[i].path,
+                                       server_infoList[i].username,
+                                       server_infoList[i].password)
+                          );
+            }
+        } catch(e) {
+            log.exception(e);
+        }
+
+        return list;
+    }
+
+    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+    var appInfo = Components.classes["@activestate.com/koInfoService;1"].
+                        getService(Components.interfaces.koIInfoService);
+
+    this.servers_list = (appInfo.version[0] <= "4") ? get_serversListKo4() : get_serversListKo5() ;
+}
+
+this.init_rowsList = function(){
+    var Self = ko.extensions.Sites;
+
+    function LocalDir  (elPath, elName,      depth, parent_idx, sibling_idx){
+        this.path = elPath + elName +'/';
+        this.name = elName;
+
+        this.open        = false;
+        this.depth       = depth + 1;
+        this.parent_idx  = parent_idx;
+        this.sibling_idx = sibling_idx;
+    }
+    function LocalFile (elPath, elName){
+        this.path = elPath + elName;
+
+        try {
+            var sizez = {}
+            var time = {}
+            Self.osSvc.stat(this.path,{},{},{},{},{},{},sizez,{},time,{})
+        } catch(e) {sizez.value = 'too big'; time.value = '00.00.00'}
+
+        this.name = elName;
+        this.size = sizez.value;
+        this.time = time.value;
+
+        var Ex = this.name.toLowerCase().match(/\.([a-z0-9]{1,4})$/)
+        if(Ex && Ex[1]) this.ext = Ex[1]; else this.ext = 'zzznoext';
+    }
+    //
+    LocalDir.prototype.getFileList  = function(){
+        var files = [];
+        var count = {};
+
+        var list_names = Self.osSvc.listdir(this.path, count)
+
+        for (var i = 0; i < count.value; i++) {
+            if(!Self.osSvc.path.isdir(this.path + list_names[i])){
+                files.push(new LocalFile(this.path, list_names[i]));
+            }
+        }
+
+        files.sort( function(a, b) {
+
+                        if(a.ext == b.ext){
+                            if(a.name == b.name){
+                                return 0;
+                            }
+                            return (a.name > b.name) ? 1 : -1;
+                        }
+                        return (a.ext > b.ext) ? 1 : -1;
+                    } );
+
+        return files;
+    }
+    LocalDir.prototype.setDirList   = function(num, tree_rows){
+        var count      = {};
+        var dircount   = 0;
+
+        var list_names = Self.osSvc.listdir(this.path, count)
+            list_names.sort( function(a, b) { if ( (a && b) && (a > b) ) return 1; else return -1; } );
+
+        for (var i = 0; i < count.value; i++) {
+            if(Self.osSvc.path.isdir(this.path + list_names[i])){
+                tree_rows.splice( num + dircount + 1, 0,
+                                  new LocalDir(this.path, list_names[i], this.depth, num, dircount)
+                                );
+                dircount++;
+            }
+        }
+
+        return dircount;
+    }
+    LocalDir.prototype.mkLink       = function(){
+//        return new LocalDir(this.path.substr(0, this.path.length - this.name.length - 1), this.name, -1, -1, this.sibling_idx)
+        var path = this.path.substr(0, this.path.length - this.name.length - 1)
+        var L = new LocalDir(path, this.name, -1, -1, this.sibling_idx);
+            L.link = 'local';
+            Self.prefs_saveTo('{'+ 'path : "' + path + '", sibling_idx : "' + L.sibling_idx + '", name : "' + L.name + '"}')
+        return L
+    }
+    LocalDir.prototype.mkDir        = function(name){
+        Self.osSvc.mkdir(this.path + name)
+    }
+    LocalDir.prototype.mkFile       = function(name){
+        var newFile = Self.docSvc.createDocumentFromURI(ko.uriparse.localPathToURI(this.path) + name)
+            ko.views.manager.topView.createViewFromDocument(newFile, 'editor')
+            newFile.save(true)
+    }
+    LocalDir.prototype.remove       = function(){
+        var sysUtilsSvc = Components.classes['@activestate.com/koSysUtils;1'].
+                                getService(Components.interfaces.koISysUtils);
+            sysUtilsSvc.MoveToTrash(this.path.substr(0,this.path.length-1));
+    }
+    LocalDir.prototype.rename       =
+    LocalFile.prototype.rename      = function(name){
+        var new_path = this.path.replace(new RegExp(this.name + '[\/]?$'), name)
+        Self.osSvc.rename(this.path , new_path)
+        if(Self.osSvc.path.isdir(new_path)) new_path += '/'
+        this.path = new_path;
+        this.name = name;
+    }
+    LocalFile.prototype.remove      = function(){
+        var sysUtilsSvc = Components.classes['@activestate.com/koSysUtils;1'].
+                                getService(Components.interfaces.koISysUtils);
+            sysUtilsSvc.MoveToTrash(this.path);
+    }
+    LocalFile.prototype.open        = function(){
+        switch(this.ext)
+        {
+            case 'gif':
+            case 'jpeg':
+            case 'jpg':
+            case 'png':
+            case 'bmp':
+            case 'ico':
+                Self.imageView(ko.uriparse.localPathToURI(this.path), this.name, false)
+            break;
+            default:
+                ko.open.URI(ko.uriparse.localPathToURI(this.path))
+        }
+    }
+
+    function RemoteDir (connection, rf_info, depth, parent_idx, sibling_idx, server_num, name){
+        this.rf_info     = rf_info;
+        this.connection  = connection;
+
+        this.name = name || rf_info.getFilename();
+
+        this.open        = false;
+        this.depth       = depth + 1;
+        this.parent_idx  = parent_idx;
+        this.sibling_idx = sibling_idx;
+        this.server_num  = server_num;
+    }
+    function RemoteFile(connection, rf_info){
+        this.uri  = Self.rConnectSvc.getUriForConnectionAndRfInfo(connection, rf_info) ;
+        this.name = rf_info.getFilename();
+        this.size = rf_info.getFileSize();
+        this.time = rf_info.getModifiedTime();
+
+        var Ex = this.name.toLowerCase().match(/\.([a-z0-9]{1,4})$/)
+        if(Ex && Ex[1]) this.ext = Ex[1]; else this.ext = 'zzznoext';
+    }
+    //
+    RemoteDir.prototype.connect     = function(refresh){
+        try{
+            if(!this.connection)                              // Depth is 0, it's a server
+                this.connection = Self.servers_list[this.server_num].connect();
+
+            if(!this.rf_info && this.depth == 0)
+                this.rf_info = Self.servers_list[this.server_num].rf_info;
+
+            if(this.link && this.link != 'local')
+                this.rf_info = this.connection.list(this.link, 1);
+            else if ((refresh || this.rf_info.needsDirectoryListing()) && this.rf_info.isDirectory() ) // Ensure the directory has been populated
+                this.rf_info = this.connection.list(this.rf_info.getFilepath(), 1);
+
+        } catch(e) {
+            alert("RemoteDir.prototype.connect" + e);
+        }
+    }
+    RemoteDir.prototype.getFileList = function(){
+        this.connect();
+
+        var files = [];
+        var count = {};
+
+        var rf_info_list = this.rf_info.getChildren(count);
+
+        for (var i = 0; i < count.value; i++) {
+            if (rf_info_list[i].isFile()) {
+                files.push(new RemoteFile(this.connection, rf_info_list[i]));
+            }
+        }
+
+        files.sort( function(a, b) {
+                        if(a.ext == b.ext){
+                            if(a.name == b.name){
+                                return 0;
+                            }
+                            return (a.name > b.name) ? 1 : -1;
+                        }
+                        return (a.ext > b.ext) ? 1 : -1;
+                    } );
+        return files;
+    }
+    RemoteDir.prototype.setDirList  = function(num, tree_rows){
+        this.connect();
+
+        var count        = {};
+        var dircount     = 0;
+
+        var rf_info_list = this.rf_info.getChildren(count);
+            rf_info_list.sort( function(a, b) { var x = a.getFilename();
+                                                var y = b.getFilename();
+                                                if ( (x && y) && (x > y) ) return 1; else return -1; } );
+
+        for (var i = 0; i < count.value; i++) {
+            if (rf_info_list[i].isDirectory()) {
+                tree_rows.splice( num + dircount + 1, 0,
+                                  new RemoteDir(this.connection, rf_info_list[i], this.depth, num, dircount, this.server_num)
+                                );
+                dircount++;
+            }
+        }
+
+        return dircount;
+    }
+    RemoteDir.prototype.mkLink      = function(){
+//        return new RemoteDir(this.connection, this.rf_info, -1, -1, 999, this.server_num, this.name);
+        var L = new RemoteDir(this.connection, this.rf_info, -1, -1, this.sibling_idx, this.server_num, this.name);
+            L.link = L.rf_info.getFilepath();
+            Self.prefs_saveTo('{'+ 'link : "' + L.link + '", sibling_idx : "' + L.sibling_idx + '", server_num : "' + L.server_num + '", name : "' + L.name + '"}')
+        return L
+    }
+    RemoteDir.prototype.mkDir       = function(name){
+        this.connection.createDirectory(this.rf_info.getFilepath() + '/' + name, 0755);
+    }
+    RemoteDir.prototype.mkFile      = function(name){
+        var newFile = Self.docSvc.createDocumentFromURI(Self.rConnectSvc.getUriForConnectionAndRfInfo(this.connection, this.rf_info)+ '/' + name)
+            ko.views.manager.topView.createViewFromDocument(newFile, 'editor')
+            newFile.save(true)
+    }
+    RemoteDir.prototype.rename      = function(name){
+        this.connection.rename(this.rf_info.getDirname() + '/' + this.name, this.rf_info.getDirname() + '/' + name);
+        this.name = name;
+        Self.on_reload(true)
+    }
+    RemoteDir.prototype.remove      = function(){
+        this.connection.removeDirectory(this.rf_info.getDirname() + '/' + this.name);
+
+        Self.on_reload(true)
+    }
+    RemoteFile.prototype.rename     = function(name){
+        var sRow = Self.S.tree_rows[Self.S.selection.currentIndex];
+        sRow.connection.rename(sRow.rf_info.getFilepath() + '/' + this.name, sRow.rf_info.getFilepath() + '/' + name);
+        this.name = name;
+    }
+    RemoteFile.prototype.remove     = function(){
+        var sRow = Self.S.tree_rows[Self.S.selection.currentIndex];
+        sRow.connection.removeFile(sRow.rf_info.getFilepath() + '/' + this.name);
+    }
+    RemoteFile.prototype.open       = function(){
+        switch(this.ext)
+        {
+            case 'gif':
+                Self.imageView(this.uri, this.name, 'gif');
+                break;
+            case 'jpeg':
+            case 'jpg':
+                Self.imageView(this.uri, this.name, 'jpeg');
+                break;
+            case 'png':
+                Self.imageView(this.uri, this.name, 'png');
+                break;
+            default:
+                ko.open.URI(this.uri)
+        }
+    }
+
+    try{
+        this.init_serverList();
+
+        var  numServers   = this.servers_list.length;
+        var  serversRows  = [];
+        for (var i=0; i < numServers; i++) {
+            serversRows.push( new RemoteDir (null, null, -1, -1, i, i, this.servers_list[i].alias) );
+        }
+
+        // ����������� ��������� ����
+        if(this.osSvc.name == 'nt'){
+
+            for(var i=35;i>11;i--)
+                if(this.osSvc.access(i.toString(36) + ':/',2))
+                    serversRows.splice(0,0,new LocalDir('', i.toString(36).toUpperCase() + ':', -1, -1, 0))
+
+        }else{
+            serversRows.splice(0,0,new LocalDir('/', 'Local Drive', -1, -1, 0))
+            serversRows[0].path = '/';
+        }
+        // ����������� links
+        var L, Ltemp;
+        Ltemp = this.prefs_loadFrom()
+        if(Ltemp){
+            this.links = Ltemp.split(";")
+            var links = eval('([' + this.links.join(",") + '])');
+                links.reverse()
+            for(L in links){
+                if(links[L].link){
+                    Ltemp = new RemoteDir(null, null, -1, -1, links[L].sibling_idx, links[L].server_num, links[L].name);
+                    Ltemp.link = links[L].link;
+                }
+                else{
+                    Ltemp = new LocalDir(links[L].path, links[L].name, -1, -1, links[L].sibling_idx);
+                    Ltemp.link = 'local';
+                }
+                serversRows.splice(0,0, Ltemp);
+            }
+        }
+    } catch(e) {
+        log.exception(e);
+    }
+
+    return serversRows;
+}
+
+
+
+// functions called from overlay.xul
+this.on_directorySelect = function(event){
+    try {
+        // Server directory was selected, update the files shown in the tree
+        if (this.S) {
+        this.S.update_fileTree_fromDirRow(this.s_XULtree.currentIndex, false /* refresh */);
+        }
+    } catch (e) {
+        window.setCursor("auto");
+        alert('on_directorySelect - ' + e);
+    }
+}
+this.on_Open            = function(event){
+    try {
+        if (event.target.localName != "treechildren" && event.target.localName != "tree")
+            return false;
+        if (event.type == "click" && (event.button != 0 || event.detail != 2))
+            return false;
+        if (event.type == "keypress" && event.keyCode != 13)
+            return false;
+
+//        Server file was requested to be opened
+//        if (this.F) this.F.open_selectedFiles();
+        this.F.file_rows[this.F.selection.currentIndex].open();
+    } catch (e) {
+       alert('on_Open - ' + e);
+    }
+    return true;
+}
+
+// toolbarbutton
+this.on_reload          = function(level_up, forse_F){
+    var num   = this.S.selection.currentIndex;
+    var aRows = this.S.tree_rows;
+
+    if(level_up) num = aRows[num].parent_idx
+
+    if(aRows[num].rf_info) aRows[num].connect(true); // for refresh
+
+    if(aRows[num].open){
+        this.S.clear_subRows(num) // delete subdirs
+        this.S.selection.tree.rowCountChanged(num + 1, aRows[num].setDirList(num, aRows)) // add subdirs
+    }
+    if(this.F.selection.currentIndex > -1){
+        this.S.update_fileTree_fromDirRow(num);
+    }
+    if(forse_F){
+        this.S.update_fileTree_fromDirRow(num);
+    }
+}
+this.on_mkDir           = function() {
+    var dirName = ko.dialogs.prompt("Enter the name for the new directory");
+    if (!dirName) return false;
+
+    var ret = false;
+    window.setCursor("wait");
+    try {
+        this.S.tree_rows[this.S.selection.currentIndex].mkDir(dirName);
+
+        this.S.tree_rows[this.S.selection.currentIndex].open = true ;
+        this.S.selection.tree.invalidateRow(this.S.selection.currentIndex);
+
+        this.on_reload();
+        ret = true;
+    } catch (ex) {
+        alert("Cannot make new directory: " + ex);
+    }
+    window.setCursor("auto");
+    return ret;
+}
+this.on_mkFile          = function() {
+    var fileName = ko.dialogs.prompt("Enter the name for the new file");
+    if (!fileName) return false;
+
+    var ret = false;
+    window.setCursor("wait");
+    try {
+        this.S.tree_rows[this.S.selection.currentIndex].mkFile(fileName);
+
+        this.on_reload(false, true);
+        ret = true;
+    } catch (ex) {
+        alert("Cannot make new file: " + ex);
+    }
+    window.setCursor("auto");
+    return ret;
+}
+
+// files menupopup
+this.on_rename          = function(SorF) {
+    try {
+        if(SorF == 'S')
+            var aRow = this.S.tree_rows[this.S.selection.currentIndex];
+        else
+            var aRow = this.F.file_rows[this.F.selection.currentIndex];
+
+        var newName = ko.dialogs.prompt("Enter the new name...", null, aRow.name)
+        if (!newName || newName == aRow.name) return false;
+
+        aRow.rename(newName);
+
+        this.on_reload();
+        return true;
+    } catch (ex) {
+        alert("Cannot rename: " + ex);
+    }
+}
+this.on_delete          = function(SorF) {
+    if (ko.dialogs.yesNo("Delete ?", "No") == "No") {
+      return;
+    }
+    try {
+        if(SorF == 'F'){
+            this.F.file_rows[this.F.selection.currentIndex].remove();
+        }else{
+            if(this.S.tree_rows[this.S.selection.currentIndex].link){
+                this.prefs_deleteIt(this.S.selection.currentIndex);
+                this.S.clear_subRows(this.S.selection.currentIndex);
+                this.S.edit_rowItems('del', this.S.selection.currentIndex)
+                return;
+            }else{
+                this.S.tree_rows[this.S.selection.currentIndex].remove();
+            }
+        }
+
+        this.on_reload()
+    } catch (ex) {
+        alert("Cannot delete: " + ex);
+    }
+}
+this.on_link            = function() {
+    try {
+        this.S.edit_rowItems('link', 0, this.S.selection.currentIndex)
+    } catch (ex) {
+        alert("Cannot make: " + ex);
+    }
+}
+
+
+this.on_popupShowing    = function() {
+    var S_Row = this.S.tree_rows[document.popupNode._lastSelectedRow]
+    if(S_Row.depth == 0){
+        if(S_Row.link){
+            $('menu_rename_S').hidden = true;
+            $('menu_link_S').hidden   = true;
+            $('menu_delete_S').hidden = false;
+            $('menu_reload_S').hidden = true;
+        }
+        else if(S_Row.path){
+            $('menu_rename_S').hidden = true;
+            $('menu_link_S').hidden   = true;
+            $('menu_delete_S').hidden = true;
+            $('menu_reload_S').hidden = false;
+        }
+        else{
+            $('menu_rename_S').hidden = true;
+            $('menu_link_S').hidden   = true;
+            $('menu_delete_S').hidden = true;
+            $('menu_reload_S').hidden = false;
+//            $('sites_edit_Smenu').appendChild(
+//                                            create( "menuitem",{id : "menu_reload_S",
+//                                                                label : "Reload",
+//                                                                oncommand : "ko.extensions.Sites.S.init_List_forView();"})
+//                                        );
+        }
+    }else{
+            $('menu_rename_S').hidden = false;
+            $('menu_link_S').hidden   = false;
+            $('menu_delete_S').hidden = false;
+            $('menu_reload_S').hidden = true;
+    }
+}
+
+
+this.run = function(){
+    this.s_XULtree          = document.getElementById("sites_S_tree");
+    this.s_XULtree.view     = this.S;
+    this.f_XULtree          = document.getElementById('sites_F_tree');
+    this.f_XULtree.view     = this.F;
+    this.S.init_List_forView();
+}
+
+}).apply(ko.extensions.Sites);
+
+//addEventListener("load", ko.extensions.Sites.run, false);
+//addEventListener("load", function() { setTimeout(ko.extensions.Sites.run, 3000); }, false);
+window.addEventListener("load", function(event) { ko.extensions.Sites.run(event); }, false);
+
+//            var urls = [];
+//            var rangeCount = this.F.selection.getRangeCount();
+//            for (var i=0; i < rangeCount; i++) {
+//                var start = {}; var end = {};
+//                this.F.selection.getRangeAt(i, start, end);
+//
+//                for (var c=start.value; c <= end.value; c++) {
+//                    urls.push(this.F.file_rows[c]);
+//                }
+//            }
+//            for (var cc in urls) {
+//                urls[cc].remove();
+//            }

sites.jar/skin/images/folder-link.png

Added
New image

sites.jar/skin/images/gif.png

Added
New image

sites.jar/skin/images/jpg.png

Added
New image

sites.jar/skin/images/php.png

Added
New image

sites.jar/skin/images/png.png

Added
New image

sites.jar/skin/images/project_icon.png

Added
New image

sites.jar/skin/images/python.png

Added
New image

sites.jar/skin/sites.css

+treechildren::-moz-tree-image(FilenameColumn, computer) {
+  list-style-image: url("chrome://famfamfamsilk/skin/icons/computer.png");
+  margin-right: 3px !important;
+}
+treechildren::-moz-tree-image(FilenameColumn, server) {
+  list-style-image: url("chrome://famfamfamsilk/skin/icons/server_link.png");
+  margin-right: 3px !important;
+}
+treechildren::-moz-tree-image(FilenameColumn, link) {
+  list-style-image: url('chrome://sites/skin/images/folder-link.png');
+  margin-right: 3px;
+}
+treechildren::-moz-tree-image(FilenameColumn, directory-open) {
+  list-style-image: url('chrome://komodo/skin/images/folder-open.png');
+  margin-right: 3px;
+}
+treechildren::-moz-tree-image(FilenameColumn, directory-close) {
+  list-style-image: url('chrome://komodo/skin/images/folder-closed.png');
+  margin-right: 3px;
+}
+
+
+treechildren::-moz-tree-image(FilenameColumn, file-icon) {
+  list-style-image: url('chrome://komodo/skin/images/existing_file.png');
+  margin-right: 5px !important;
+}
+treechildren::-moz-tree-image(FilenameColumn, xml-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/page_white_code.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, xul-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/application_form.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, html-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/html.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, htm-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/html.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, tpl-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/page_code.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, css-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/css.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, js-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/script_code.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, rb-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/ruby.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, php-icon) {
+/*  list-style-image: url('chrome://famfamfamsilk/skin/icons/page_white_php.png'); */
+  list-style-image: url('chrome://sites/skin/images/php.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, py-icon) {
+/* list-style-image: url('chrome://famfamfamsilk/skin/icons/arrow_switch.png');
+  list-style-image: url('chrome://komodo/skin/images/lang_python.png'); */
+  list-style-image: url('chrome://sites/skin/images/python.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, c-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/page_white_c.png');
+  margin-right: 5px;
+}
+
+treechildren::-moz-tree-image(FilenameColumn, image-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/image.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, png-icon) {
+  list-style-image: url('chrome://sites/skin/images/png.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, gif-icon) {
+  list-style-image: url('chrome://sites/skin/images/gif.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, jpg-icon) {
+  list-style-image: url('chrome://sites/skin/images/jpg.png');
+  margin-right: 5px;
+}
+
+
+treechildren::-moz-tree-image(FilenameColumn, arh-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/package_green.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, cmd-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/application_osx_terminal.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, xpi-icon) {
+  list-style-image: url('chrome://famfamfamsilk/skin/icons/bricks.png');
+  margin-right: 5px;
+}
+treechildren::-moz-tree-image(FilenameColumn, kpf-icon) {
+  list-style-image: url('chrome://sites/skin/images/project_icon.png');
+  margin-right: 5px;
+}
+.toggle-hidden-icon
+{
+    list-style-image : url("chrome://komodo/skin/images/tree_select.png");
+}
+.all-reload-icon
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/arrow_refresh.png');
+}
+.newfolder-iconz
+{
+    /*list-style-image : url("chrome://famfamfamsilk/skin/icons/folder_add.png");*/
+    list-style-image : url("chrome://komodo/skin/images/new_live_folder.png");
+}
+.newfile-iconz
+{
+    /*list-style-image : url("chrome://famfamfamsilk/skin/icons/script_add.png");*/
+    list-style-image : url("chrome://komodo/skin/images/new_file.png");
+}
+
+
+/* +++++++++++++++++  popup menu +++++++++++++++++ */
+.reload-iconz
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/arrow_refresh.png');
+}
+.reload-iconz:hover
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/arrow_refresh.png');
+}
+.reload-iconz[disabled="true"],
+.reload-iconz[disabled="true"]:hover,
+.reload-iconz[disabled="true"]:hover:active
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/arrow_refresh.png');
+}
+
+.rename-iconz
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/textfield_rename.png');
+}
+.rename-iconz:hover
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/textfield_rename.png');
+}
+.rename-iconz[disabled="true"],
+.rename-iconz[disabled="true"]:hover,
+.rename-iconz[disabled="true"]:hover:active
+{
+    list-style-image : url('chrome://famfamfamsilk/skin/icons/textfield_rename.png');
+}
+
+.link-iconz
+{
+    list-style-image : url('chrome://sites/skin/images/folder-link.png');
+}
+.link-iconz:hover
+{
+    list-style-image : url('chrome://sites/skin/images/folder-link.png');
+}
+.link-iconz[disabled="true"],
+.link-iconz[disabled="true"]:hover,
+.link-iconz[disabled="true"]:hover:active
+{
+    list-style-image : url('chrome://sites/skin/images/folder-link.png');
+}
+
+.delete-iconz
+{
+    list-style-image : url('chrome://komodo/skin/images/list_item_remove.png');
+}
+.delete-iconz:hover
+{
+    list-style-image : url('chrome://komodo/skin/images/list_item_remove_hover.png');
+}
+.delete-iconz[disabled="true"],
+.delete-iconz[disabled="true"]:hover,
+.delete-iconz[disabled="true"]:hover:active
+{
+    list-style-image : url('chrome://komodo/skin/images/list_item_remove_disable.png');
+}