// JavaScript Document

function __locstring(s) {
  if (typeof(LocStrings) != "undefined") {
    if (LocStrings[s]) {
      return LocStrings[s];
    }
  }
  return s;
}

  if (Ext.version == 2.1) {
     // private
     Date.createParser = function(format) {
       var funcName = "parse" + Date.parseFunctions.count++;
       var regexNum = Date.parseRegexes.length;
       var currentGroup = 1;
       Date.parseFunctions[format] = funcName;

       var code = "Date." + funcName + " = function(input){\n"
           + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, ms = -1, o, z, u, v;\n"
           + "input = String(input);var d = new Date();\n"
           + "y = d.getFullYear();\n"
           + "m = d.getMonth();\n"
           + "d = d.getDate();\n"
           + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
           + "if (results && results.length > 0) {";
       var regex = "";

       var special = false;
       var ch = '';
       for (var i = 0; i < format.length; ++i) {
           ch = format.charAt(i);
           if (!special && ch == "\\") {
               special = true;
           }
           else if (special) {
               special = false;
               regex += String.escape(ch);
           }
           else {
               var obj = Date.formatCodeToRegex(ch, currentGroup);
               currentGroup += obj.g;
               regex += obj.s;
               if (obj.g && obj.c) {
                   code += obj.c;
               }
           }
       }

       code += "if (u){\n"
           + "v = new Date(u * 1000);\n" // give top priority to UNIX time
           + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0 && ms >= 0){\n"
           + "v = new Date(y, m, d, h, i, s, ms);\n"
           + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0){\n"
           + "v = new Date(y, m, d, h, i, s);\n"
           + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0){\n"
           + "v = new Date(y, m, d, h, i);\n"
           + "}else if (y >= 0 && m >= 0 && d > 0 && h >= 0){\n"
           + "v = new Date(y, m, d, h);\n"
           + "}else if (y >= 0 && m >= 0 && d > 0){\n"
           + "v = new Date(y, m, d);\n"
           + "}else if (y >= 0 && m >= 0){\n"
           + "v = new Date(y, m);\n"
           + "}else if (y >= 0){\n"
           + "v = new Date(y);\n"
           + "}\n}\nreturn (v && (z || o))?" // favour UTC offset over GMT offset
           +     " (Ext.type(z) == 'number' ? v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - z) :" // reset to UTC, then add offset
           +         " v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn))) : v;\n" // reset to GMT, then add offset
           + "}";

       Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$", "i");
       eval(code);
     };

     // private
     Ext.apply(Date.parseCodes, {
         j: {
             g:1,
             c:"d = parseInt(results[{0}], 10);\n",
             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
         },
         M: function() {
             for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names
             return Ext.applyIf({
                 s:"(" + a.join("|") + ")"
             }, Date.formatCodeToRegex("F"));
         },
         n: {
             g:1,
             c:"m = parseInt(results[{0}], 10) - 1;\n",
             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
         },
         o: function() {
             return Date.formatCodeToRegex("Y");
         },
         g: function() {
             return Date.formatCodeToRegex("G");
         },
         h: function() {
             return Date.formatCodeToRegex("H");
         },
         P: {
           g:1,
           c:[
               "o = results[{0}];",
               "var sn = o.substring(0,1);", // get + / - sign
               "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);", // get hours (performs minutes-to-hour conversion also, just in case)
               "var mn = o.substring(4,6) % 60;", // get minutes
               "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
           ].join("\n"),
           s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
         }
     });

     // private
     Date.formatCodeToRegex = function(character, currentGroup) {
         // Note: currentGroup - position in regex result array (see notes for Date.parseCodes above)
         var p = Date.parseCodes[character];

         if (p) {
           p = Ext.type(p) == 'function'? p() : p;
           Date.parseCodes[character] = p; // reassign function result to prevent repeated execution
         }

         return p? Ext.applyIf({
           c: p.c? String.format(p.c, currentGroup || "{0}") : p.c
         }, p) : {
             g:0,
             c:null,
             s:Ext.escapeRe(character) // treat unrecognised characters as literals
         }
     };

     Date.prototype.getGMTOffset = function(colon) {
         return (this.getTimezoneOffset() > 0 ? "-" : "+")
             + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
             + (colon ? ":" : "")
             + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0");
     };

     Ext.isIE8 = !Ext.isOpera && navigator.userAgent.toLowerCase().indexOf("msie 8") > -1;
     Ext.isIE6 = Ext.isIE6 && !Ext.isIE8;
 }

// Time field that allows separate formats for display, submit
// If displayformat is set, then "format" is assumed to be what we want to submit
// If submitformat is set (or both are set), then "format" is assumed to be what we want for display.
// To be compatible with superclass, after init, "format" is what we want to submit.
Ext.form.GTimeField = Ext.extend(Ext.form.TimeField, {
  displayformat : null,
  submitformat : null,
  initComponent : function(){
    if (this.displayformat || this.submitformat) {
      if (this.submitformat) {
        if (!this.displayformat) {
          this.displayformat = this.format;
        }
        this.altFormats = this.displayformat + "|" + this.altFormats;
        this.format = this.submitformat;
      }
      if(typeof this.minValue == "string"){
          this.minValue = this.parseDate(this.minValue);
      }
      if(typeof this.maxValue == "string"){
          this.maxValue = this.parseDate(this.maxValue);
      }

      if(!this.store){
          var min = this.parseDate(this.minValue) || new Date(this.initDate).clearTime();
          var max = this.parseDate(this.maxValue) || new Date(this.initDate).clearTime().add('mi', (24 * 60) - 1);
          var times = [];
          while(min <= max){
              times.push([min.dateFormat(this.format), min.dateFormat(this.displayformat)]);
              min = min.add('mi', this.increment);
          }
          this.store = times;
      }
    }
    Ext.form.GTimeField.superclass.initComponent.call(this);
  }
});

// Date field that allows you to specify a format for submit, separate from format for display.
// getSubmitValue() returns a string in the submit format; fetDateValue() returns the value as a Date object.
// Also override setValue so it can take a string or a date.
// Wanted to override getValue, but too many extjs components expect to get a date back from it.
Ext.form.GDateField = Ext.extend(Ext.form.DateField, {
  submitformat : null,
  getSubmitValue : function() {
    if (this.submitformat) {
      var date = Ext.form.GDateField.superclass.getValue.call(this);
      return Ext.isDate(date) ? date.dateFormat(this.submitformat) : date;
    }
    return Ext.form.GDateField.superclass.getRawValue.call(this);
  },
  getDateValue : function() {
    return Ext.form.GDateField.superclass.getValue.call(this);
  },
  setValue : function(date) {
    Ext.form.GDateField.superclass.setValue.call(this, this.parseDate(date));
  }
});


/* temporary workaround for htmleditor disable/enable issue */
var HtmlEditorOnRender = Ext.form.HtmlEditor.onRender;

Ext.override(Ext.form.HtmlEditor, {
  onDisable: function(){
    if(this.rendered){
      this.wrap.mask();
    }
    Ext.form.HtmlEditor.superclass.onDisable.call(this);
  },
  defaultOnRender : Ext.form.HtmlEditor.prototype.onRender,

  onEnable: function(){
    if(this.rendered){
      this.wrap.unmask();
    }
    Ext.form.HtmlEditor.superclass.onEnable.call(this);
  }

});

Ext.DomQuery.operators["`="] = function(a, v) {
  vv = v.split(".");
  aa = a.split(" ");
  if (aa.length < vv.length) {
    return false;
  }
  for (var i = 0; i < vv.length; i++) {
    if (aa.indexOf(vv[i]) == -1) {
      return false;
    }
  }
  return true;
};

Ext.override(Ext.Element,
  { isVisible : function(deep) {
        var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
        if(deep !== true || !vis){
            return vis;
        }
        var p = this.dom.parentNode;
        while(p && p.tagName.toLowerCase() != "body"){
            if(!Ext.fly(p, '_isVisible').isVisible()){
                return false;
            }
            p = p.parentNode;
        }
        return true;
    }
  });


Ext.util.Format.br2nl = function(v) {
  return v === undefined || v === null ? '' : v.replace(/<br\s*\/?>/gi, '\n');
}


Ext.DataView.DragSelector = function(cfg){
    cfg = cfg || {};
    var view, regions, proxy, tracker;
    var rs, bodyRegion, dragRegion = new Ext.lib.Region(0,0,0,0);
    var dragSafe = cfg.dragSafe === true;

    this.init = function(dataView){
        view = dataView;
        view.on('render', onRender);
    };

    function fillRegions(){
        rs = [];
        view.all.each(function(el){
            rs[rs.length] = el.getRegion();
        });
        bodyRegion = view.el.getRegion();
    }

    function cancelClick(){
        return false;
    }

    function onBeforeStart(e){
        return !dragSafe || e.target == view.el.dom;
    }

    function onStart(e){
        view.on('containerclick', cancelClick, view, {single:true});
        if(!proxy){
            proxy = view.el.createChild({cls:'x-view-selector'});
        }else{
            proxy.setDisplayed('block');
        }
        fillRegions();
        view.clearSelections();
    }

    function onDrag(e){
        var startXY = tracker.startXY;
        var xy = tracker.getXY();

        var x = Math.min(startXY[0], xy[0]);
        var y = Math.min(startXY[1], xy[1]);
        var w = Math.abs(startXY[0] - xy[0]);
        var h = Math.abs(startXY[1] - xy[1]);

        dragRegion.left = x;
        dragRegion.top = y;
        dragRegion.right = x+w;
        dragRegion.bottom = y+h;

        dragRegion.constrainTo(bodyRegion);
        proxy.setRegion(dragRegion);

        for(var i = 0, len = rs.length; i < len; i++){
            var r = rs[i], sel = dragRegion.intersect(r);
            if(sel && !r.selected){
                r.selected = true;
                view.select(i, true);
            }else if(!sel && r.selected){
                r.selected = false;
                view.deselect(i);
            }
        }
    }

    function onEnd(e){
        if(proxy){
            proxy.setDisplayed(false);
        }
    }

    function onRender(view){
        tracker = new Ext.dd.DragTracker({
            onBeforeStart: onBeforeStart,
            onStart: onStart,
            onDrag: onDrag,
            onEnd: onEnd
        });
        tracker.initEl(view.el);
    }
};

Ext.ns('Ext.ux.form');

/**
 * @class Ext.ux.form.FileUploadField
 * @extends Ext.form.TextField
 * Creates a file upload field.
 * @xtype fileuploadfield
 */
Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField,  {
    /**
     * @cfg {String} buttonText The button text to display on the upload button (defaults to
     * 'Browse...').  Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text
     * value will be used instead if available.
     */
    buttonText: 'Browse...',
    /**
     * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
     * text field (defaults to false).  If true, all inherited TextField members will still be available.
     */
    buttonOnly: false,
    /**
     * @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field
     * (defaults to 3).  Note that this only applies if {@link #buttonOnly} = false.
     */
    buttonOffset: 3,
    /**
     * @cfg {Object} buttonCfg A standard {@link Ext.Button} config object.
     */

    // private
    readOnly: true,

    /**
     * @hide
     * @method autoSize
     */
    autoSize: Ext.emptyFn,

    // private
    initComponent: function(){
        Ext.ux.form.FileUploadField.superclass.initComponent.call(this);

        this.addEvents(
            /**
             * @event fileselected
             * Fires when the underlying file input field's value has changed from the user
             * selecting a new file from the system file selection dialog.
             * @param {Ext.ux.form.FileUploadField} this
             * @param {String} value The file value returned by the underlying file input field
             */
            'fileselected'
        );
    },

    // private
    onRender : function(ct, position){
        Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position);

        this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'});
        this.el.addClass('x-form-file-text');
        this.el.dom.removeAttribute('name');
        this.createFileInput();

        var btnCfg = Ext.applyIf(this.buttonCfg || {}, {
            text: this.buttonText
        });
        this.button = new Ext.Button(Ext.apply(btnCfg, {
            renderTo: this.wrap,
            cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '')
        }));

        if(this.buttonOnly){
            this.el.hide();
            this.wrap.setWidth(this.button.getEl().getWidth());
        }

        this.bindListeners();
        this.resizeEl = this.positionEl = this.wrap;
    },

    bindListeners: function(){
        this.fileInput.on({
            scope: this,
            mouseenter: function() {
                this.button.addClass(['x-btn-over','x-btn-focus'])
            },
            mouseleave: function(){
                this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
            },
            mousedown: function(){
                this.button.addClass('x-btn-click')
            },
            mouseup: function(){
                this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click'])
            },
            change: function(){
                var v = this.fileInput.dom.value;
                this.setValue(v);
                this.fireEvent('fileselected', this, v);
            }
        });
    },

    createFileInput : function() {
        this.fileInput = this.wrap.createChild({
            id: this.getFileInputId(),
            name: this.name||this.getId(),
            cls: 'x-form-file',
            tag: 'input',
            type: 'file',
            size: 1
        });
    },

    reset : function(){
        this.fileInput.remove();
        this.createFileInput();
        this.bindListeners();
        Ext.ux.form.FileUploadField.superclass.reset.call(this);
    },

    // private
    getFileInputId: function(){
        return this.id + '-file';
    },

    // private
    onResize : function(w, h){
        Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h);

        this.wrap.setWidth(w);

        if(!this.buttonOnly){
            var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset;
            this.el.setWidth(w);
        }
    },

    // private
    onDestroy: function(){
        Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);
        Ext.destroy(this.fileInput, this.button, this.wrap);
    },

    onDisable: function(){
        Ext.ux.form.FileUploadField.superclass.onDisable.call(this);
        this.doDisable(true);
    },

    onEnable: function(){
        Ext.ux.form.FileUploadField.superclass.onEnable.call(this);
        this.doDisable(false);

    },

    // private
    doDisable: function(disabled){
        this.fileInput.dom.disabled = disabled;
        this.button.setDisabled(disabled);
    },


    // private
    preFocus : Ext.emptyFn,

    // private
    alignErrorIcon : function(){
        this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
    }

});

Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField);

// backwards compat
Ext.form.FileUploadField = Ext.ux.form.FileUploadField;


Ext.ns('Ext.ux.form.HtmlEditor');
Ext.ux.form.HtmlEditor.Image = Ext.extend(Ext.util.Observable,
{
  urlSizeVars: ['width','height'],
  editor : null,
  imgBrowsers : {},
  init: function(editor){
      this.editor = editor;
      this.editor.on('render', this.onRender, this);
  },
  onRender: function() {
    var btn = this.editor.getToolbar().addButton({
        iconCls: 'x-edit-img',
        handler: this.selectImage,
        scope: this,
        disabled : true,
        tooltip: __locstring('Insert photo(s)')
    });
  },
  selectImage: function(btn) {
    this.editor = btn.scope.editor;
    if (!this.imgBrowsers[this.editor.name])
    {
      var photosurl = 'ajax/pb.getphotos.ajax';
      var albumsurl = 'ajax/pb.getalbums.ajax';
      var uploadphotosurl = 'ajax/pb.upload.ajax';
      var privacyncurl = 'ajax/pb.getprivacy.ajax';
      if (typeof(CC) != 'undefined')
      {
        var address = CC.address + "/";
        photosurl = address + photosurl;
        albumsurl = address + albumsurl;
        uploadphotosurl = address + uploadphotosurl;
        privacyncurl = address + privacyncurl;
      } else
      {
        photosurl = Grouply.sitebase + photosurl;
        albumsurl = Grouply.sitebase + albumsurl;
        uploadphotosurl = Grouply.sitebase + uploadphotosurl;
        privacyncurl = Grouply.sitebase + privacyncurl;
      }

      var cfg = {
        albumsurl:albumsurl,
        photosurl:photosurl,
        uploadphotosurl:uploadphotosurl,
        privacyncurl:privacyncurl,
        width:635,
        height:400,
        getBaseParams:Ext.emptyFn
      };

      this.imgBrowsers[this.editor.name] = new PhotoBrowser(cfg);
    }

    if (this.editor.getPhotoBrowserParams)
    {
      this.imgBrowsers[this.editor.name].cfg.getBaseParams = this.editor.getPhotoBrowserParams;
    }

    var editor = this.editor;
    this.imgBrowsers[this.editor.name].show(this.insertImage, editor);
  },
  insertImage: function(img, editor) {
    editor.insertAtCursor('<img src="'+img.data.url+'" title="'+(img.data.fname ? img.data.fname : '')+'" alt="'+(img.data.fname ? img.data.fname : '')+'" style="'+(img.data.style ? img.data.style : '')+'" /><br /><br />');
  }
});

var PhotoBrowser = function(cfg){
  this.cfg = cfg;
};

PhotoBrowser.prototype = {
  setConfig : function (cfg)
  {
    this.cfg = cfg;
    if (this.privacyStore) { this.privacyStore.url = this.cfg.privacyncurl; }
    if (this.albumsStore) { this.albumsStore.url = this.cfg.albumsurl; }
    if (this.photosStore) { this.photosStore.url = this.cfg.photosurl; }
    if (this.albumsloader) { this.albumsloader.url = this.cfg.albumsurl; }

    this.resetUpload();
    this.resetBrowser();
  },

  show : function (cb, editor)
  {
    this.editor = editor;

    if (!this.uploadWin)
    {
      this.privacyStore = new Ext.data.JsonStore({
        url : this.cfg.privacyncurl,
        fields : [
          'value', 'text'
        ]
      });
      this.privacyStore.on('beforeload', function(store,options) {
        store.baseParams = this.cfg.getBaseParams() || {};
        return true;
      }, this);

      this.albumsStore = new Ext.data.JsonStore({
        url : this.cfg.albumsurl,
        fields : [
          'id', 'text'
        ]
      });

      this.albumsStore.on('beforeload', function(store,options) {
        store.baseParams = this.cfg.getBaseParams() || {};
        return true;
      }, this);

      this.albumsStore.on('load', function (store, records) {
        for (var i in records)
        {
          if (records[i].id == 'attachments')
          {
            store.remove(records[i]);
          }
        }
        store.add(new store.recordType({id:'n',text:__locstring('New album')}, 0));
      });

      this.albumsDD = new Ext.form.ComboBox({
          fieldLabel : __locstring('Upload to'),
          autoCreate: {tag: 'input', type: 'text', size: '20', autocomplete: 'off'},
          name: 'album_name_dd',
          hiddenName : 'album_id',
          typeAhead : true,
          displayField : 'text',
          valueField : 'id',
          listClass : 'combodrop',
          store : this.albumsStore,
          emptyText : __locstring('Select an album...'), triggerAction : 'all', forceSelection : true, editable : false, width: 290, listWidth : 290,
          listeners : {
            'select' :  {
              fn : function(box, record, index) {
                var v = box.getValue();
                var hc = this.album_type_field;
                hc.setRawValue(v);
                if ('n' == v) {
                  this.newalbumsFS.show();
                } else {
                  this.newalbumsFS.hide();
                }
              },
              scope : this}
          }
        });

      this.privacyDD = new Ext.form.ComboBox({
        name : 'new_album_privacy_dd',
        hiddenName : 'new_album_privacy_nc',
        store : this.privacyStore,
        displayField : 'text',
        valueField : 'value',
        listClass : 'combodrop',
        fieldLabel : __locstring('Privacy'), triggerAction : 'all', forceSelection : true, editable : false, width: 250, listWidth : 250
      });

      this.album_type_field = new Ext.form.Hidden({
        name : 'album_type',
        value : ''
      });

      this.newalbumsFS = new Ext.form.FieldSet ({
          //checkboxToggle : {tag: 'input', type: 'checkbox', name: 'album_type', value: 'n'},
          title : __locstring('New album'),
          autoHeight : true,
          hidden : true,
          defaults : {
            width : 250
          },
          items : [{
            xtype : 'textfield',
            fieldLabel : __locstring('Name'),
            name : 'new_album_name'
          }, {
            xtype : 'textarea',
            fieldLabel : __locstring('Description'),
            name : 'new_album_description'
          }, this.privacyDD, this.album_type_field, {
            xtype : 'hidden',
            name : 'setdomain',
            value : document.domain
          }],
          listeners : {
            // 'show' :  {fn:function() { this.newalbumsFS.getComponent(1).validate(); this.albumsDD.validate(); }, scope:this}
          }
        });

      this.fileuploadspanel = new Ext.form.FormPanel({
        region : 'center',
        defaults: {
            anchor: '95%',
            msgTarget: 'side'
        },
        border : false,
        fileUpload: true,
        width: 450,
        autoHeight : true,
        labelWidth: 100,
        items: [{
          xtype: 'fileuploadfield',
          ctCls : 'macfffix',
          fieldLabel: __locstring('File'),
          allowBlank: false,
          name: 'fupl[]',
          buttonText: __locstring('Browse'),
          width : 150
        }, this.albumsDD, this.newalbumsFS],
        buttons: [{
          text : __locstring('Select an existing photo'),
          handler : this.doBrowseExisting,
          scope : this
        }, {
          text: __locstring('Upload'),
          handler: function() {
              if(this.fileuploadspanel.getForm().isValid()){
                this.fileuploadspanel.getForm().submit({
                    url: this.cfg.uploadphotosurl,
                    waitMsg: 'Uploading...',
                    success: function(form, o){
                      var photos = o.result ? o.result.photos : null;
                      if (!photos || !photos.length)
                      {
                        Grouply.fail(o.result ? o.result.error : null);
                        return;
                      }
                      for (var i=0;i<photos.length;i++) {
                        this.cb({data:photos[i]}, this.editor);
                      }
                      form.reset();
                      this.uploadWin.hide();
                  },
                  failure : function(f,o) { Grouply.fail(o.result ? o.result.error : null) },
                  scope : this
                });
              }
          },
          scope : this
        },{
            text: __locstring('Cancel'),
            handler: function(){
                this.fileuploadspanel.getForm().reset();
                this.uploadWin.hide();
            },
            scope : this
        }]
      });

      this.fileuploadspanel.getForm().on('beforeaction',
        function (form, action) {
          form.baseParams = this.cfg.getBaseParams();
        },
        this
      );



      var windowCfg = {
        title : __locstring('Insert photo(s)'),
        cls : 'uploadPhotosPopin',
        layout : 'fit',
        minHeight : 100,
        width : 450,
        modal : true,
        closeAction : 'hide',
        border : false,
        bodyStyle : 'padding:10px;',
        footerCssClass : 'x-window-footer-whitebg',
        items : [
          this.fileuploadspanel
        ],
        keys : {
          key : 27, // Esc
          handler : function() { this.uploadWin.hide(); },
          scope : this
        }
      };
      this.uploadWin = new Ext.Window(windowCfg);
    } else
    {
      this.resetUpload();
    }

    this.uploadWin.show();
    this.uploadWin.alignTo(document, 'c-c');
    this.cb = cb;
  },

  doBrowseExisting : function () {
    if (!this.win)
    {
      this.initTpl();

      this.photosStore = new Ext.data.JsonStore({
        url : this.cfg.photosurl,
        root : 'photos',
        totalProperty : 'total',
        idProperty : 'fid',
        fields : [
          'fid', 'fname', 'thumburl', 'width', 'height', 'url', 'style'
        ]
      });

      this.photosStore.on('beforeload', function(store,options) {
        store.baseParams = this.cfg.getBaseParams() || {};
        Ext.apply(store.baseParams, {folder_id:store.folder_id});
        return true;
      }, this);

      this.albumsloader = new Ext.tree.TreeLoader({
        dataUrl : this.cfg.albumsurl
      });

      this.albumsloader.on('beforeload', function(loader,node) {
        loader.baseParams = this.cfg.getBaseParams();
      }, this);

      this.albumsloader.on('load', function(loader,node) {
        node.eachChild(function(n) { n.on('click', function() { this.photosStore.folder_id = n.id; this.photosStore.load({params:{folder_id:n.id, start:0, limit:20}}); }, this); }, this);
      }, this);

      this.albumstree = new Ext.tree.TreePanel({
        cls : 'albumstree',
        animate : true,
        containerScroll : true,
        rootVisible : false,
        region : 'west',
        width : 185,
        split : true,
        title : __locstring('Select an album...'),
        autoScroll : true,
        root : {
          nodeType : 'async',
          text : 'Albums'
        },
        loadingText : __locstring('Loading...'),
        margins : '5 0 0 5',
        loader : this.albumsloader
      });

      this.photosview = new Ext.DataView({
        overClass : 'x-view-over',
        itemSelector : 'div.thumb-wrap',
        loadingText : __locstring('Loading...'),
        style : 'overflow:auto;',
        multiSelect : true,
        plugins : new Ext.DataView.DragSelector({dragSafe:true}),
        tpl : this.photosTpl,
        region : 'east',
        emptyText : '<div style="padding:10px;"><span>'+__locstring('There are no photos in this album.')+'</span></div>',
        store : this.photosStore,
        listeners : {
          'dblclick' : {fn:this.doCallback, scope:this}
        }

      });

      var windowCfg = {
        title : __locstring('Select photo(s) to insert...'),
        cls : 'selectImgPopin',
        layout : 'border',
        minWidth : 635,
        minHeight : 400,
        modal : true,
        closeAction : 'hide',
        border : false,
        footerCssClass : 'x-window-footer-whitebg',
        items : [this.albumstree, {
          cls : 'photospanel',
          title : __locstring('Photos'),
          region : 'center',
          layout : 'fit',
          margins : '5 5 0 0',
          items : this.photosview,
          bbar: new Ext.PagingToolbar({
            store: this.photosStore,
            displayInfo: true,
            pageSize: 20,
            prependButtons: true
        })
        }],
        buttons : [{
          text : __locstring('Insert'),
          handler : this.doCallback,
          scope : this
        }, {
          text : __locstring('Cancel'),
          handler : function() { this.win.hide(); },
          scope : this
        }],
        keys : {
          key : 27, // Esc
          handler : function() { this.win.hide(); },
          scope : this
        }
      };

      Ext.apply(windowCfg, this.cfg);
      this.win = new Ext.Window(windowCfg);
    } else
    {
      this.resetBrowser();
    }

    this.win.show();
    this.win.alignTo(document, 'c-c');
  },

  initTpl : function() {
    this.photosTpl = new Ext.XTemplate('<tpl for=".">',
                                      '<div class="thumb-wrap" id="{fid}">',
                                      '<div class="thumb"><img src="{thumburl}" title="{fname}"></div>',
                                      '<div class="ca-e ca-e1 ca-emax photo_name"><span>{fname}</span></div></div>',
                                      '</tpl>');
    this.photosTpl.compile();
  },

  resetUpload : function () {
    if (this.albumsStore && this.paramsChanged(this.albumsStore.baseParams))
    {
      if (this.albumsDD)
      {
        delete this.albumsDD.lastQuery;
        this.albumsStore.removeAll();
        this.albumsDD.setRawValue("");
      }
      if (this.newalbumsFS) {
        this.newalbumsFS.hide();
        this.album_type_field.setValue('');
      }
    }
  },

  resetBrowser : function() {
    // reload tree
    if (this.albumstree && this.albumstree.getLoader() && this.paramsChanged(this.albumstree.getLoader().baseParams))
    {
      if (this.photosStore)
      {
        this.photosStore.removeAll();
      }
      if (this.albumstree)
      {
        this.albumstree.getLoader().load(this.albumstree.root);
      }
      if (this.photosview)
      {
        this.photosview.getEl().update('');
      }
    }


  },

  doCallback : function() {
    var selectedPhotos = this.photosview.getSelectedRecords();
    var cb = this.cb;
    this.win.hide(this.animateTarget, function() {
      if (selectedPhotos && cb) {
        for(var i=0;i<selectedPhotos.length;i++) {
          cb(selectedPhotos[i], this.editor);
        }
      }
    }, this);

    if (this.uploadWin) { this.uploadWin.hide(); }
  },

  paramsChanged : function (baseParams)
  {
    var newParams = this.cfg.getBaseParams();

    if (newParams && baseParams && newParams.group_id == baseParams.group_id)
    {
      return false;
    }

    return true;
  }


};


// #8100, also see http://www.sencha.com/forum/archive/index.php/t-70942.html
Ext.override(Ext.form.HtmlEditor, {
insertAtCursor : function(text){
if(!this.activated){
return;
}
if(Ext.isIE){
this.win.focus();
var r = this.doc.selection.createRange();
if(r){
r.collapse(true);
r.pasteHTML(text);
this.syncValue();
this.deferFocus();
}
}else{
this.win.focus();
this.execCmd('InsertHTML', text);
this.deferFocus();
}
}
});
