* @cfg {String} icon (info-sign|check|...) glyphicon name
* @cfg {Boolean} hidden (true|false) hide the element
* @cfg {Boolean} expandable (true|false) default false
+ * @cfg {Boolean} expanded (true|false) default true
* @cfg {String} rheader contet on the right of header
*
h.push({
tag: 'i',
- cls: 'fa fa-minus'
+ cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
});
+
}
h.push(
{
tag: 'span',
cls : 'panel-title',
- html : this.header
+ html : (this.expandable ? ' ' : '') + this.header
},
{
tag: 'span',
cfg.cn.push({
cls : 'panel-heading',
+ style : this.expandable ? 'cursor: pointer' : '',
cn : h
});
body = false;
cfg.cn.push({
- cls : 'panel-body',
+ cls : 'panel-body' + (this.expanded ? '' : ' hide'),
html : this.html
});
this.expanded = true;
- this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
-
+ //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
+
+ this.el.select('.panel-body',true).first().removeClass('hide');
+
var toggleEl = this.toggleEl();
if(!toggleEl){
this.expanded = false;
- this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
+ //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
+ this.el.select('.panel-body',true).first().addClass('hide');
var toggleEl = this.toggleEl();
var s = ['xs', 'sm', 'md', 'lg'];
- Roo.eac(ss.splice(ss.indexOf(size), 1), function(ss){
+ s.splice(s.indexOf(size), 1);
+
+ Roo.each(s, function(ss){
img.cls += ' hidden-' + ss;
});
if (this.buttons.length) {
Roo.each(this.buttons, function(bb) {
- b = Roo.apply({}, bb);
+ var b = Roo.apply({}, bb);
b.xns = b.xns || Roo.bootstrap;
b.xtype = b.xtype || 'Button';
if (typeof(b.listeners) == 'undefined') {
//this.el.addClass([this.fieldClass, this.cls]);
},
+
getAutoCreate : function(){
if (this.allow_close) {
this.closeEl.on('click', this.hide, this);
}
+
+ var _this = this;
+
+ window.addEventListener("resize", function() { _this.resize(); } );
},
+
+ resize : function()
+ {
+ this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
+ },
+
show : function() {
if (!this.rendered) {
},
setActive : function(state, fire, is_was_active)
{
- if (this.active && !state & this.navId) {
+ if (this.active && !state && this.navId) {
this.was_active = true;
var nv = Roo.bootstrap.NavGroup.get(this.navId);
if (nv) {
* @cfg {boolean} condensed Format condensed
* @cfg {boolean} responsive Format condensed
* @cfg {Boolean} loadMask (true|false) default false
- * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
- * @cfg {Boolean} thead (true|false) generate thead, default true
- * @cfg {Boolean} RowSelection (true|false) default false
- * @cfg {Boolean} CellSelection (true|false) default false
+ * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
+ * @cfg {Boolean} headerShow (true|false) generate thead, default true
+ * @cfg {Boolean} rowSelection (true|false) default false
+ * @cfg {Boolean} cellSelection (true|false) default false
* @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
*
Roo.bootstrap.Table = function(config){
Roo.bootstrap.Table.superclass.constructor.call(this, config);
+ // BC...
+ this.rowSelection = (typeof(config.RowSelection) != 'undefined') ? config.RowSelection : this.rowSelection;
+ this.cellSelection = (typeof(config.CellSelection) != 'undefined') ? config.CellSelection : this.cellSelection;
+ this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
+ this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
+
+
if (this.sm) {
this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
this.sm = this.selModel;
cm : false,
store : false,
loadMask : false,
- tfoot : true,
- thead : true,
- RowSelection : false,
- CellSelection : false,
+ footerShow : true,
+ headerShow : true,
+
+ rowSelection : false,
+ cellSelection : false,
layout : false,
// Roo.Element - the tbody
}
if(this.store || this.cm){
- if(this.thead){
+ if(this.headerShow){
cfg.cn.push(this.renderHeader());
}
cfg.cn.push(this.renderBody());
- if(this.tfoot){
+ if(this.footerShow){
cfg.cn.push(this.renderFooter());
}
{
var cell = Roo.get(el);
- if(!cell || (!this.CellSelection && !this.RowSelection)){
+ if(!cell || (!this.cellSelection && !this.rowSelection)){
return;
}
var cellIndex = cell.dom.cellIndex;
var rowIndex = this.getRowIndex(row);
- if(this.CellSelection){
+ // why??? - should these not be based on SelectionModel?
+ if(this.cellSelection){
this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
}
- if(this.RowSelection){
+ if(this.rowSelection){
this.fireEvent('rowclick', this, row, rowIndex, e);
}
for(var i = 0, len = cm.getColumnCount(); i < len; i++){
var config = cm.config[i];
-
+
var c = {
tag: 'th',
style : '',
html: cm.getColumnHeader(i)
};
+ var hh = '';
+
+ if(typeof(config.lgHeader) != 'undefined'){
+ hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
+ }
+
+ if(typeof(config.mdHeader) != 'undefined'){
+ hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
+ }
+
+ if(typeof(config.smHeader) != 'undefined'){
+ hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
+ }
+
+ if(typeof(config.xsHeader) != 'undefined'){
+ hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
+ }
+
+ if(hh.length){
+ c.html = hh;
+ }
+
if(typeof(config.tooltip) != 'undefined'){
c.tooltip = config.tooltip;
}
* @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
* @cfg {String} align (left|center|right) Default left
+ * @cfg {Boolean} forceFeedback (true|false) Default false
+ *
*
*
*
readOnly : false,
align : false,
formatedValue : false,
+ forceFeedback : false,
parentLabelAlign : function()
{
this.inputEl().on("blur", this.onBlur, this);
this.inputEl().relayEvent('keyup', this);
-
+
// reference to original value for reset
this.originalValue = this.getValue();
//Roo.form.TextField.superclass.initEvents.call(this);
this.el.removeClass([this.invalidClass, this.validClass]);
+ var feedback = this.el.select('.form-control-feedback', true).first();
+
+ if(feedback){
+ this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+ }
+
if(this.disabled || this.allowBlank){
return;
}
this.el.addClass(this.validClass);
- if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
+ if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
var feedback = this.el.select('.form-control-feedback', true).first();
this.el.removeClass([this.invalidClass, this.validClass]);
+ var feedback = this.el.select('.form-control-feedback', true).first();
+
+ if(feedback){
+ this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+ }
+
if(this.disabled || this.allowBlank){
return;
}
if(feedback){
this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
- if(this.getValue().length){
+ if(this.getValue().length || this.forceFeedback){
this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
}
]
};
}
-
+
} else {
if(this.removable && !this.editable && !this.tickable){
inputblock = {
cfg.cls += ' col-' + size + '-' + settings[size];
}
});
-
+ Roo.log(cfg);
return cfg;
},
var close = this.closeTriggerEl();
if(close){
- close.setVisibilityMode(Roo.Element.DISPALY).hide();
+ close.setVisibilityMode(Roo.Element.DISPLAY).hide();
close.on('click', this.removeBtnClick, this, close);
}
}
{
e.preventDefault();
- this.fireEvent("remove", this);
+ if(this.fireEvent("remove", this) !== false){
+ this.reset();
+ }
},
createList : function()
* @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
* @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
* @cfg {String} btnPosition set the position of the trigger button (left | right) default right
+ * @cfg {Boolean} animate default true
+ * @cfg {Boolean} emptyResultText only for touch device
* @constructor
* Create a new ComboBox.
* @param {Object} config Configuration options
*/
specialFilter : false,
+ /**
+ * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
+ */
+ mobileTouchView : true,
+
//private
addicon : false,
editicon: false,
btnPosition : 'right',
triggerList : true,
showToggleBtn : true,
+ animate : true,
+ emptyResultText: 'Empty',
// element that contains real text value.. (when hidden is used..)
getAutoCreate : function()
{
var cfg = false;
+ /*
+ * Touch Devices
+ */
+
+ if(Roo.isTouch && this.mobileTouchView){
+ cfg = this.getAutoCreateTouchView();
+ return cfg;;
+ }
+
/*
* Normal ComboBox
*/
if (!this.store) {
throw "can not find store for combo";
}
+
this.store = Roo.factory(this.store, Roo.data);
+ /*
+ * Touch Devices
+ */
+
+ if(Roo.isTouch && this.mobileTouchView){
+ this.initTouchView();
+ return;
+ }
+
if(this.tickable){
this.initTickableEvents();
return;
var close = this.closeTriggerEl();
if(close){
- (v.length || v * 1 > 0) ? close.show() : close.hide();
+ (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
}
},
/**
this.syncValue();
this.validate();
+
+ if(this.tickable && !Roo.isTouch){
+ this.view.refresh();
+ }
},
inputEl: function ()
{
+ if(Roo.isTouch && this.mobileTouchView){
+ return this.el.select('input.form-control',true).first();
+ }
+
if(this.tickable){
return this.searchField;
}
+
return this.el.select('input.form-control',true).first();
},
}
return this.inputEl().select('.select2-search-field-input', true).first();
- }
+ },
+ getAutoCreateTouchView : function()
+ {
+ var id = Roo.id();
+
+ var cfg = {
+ cls: 'form-group' //input-group
+ };
+
+ var input = {
+ tag: 'input',
+ id : id,
+ type : this.inputType,
+ cls : 'form-control x-combo-noedit',
+ autocomplete: 'new-password',
+ placeholder : this.placeholder || '',
+ readonly : true
+ };
+
+ if (this.name) {
+ input.name = this.name;
+ }
+
+ if (this.size) {
+ input.cls += ' input-' + this.size;
+ }
+
+ if (this.disabled) {
+ input.disabled = true;
+ }
+
+ var inputblock = {
+ cls : '',
+ cn : [
+ input
+ ]
+ };
+
+ if(this.before){
+ inputblock.cls += ' input-group';
+
+ inputblock.cn.unshift({
+ tag :'span',
+ cls : 'input-group-addon',
+ html : this.before
+ });
+ }
+
+ if(this.removable && !this.multiple){
+ inputblock.cls += ' roo-removable';
+
+ inputblock.cn.push({
+ tag: 'button',
+ html : 'x',
+ cls : 'roo-combo-removable-btn close'
+ });
+ }
- /**
- * @cfg {Boolean} grow
- * @hide
- */
- /**
- * @cfg {Number} growMin
- * @hide
- */
- /**
- * @cfg {Number} growMax
- * @hide
- */
- /**
- * @hide
- * @method autoSize
- */
-});
-/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
-
-/**
- * @class Roo.View
- * @extends Roo.util.Observable
- * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
- * This class also supports single and multi selection modes. <br>
- * Create a data model bound view:
- <pre><code>
- var store = new Roo.data.Store(...);
+ if(this.hasFeedback && !this.allowBlank){
+
+ inputblock.cls += ' has-feedback';
+
+ inputblock.cn.push({
+ tag: 'span',
+ cls: 'glyphicon form-control-feedback'
+ });
+
+ }
+
+ if (this.after) {
+
+ inputblock.cls += (this.before) ? '' : ' input-group';
+
+ inputblock.cn.push({
+ tag :'span',
+ cls : 'input-group-addon',
+ html : this.after
+ });
+ }
- var view = new Roo.View({
- el : "my-element",
- tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
-
- singleSelect: true,
- selectedClass: "ydataview-selected",
- store: store
- });
+ var box = {
+ tag: 'div',
+ cn: [
+ {
+ tag: 'input',
+ type : 'hidden',
+ cls: 'form-hidden-field'
+ },
+ inputblock
+ ]
+
+ };
+
+ if(this.multiple){
+ box = {
+ tag: 'div',
+ cn: [
+ {
+ tag: 'input',
+ type : 'hidden',
+ cls: 'form-hidden-field'
+ },
+ {
+ tag: 'ul',
+ cls: 'select2-choices',
+ cn:[
+ {
+ tag: 'li',
+ cls: 'select2-search-field',
+ cn: [
- // listen for node click?
- view.on("click", function(vw, index, node, e){
- alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
- });
+ inputblock
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ };
+
+ var combobox = {
+ cls: 'select2-container input-group',
+ cn: [
+ box
+ ]
+ };
+
+ if(this.multiple){
+ combobox.cls += ' select2-container-multi';
+ }
+
+ var align = this.labelAlign || this.parentLabelAlign();
+
+ cfg.cn = combobox;
+
+ if(this.fieldLabel.length){
+
+ var lw = align === 'left' ? ('col-sm' + this.labelWidth) : '';
+ var cw = align === 'left' ? ('col-sm' + (12 - this.labelWidth)) : '';
+
+ cfg.cn = [
+ {
+ tag: 'label',
+ cls : 'control-label ' + lw,
+ html : this.fieldLabel
- // load XML data
- dataModel.load("foobar.xml");
- </code></pre>
- For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
- * <br><br>
- * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
- * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
- *
- * Note: old style constructor is still suported (container, template, config)
- *
- * @constructor
- * Create a new View
- * @param {Object} config The config object
- *
- */
-Roo.View = function(config, depreciated_tpl, depreciated_config){
-
- this.parent = false;
-
- if (typeof(depreciated_tpl) == 'undefined') {
- // new way.. - universal constructor.
- Roo.apply(this, config);
- this.el = Roo.get(this.el);
- } else {
- // old format..
- this.el = Roo.get(config);
- this.tpl = depreciated_tpl;
- Roo.apply(this, depreciated_config);
- }
- this.wrapEl = this.el.wrap().wrap();
- ///this.el = this.wrapEla.appendChild(document.createElement("div"));
-
-
- if(typeof(this.tpl) == "string"){
- this.tpl = new Roo.Template(this.tpl);
- } else {
- // support xtype ctors..
- this.tpl = new Roo.factory(this.tpl, Roo);
- }
-
+ },
+ {
+ cls : cw,
+ cn: [
+ combobox
+ ]
+ }
+ ];
+ }
+
+ var settings = this;
+
+ ['xs','sm','md','lg'].map(function(size){
+ if (settings[size]) {
+ cfg.cls += ' col-' + size + '-' + settings[size];
+ }
+ });
+
+ return cfg;
+ },
- this.tpl.compile();
+ initTouchView : function()
+ {
+ this.renderTouchView();
+
+ this.touchViewEl.on('scroll', function(){
+ this.el.dom.scrollTop = 0;
+ }, this);
+
+ this.inputEl().on("click", this.showTouchView, this);
+ this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
+ this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
+
+ this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
+
+ this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
+ this.store.on('load', this.onTouchViewLoad, this);
+ this.store.on('loadexception', this.onTouchViewLoadException, this);
+
+ if(this.hiddenName){
+
+ this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+
+ this.hiddenField.dom.value =
+ this.hiddenValue !== undefined ? this.hiddenValue :
+ this.value !== undefined ? this.value : '';
+
+ this.el.dom.removeAttribute('name');
+ this.hiddenField.dom.setAttribute('name', this.hiddenName);
+ }
+
+ if(this.multiple){
+ this.choices = this.el.select('ul.select2-choices', true).first();
+ this.searchField = this.el.select('ul li.select2-search-field', true).first();
+ }
+
+ if(this.removable && !this.multiple){
+ var close = this.closeTriggerEl();
+ if(close){
+ close.setVisibilityMode(Roo.Element.DISPLAY).hide();
+ close.on('click', this.removeBtnClick, this, close);
+ }
+ }
+
+ return;
+
+
+ },
- /** @private */
- this.addEvents({
- /**
- * @event beforeclick
- * Fires before a click is processed. Returns false to cancel the default action.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "beforeclick" : true,
- /**
- * @event click
- * Fires when a template node is clicked.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "click" : true,
- /**
- * @event dblclick
- * Fires when a template node is double clicked.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "dblclick" : true,
- /**
- * @event contextmenu
- * Fires when a template node is right clicked.
- * @param {Roo.View} this
- * @param {Number} index The index of the target node
- * @param {HTMLElement} node The target node
- * @param {Roo.EventObject} e The raw event object
- */
- "contextmenu" : true,
- /**
- * @event selectionchange
- * Fires when the selected nodes change.
- * @param {Roo.View} this
- * @param {Array} selections Array of the selected nodes
- */
- "selectionchange" : true,
+ renderTouchView : function()
+ {
+ this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
+ this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
+ this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
+ this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ this.touchViewBodyEl.setStyle('overflow', 'auto');
+
+ this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
+ this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
+ this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ },
- /**
- * @event beforeselect
- * Fires before a selection is made. If any handlers return false, the selection is cancelled.
- * @param {Roo.View} this
- * @param {HTMLElement} node The node to be selected
- * @param {Array} selections Array of currently selected nodes
- */
- "beforeselect" : true,
- /**
- * @event preparedata
- * Fires on every row to render, to allow you to change the data.
- * @param {Roo.View} this
- * @param {Object} data to be rendered (change this)
- */
- "preparedata" : true
-
-
- });
+ showTouchView : function()
+ {
+ this.touchViewHeaderEl.hide();
+ if(this.fieldLabel.length){
+ this.touchViewHeaderEl.dom.innerHTML = this.fieldLabel;
+ this.touchViewHeaderEl.show();
+ }
+ this.touchViewEl.show();
- this.el.on({
- "click": this.onClick,
- "dblclick": this.onDblClick,
- "contextmenu": this.onContextMenu,
- scope:this
- });
+ this.touchViewEl.select('.modal-dialog', true).first().setStyle('margin', '0px');
+ this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
- this.selections = [];
- this.nodes = [];
- this.cmp = new Roo.CompositeElementLite([]);
- if(this.store){
- this.store = Roo.factory(this.store, Roo.data);
- this.setStore(this.store, true);
- }
-
- if ( this.footer && this.footer.xtype) {
-
- var fctr = this.wrapEl.appendChild(document.createElement("div"));
+ var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
+
+ if(this.fieldLabel.length){
+ bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
+ }
- this.footer.dataSource = this.store
- this.footer.container = fctr;
- this.footer = Roo.factory(this.footer, Roo);
- fctr.insertFirst(this.el);
+ this.touchViewBodyEl.setHeight(bodyHeight);
+
+ if(this.animate){
+ var _this = this;
+ (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
+ }else{
+ this.touchViewEl.addClass('in');
+ }
+
+ this.doTouchViewQuery();
- // this is a bit insane - as the paging toolbar seems to detach the el..
-// dom.parentNode.parentNode.parentNode
- // they get detached?
- }
+ },
+ hideTouchView : function()
+ {
+ this.touchViewEl.removeClass('in');
+
+ if(this.animate){
+ var _this = this;
+ (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
+ }else{
+ this.touchViewEl.setStyle('display', 'none');
+ }
+
+ },
- Roo.View.superclass.constructor.call(this);
+ setTouchViewValue : function()
+ {
+ if(this.multiple){
+ this.clearItem();
+
+ var _this = this;
+
+ Roo.each(this.tickItems, function(o){
+ this.addItem(o);
+ }, this);
+ }
+
+ this.hideTouchView();
+ },
+ doTouchViewQuery : function()
+ {
+ var qe = {
+ query: '',
+ forceAll: true,
+ combo: this,
+ cancel:false
+ };
+
+ if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
+ return false;
+ }
+
+ if(!this.alwaysQuery || this.mode == 'local'){
+ this.onTouchViewLoad();
+ return;
+ }
+
+ this.store.load();
+ },
-};
+ onTouchViewBeforeLoad : function(combo,opts)
+ {
+ return;
+ },
-Roo.extend(Roo.View, Roo.util.Observable, {
+ // private
+ onTouchViewLoad : function()
+ {
+ if(this.store.getCount() < 1){
+ this.onTouchViewEmptyResults();
+ return;
+ }
+
+ this.clearTouchView();
+
+ var rawValue = this.getRawValue();
+
+ var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
+
+ this.tickItems = [];
+
+ this.store.data.each(function(d, rowIndex){
+ var row = this.touchViewListGroup.createChild(template);
+
+ if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
+ row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = d.data[this.displayField];
+ }
+
+ if(!this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue()){
+ row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+ }
+
+ if(this.multiple && this.valueField && typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1){
+ row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+ this.tickItems.push(d.data);
+ }
+
+ row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
+
+ }, this);
+
+ var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
+
+ var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
+
+ if(this.fieldLabel.length){
+ bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
+ }
+
+ var listHeight = this.touchViewListGroup.getHeight();
+
+ var _this = this;
+
+ if(firstChecked && listHeight > bodyHeight){
+ (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
+ }
+
+ },
- /**
- * @cfg {Roo.data.Store} store Data store to load data from.
- */
- store : false,
+ onTouchViewLoadException : function()
+ {
+ this.hideTouchView();
+ },
- /**
- * @cfg {String|Roo.Element} el The container element.
- */
- el : '',
+ onTouchViewEmptyResults : function()
+ {
+ this.clearTouchView();
+
+ this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
+
+ this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
+
+ },
- /**
- * @cfg {String|Roo.Template} tpl The template used by this View
- */
- tpl : false,
- /**
- * @cfg {String} dataName the named area of the template to use as the data area
- * Works with domtemplates roo-name="name"
- */
- dataName: false,
- /**
- * @cfg {String} selectedClass The css class to add to selected nodes
- */
- selectedClass : "x-view-selected",
- /**
- * @cfg {String} emptyText The empty text to show when nothing is loaded.
- */
- emptyText : "",
-
- /**
- * @cfg {String} text to display on mask (default Loading)
- */
- mask : false,
- /**
- * @cfg {Boolean} multiSelect Allow multiple selection
- */
- multiSelect : false,
- /**
- * @cfg {Boolean} singleSelect Allow single selection
- */
- singleSelect: false,
-
- /**
- * @cfg {Boolean} toggleSelect - selecting
- */
- toggleSelect : false,
-
- /**
- * @cfg {Boolean} tickable - selecting
- */
- tickable : false,
-
- /**
- * Returns the element this view is bound to.
- * @return {Roo.Element}
- */
- getEl : function(){
- return this.wrapEl;
+ clearTouchView : function()
+ {
+ this.touchViewListGroup.dom.innerHTML = '';
},
-
-
- /**
- * Refreshes the view. - called by datachanged on the store. - do not call directly.
- */
- refresh : function(){
- //Roo.log('refresh');
- var t = this.tpl;
-
- // if we are using something like 'domtemplate', then
- // the what gets used is:
- // t.applySubtemplate(NAME, data, wrapping data..)
- // the outer template then get' applied with
- // the store 'extra data'
- // and the body get's added to the
- // roo-name="data" node?
- // <span class='roo-tpl-{name}'></span> ?????
+ onTouchViewClick : function(e, el, o)
+ {
+ e.preventDefault();
+ var row = o.row;
+ var rowIndex = o.rowIndex;
+ var r = this.store.getAt(rowIndex);
- this.clearSelections();
- this.el.update("");
- var html = [];
- var records = this.store.getRange();
- if(records.length < 1) {
-
- // is this valid?? = should it render a template??
+ if(!this.multiple){
+ Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
+ c.dom.removeAttribute('checked');
+ }, this);
- this.el.update(this.emptyText);
- return;
- }
- var el = this.el;
- if (this.dataName) {
- this.el.update(t.apply(this.store.meta)); //????
- el = this.el.child('.roo-tpl-' + this.dataName);
- }
+ row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
- for(var i = 0, len = records.length; i < len; i++){
- var data = this.prepareData(records[i].data, i, records[i]);
- this.fireEvent("preparedata", this, data, i, records[i]);
-
- var d = Roo.apply({}, data);
-
- if(this.tickable){
- Roo.apply(d, {'roo-id' : Roo.id()});
-
- var _this = this;
+ this.setFromData(r.data);
- Roo.each(this.parent.item, function(item){
- if(item[_this.parent.valueField] != data[_this.parent.valueField]){
- return;
- }
- Roo.apply(d, {'roo-data-checked' : 'checked'});
- });
+ var close = this.closeTriggerEl();
+
+ if(close){
+ close.show();
}
+
+ this.hideTouchView();
- html[html.length] = Roo.util.Format.trim(
- this.dataName ?
- t.applySubtemplate(this.dataName, d, this.store.meta) :
- t.apply(d)
- );
+ this.fireEvent('select', this, r, rowIndex);
+
+ return;
}
+ if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
+ row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
+ this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
+ return;
+ }
+ row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+ this.addItem(r.data);
+ this.tickItems.push(r.data);
- el.update(html.join(""));
- this.nodes = el.dom.childNodes;
- this.updateIndexes(0);
- },
+ }
+ /**
+ * @cfg {Boolean} grow
+ * @hide
+ */
+ /**
+ * @cfg {Number} growMin
+ * @hide
+ */
+ /**
+ * @cfg {Number} growMax
+ * @hide
+ */
/**
- * Function to override to reformat the data that is sent to
- * the template for each node.
- * DEPRICATED - use the preparedata event handler.
- * @param {Array/Object} data The raw data (array of colData for a data model bound view or
- * a JSON object for an UpdateManager bound view).
+ * @hide
+ * @method autoSize
*/
- prepareData : function(data, index, record)
- {
- this.fireEvent("preparedata", this, data, index, record);
- return data;
- },
+});
- onUpdate : function(ds, record){
- // Roo.log('on update');
- this.clearSelections();
- var index = this.store.indexOf(record);
- var n = this.nodes[index];
- this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
- n.parentNode.removeChild(n);
- this.updateIndexes(index, index);
+Roo.apply(Roo.bootstrap.ComboBox, {
+
+ header : {
+ tag: 'div',
+ cls: 'modal-header',
+ cn: [
+ {
+ tag: 'h4',
+ cls: 'modal-title'
+ }
+ ]
},
-
+ body : {
+ tag: 'div',
+ cls: 'modal-body',
+ cn: [
+ {
+ tag: 'ul',
+ cls: 'list-group'
+ }
+ ]
+ },
-// --------- FIXME
- onAdd : function(ds, records, index)
- {
- //Roo.log(['on Add', ds, records, index] );
- this.clearSelections();
- if(this.nodes.length == 0){
- this.refresh();
- return;
- }
- var n = this.nodes[index];
- for(var i = 0, len = records.length; i < len; i++){
- var d = this.prepareData(records[i].data, i, records[i]);
- if(n){
- this.tpl.insertBefore(n, d);
- }else{
-
- this.tpl.append(this.el, d);
+ listItemRadio : {
+ tag: 'li',
+ cls: 'list-group-item',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'roo-combobox-list-group-item-value'
+ },
+ {
+ tag: 'div',
+ cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
+ cn: [
+ {
+ tag: 'input',
+ type: 'radio'
+ },
+ {
+ tag: 'label'
+ }
+ ]
}
- }
- this.updateIndexes(index);
+ ]
},
-
- onRemove : function(ds, record, index){
- // Roo.log('onRemove');
- this.clearSelections();
- var el = this.dataName ?
- this.el.child('.roo-tpl-' + this.dataName) :
- this.el;
-
- el.dom.removeChild(this.nodes[index]);
- this.updateIndexes(index);
+
+ listItemCheckbox : {
+ tag: 'li',
+ cls: 'list-group-item',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'roo-combobox-list-group-item-value'
+ },
+ {
+ tag: 'div',
+ cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
+ cn: [
+ {
+ tag: 'input',
+ type: 'checkbox'
+ },
+ {
+ tag: 'label'
+ }
+ ]
+ }
+ ]
},
-
- /**
- * Refresh an individual node.
- * @param {Number} index
- */
- refreshNode : function(index){
- this.onUpdate(this.store, this.store.getAt(index));
+
+ emptyResult : {
+ tag: 'div',
+ cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
},
+
+ footer : {
+ tag: 'div',
+ cls: 'modal-footer',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'row',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'col-xs-6 text-left',
+ cn: {
+ tag: 'button',
+ cls: 'btn btn-danger roo-touch-view-cancel',
+ html: 'Cancel'
+ }
+ },
+ {
+ tag: 'div',
+ cls: 'col-xs-6 text-right',
+ cn: {
+ tag: 'button',
+ cls: 'btn btn-success roo-touch-view-ok',
+ html: 'OK'
+ }
+ }
+ ]
+ }
+ ]
+
+ }
+});
- updateIndexes : function(startIndex, endIndex){
- var ns = this.nodes;
- startIndex = startIndex || 0;
- endIndex = endIndex || ns.length - 1;
- for(var i = startIndex; i <= endIndex; i++){
+Roo.apply(Roo.bootstrap.ComboBox, {
+
+ touchViewTemplate : {
+ tag: 'div',
+ cls: 'modal fade roo-combobox-touch-view',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'modal-dialog',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'modal-content',
+ cn: [
+ Roo.bootstrap.ComboBox.header,
+ Roo.bootstrap.ComboBox.body,
+ Roo.bootstrap.ComboBox.footer
+ ]
+ }
+ ]
+ }
+ ]
+ }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.View
+ * @extends Roo.util.Observable
+ * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
+ * This class also supports single and multi selection modes. <br>
+ * Create a data model bound view:
+ <pre><code>
+ var store = new Roo.data.Store(...);
+
+ var view = new Roo.View({
+ el : "my-element",
+ tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
+
+ singleSelect: true,
+ selectedClass: "ydataview-selected",
+ store: store
+ });
+
+ // listen for node click?
+ view.on("click", function(vw, index, node, e){
+ alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
+ });
+
+ // load XML data
+ dataModel.load("foobar.xml");
+ </code></pre>
+ For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
+ * <br><br>
+ * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
+ * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
+ *
+ * Note: old style constructor is still suported (container, template, config)
+ *
+ * @constructor
+ * Create a new View
+ * @param {Object} config The config object
+ *
+ */
+Roo.View = function(config, depreciated_tpl, depreciated_config){
+
+ this.parent = false;
+
+ if (typeof(depreciated_tpl) == 'undefined') {
+ // new way.. - universal constructor.
+ Roo.apply(this, config);
+ this.el = Roo.get(this.el);
+ } else {
+ // old format..
+ this.el = Roo.get(config);
+ this.tpl = depreciated_tpl;
+ Roo.apply(this, depreciated_config);
+ }
+ this.wrapEl = this.el.wrap().wrap();
+ ///this.el = this.wrapEla.appendChild(document.createElement("div"));
+
+
+ if(typeof(this.tpl) == "string"){
+ this.tpl = new Roo.Template(this.tpl);
+ } else {
+ // support xtype ctors..
+ this.tpl = new Roo.factory(this.tpl, Roo);
+ }
+
+
+ this.tpl.compile();
+
+ /** @private */
+ this.addEvents({
+ /**
+ * @event beforeclick
+ * Fires before a click is processed. Returns false to cancel the default action.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "beforeclick" : true,
+ /**
+ * @event click
+ * Fires when a template node is clicked.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "click" : true,
+ /**
+ * @event dblclick
+ * Fires when a template node is double clicked.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "dblclick" : true,
+ /**
+ * @event contextmenu
+ * Fires when a template node is right clicked.
+ * @param {Roo.View} this
+ * @param {Number} index The index of the target node
+ * @param {HTMLElement} node The target node
+ * @param {Roo.EventObject} e The raw event object
+ */
+ "contextmenu" : true,
+ /**
+ * @event selectionchange
+ * Fires when the selected nodes change.
+ * @param {Roo.View} this
+ * @param {Array} selections Array of the selected nodes
+ */
+ "selectionchange" : true,
+
+ /**
+ * @event beforeselect
+ * Fires before a selection is made. If any handlers return false, the selection is cancelled.
+ * @param {Roo.View} this
+ * @param {HTMLElement} node The node to be selected
+ * @param {Array} selections Array of currently selected nodes
+ */
+ "beforeselect" : true,
+ /**
+ * @event preparedata
+ * Fires on every row to render, to allow you to change the data.
+ * @param {Roo.View} this
+ * @param {Object} data to be rendered (change this)
+ */
+ "preparedata" : true
+
+
+ });
+
+
+
+ this.el.on({
+ "click": this.onClick,
+ "dblclick": this.onDblClick,
+ "contextmenu": this.onContextMenu,
+ scope:this
+ });
+
+ this.selections = [];
+ this.nodes = [];
+ this.cmp = new Roo.CompositeElementLite([]);
+ if(this.store){
+ this.store = Roo.factory(this.store, Roo.data);
+ this.setStore(this.store, true);
+ }
+
+ if ( this.footer && this.footer.xtype) {
+
+ var fctr = this.wrapEl.appendChild(document.createElement("div"));
+
+ this.footer.dataSource = this.store
+ this.footer.container = fctr;
+ this.footer = Roo.factory(this.footer, Roo);
+ fctr.insertFirst(this.el);
+
+ // this is a bit insane - as the paging toolbar seems to detach the el..
+// dom.parentNode.parentNode.parentNode
+ // they get detached?
+ }
+
+
+ Roo.View.superclass.constructor.call(this);
+
+
+};
+
+Roo.extend(Roo.View, Roo.util.Observable, {
+
+ /**
+ * @cfg {Roo.data.Store} store Data store to load data from.
+ */
+ store : false,
+
+ /**
+ * @cfg {String|Roo.Element} el The container element.
+ */
+ el : '',
+
+ /**
+ * @cfg {String|Roo.Template} tpl The template used by this View
+ */
+ tpl : false,
+ /**
+ * @cfg {String} dataName the named area of the template to use as the data area
+ * Works with domtemplates roo-name="name"
+ */
+ dataName: false,
+ /**
+ * @cfg {String} selectedClass The css class to add to selected nodes
+ */
+ selectedClass : "x-view-selected",
+ /**
+ * @cfg {String} emptyText The empty text to show when nothing is loaded.
+ */
+ emptyText : "",
+
+ /**
+ * @cfg {String} text to display on mask (default Loading)
+ */
+ mask : false,
+ /**
+ * @cfg {Boolean} multiSelect Allow multiple selection
+ */
+ multiSelect : false,
+ /**
+ * @cfg {Boolean} singleSelect Allow single selection
+ */
+ singleSelect: false,
+
+ /**
+ * @cfg {Boolean} toggleSelect - selecting
+ */
+ toggleSelect : false,
+
+ /**
+ * @cfg {Boolean} tickable - selecting
+ */
+ tickable : false,
+
+ /**
+ * Returns the element this view is bound to.
+ * @return {Roo.Element}
+ */
+ getEl : function(){
+ return this.wrapEl;
+ },
+
+
+
+ /**
+ * Refreshes the view. - called by datachanged on the store. - do not call directly.
+ */
+ refresh : function(){
+ //Roo.log('refresh');
+ var t = this.tpl;
+
+ // if we are using something like 'domtemplate', then
+ // the what gets used is:
+ // t.applySubtemplate(NAME, data, wrapping data..)
+ // the outer template then get' applied with
+ // the store 'extra data'
+ // and the body get's added to the
+ // roo-name="data" node?
+ // <span class='roo-tpl-{name}'></span> ?????
+
+
+
+ this.clearSelections();
+ this.el.update("");
+ var html = [];
+ var records = this.store.getRange();
+ if(records.length < 1) {
+
+ // is this valid?? = should it render a template??
+
+ this.el.update(this.emptyText);
+ return;
+ }
+ var el = this.el;
+ if (this.dataName) {
+ this.el.update(t.apply(this.store.meta)); //????
+ el = this.el.child('.roo-tpl-' + this.dataName);
+ }
+
+ for(var i = 0, len = records.length; i < len; i++){
+ var data = this.prepareData(records[i].data, i, records[i]);
+ this.fireEvent("preparedata", this, data, i, records[i]);
+
+ var d = Roo.apply({}, data);
+
+ if(this.tickable){
+ Roo.apply(d, {'roo-id' : Roo.id()});
+
+ var _this = this;
+
+ Roo.each(this.parent.item, function(item){
+ if(item[_this.parent.valueField] != data[_this.parent.valueField]){
+ return;
+ }
+ Roo.apply(d, {'roo-data-checked' : 'checked'});
+ });
+ }
+
+ html[html.length] = Roo.util.Format.trim(
+ this.dataName ?
+ t.applySubtemplate(this.dataName, d, this.store.meta) :
+ t.apply(d)
+ );
+ }
+
+
+
+ el.update(html.join(""));
+ this.nodes = el.dom.childNodes;
+ this.updateIndexes(0);
+ },
+
+
+ /**
+ * Function to override to reformat the data that is sent to
+ * the template for each node.
+ * DEPRICATED - use the preparedata event handler.
+ * @param {Array/Object} data The raw data (array of colData for a data model bound view or
+ * a JSON object for an UpdateManager bound view).
+ */
+ prepareData : function(data, index, record)
+ {
+ this.fireEvent("preparedata", this, data, index, record);
+ return data;
+ },
+
+ onUpdate : function(ds, record){
+ // Roo.log('on update');
+ this.clearSelections();
+ var index = this.store.indexOf(record);
+ var n = this.nodes[index];
+ this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
+ n.parentNode.removeChild(n);
+ this.updateIndexes(index, index);
+ },
+
+
+
+// --------- FIXME
+ onAdd : function(ds, records, index)
+ {
+ //Roo.log(['on Add', ds, records, index] );
+ this.clearSelections();
+ if(this.nodes.length == 0){
+ this.refresh();
+ return;
+ }
+ var n = this.nodes[index];
+ for(var i = 0, len = records.length; i < len; i++){
+ var d = this.prepareData(records[i].data, i, records[i]);
+ if(n){
+ this.tpl.insertBefore(n, d);
+ }else{
+
+ this.tpl.append(this.el, d);
+ }
+ }
+ this.updateIndexes(index);
+ },
+
+ onRemove : function(ds, record, index){
+ // Roo.log('onRemove');
+ this.clearSelections();
+ var el = this.dataName ?
+ this.el.child('.roo-tpl-' + this.dataName) :
+ this.el;
+
+ el.dom.removeChild(this.nodes[index]);
+ this.updateIndexes(index);
+ },
+
+ /**
+ * Refresh an individual node.
+ * @param {Number} index
+ */
+ refreshNode : function(index){
+ this.onUpdate(this.store, this.store.getAt(index));
+ },
+
+ updateIndexes : function(startIndex, endIndex){
+ var ns = this.nodes;
+ startIndex = startIndex || 0;
+ endIndex = endIndex || ns.length - 1;
+ for(var i = startIndex; i <= endIndex; i++){
ns[i].nodeIndex = i;
}
},
- /**
- * Changes the data store this view uses and refresh the view.
- * @param {Store} store
- */
- setStore : function(store, initial){
- if(!initial && this.store){
- this.store.un("datachanged", this.refresh);
- this.store.un("add", this.onAdd);
- this.store.un("remove", this.onRemove);
- this.store.un("update", this.onUpdate);
- this.store.un("clear", this.refresh);
- this.store.un("beforeload", this.onBeforeLoad);
- this.store.un("load", this.onLoad);
- this.store.un("loadexception", this.onLoad);
+ /**
+ * Changes the data store this view uses and refresh the view.
+ * @param {Store} store
+ */
+ setStore : function(store, initial){
+ if(!initial && this.store){
+ this.store.un("datachanged", this.refresh);
+ this.store.un("add", this.onAdd);
+ this.store.un("remove", this.onRemove);
+ this.store.un("update", this.onUpdate);
+ this.store.un("clear", this.refresh);
+ this.store.un("beforeload", this.onBeforeLoad);
+ this.store.un("load", this.onLoad);
+ this.store.un("loadexception", this.onLoad);
+ }
+ if(store){
+
+ store.on("datachanged", this.refresh, this);
+ store.on("add", this.onAdd, this);
+ store.on("remove", this.onRemove, this);
+ store.on("update", this.onUpdate, this);
+ store.on("clear", this.refresh, this);
+ store.on("beforeload", this.onBeforeLoad, this);
+ store.on("load", this.onLoad, this);
+ store.on("loadexception", this.onLoad, this);
+ }
+
+ if(store){
+ this.refresh();
+ }
+ },
+ /**
+ * onbeforeLoad - masks the loading area.
+ *
+ */
+ onBeforeLoad : function(store,opts)
+ {
+ //Roo.log('onBeforeLoad');
+ if (!opts.add) {
+ this.el.update("");
+ }
+ this.el.mask(this.mask ? this.mask : "Loading" );
+ },
+ onLoad : function ()
+ {
+ this.el.unmask();
+ },
+
+
+ /**
+ * Returns the template node the passed child belongs to or null if it doesn't belong to one.
+ * @param {HTMLElement} node
+ * @return {HTMLElement} The template node
+ */
+ findItemFromChild : function(node){
+ var el = this.dataName ?
+ this.el.child('.roo-tpl-' + this.dataName,true) :
+ this.el.dom;
+
+ if(!node || node.parentNode == el){
+ return node;
+ }
+ var p = node.parentNode;
+ while(p && p != el){
+ if(p.parentNode == el){
+ return p;
+ }
+ p = p.parentNode;
+ }
+ return null;
+ },
+
+ /** @ignore */
+ onClick : function(e){
+ var item = this.findItemFromChild(e.getTarget());
+ if(item){
+ var index = this.indexOf(item);
+ if(this.onItemClick(item, index, e) !== false){
+ this.fireEvent("click", this, index, item, e);
+ }
+ }else{
+ this.clearSelections();
+ }
+ },
+
+ /** @ignore */
+ onContextMenu : function(e){
+ var item = this.findItemFromChild(e.getTarget());
+ if(item){
+ this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
+ }
+ },
+
+ /** @ignore */
+ onDblClick : function(e){
+ var item = this.findItemFromChild(e.getTarget());
+ if(item){
+ this.fireEvent("dblclick", this, this.indexOf(item), item, e);
+ }
+ },
+
+ onItemClick : function(item, index, e)
+ {
+ if(this.fireEvent("beforeclick", this, index, item, e) === false){
+ return false;
+ }
+ if (this.toggleSelect) {
+ var m = this.isSelected(item) ? 'unselect' : 'select';
+ //Roo.log(m);
+ var _t = this;
+ _t[m](item, true, false);
+ return true;
+ }
+ if(this.multiSelect || this.singleSelect){
+ if(this.multiSelect && e.shiftKey && this.lastSelection){
+ this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
+ }else{
+ this.select(item, this.multiSelect && e.ctrlKey);
+ this.lastSelection = item;
+ }
+
+ if(!this.tickable){
+ e.preventDefault();
+ }
+
+ }
+ return true;
+ },
+
+ /**
+ * Get the number of selected nodes.
+ * @return {Number}
+ */
+ getSelectionCount : function(){
+ return this.selections.length;
+ },
+
+ /**
+ * Get the currently selected nodes.
+ * @return {Array} An array of HTMLElements
+ */
+ getSelectedNodes : function(){
+ return this.selections;
+ },
+
+ /**
+ * Get the indexes of the selected nodes.
+ * @return {Array}
+ */
+ getSelectedIndexes : function(){
+ var indexes = [], s = this.selections;
+ for(var i = 0, len = s.length; i < len; i++){
+ indexes.push(s[i].nodeIndex);
+ }
+ return indexes;
+ },
+
+ /**
+ * Clear all selections
+ * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
+ */
+ clearSelections : function(suppressEvent){
+ if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
+ this.cmp.elements = this.selections;
+ this.cmp.removeClass(this.selectedClass);
+ this.selections = [];
+ if(!suppressEvent){
+ this.fireEvent("selectionchange", this, this.selections);
+ }
+ }
+ },
+
+ /**
+ * Returns true if the passed node is selected
+ * @param {HTMLElement/Number} node The node or node index
+ * @return {Boolean}
+ */
+ isSelected : function(node){
+ var s = this.selections;
+ if(s.length < 1){
+ return false;
+ }
+ node = this.getNode(node);
+ return s.indexOf(node) !== -1;
+ },
+
+ /**
+ * Selects nodes.
+ * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+ * @param {Boolean} keepExisting (optional) true to keep existing selections
+ * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+ */
+ select : function(nodeInfo, keepExisting, suppressEvent){
+ if(nodeInfo instanceof Array){
+ if(!keepExisting){
+ this.clearSelections(true);
+ }
+ for(var i = 0, len = nodeInfo.length; i < len; i++){
+ this.select(nodeInfo[i], true, true);
+ }
+ return;
+ }
+ var node = this.getNode(nodeInfo);
+ if(!node || this.isSelected(node)){
+ return; // already selected.
+ }
+ if(!keepExisting){
+ this.clearSelections(true);
+ }
+
+ if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
+ Roo.fly(node).addClass(this.selectedClass);
+ this.selections.push(node);
+ if(!suppressEvent){
+ this.fireEvent("selectionchange", this, this.selections);
+ }
+ }
+
+
+ },
+ /**
+ * Unselects nodes.
+ * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+ * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
+ * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+ */
+ unselect : function(nodeInfo, keepExisting, suppressEvent)
+ {
+ if(nodeInfo instanceof Array){
+ Roo.each(this.selections, function(s) {
+ this.unselect(s, nodeInfo);
+ }, this);
+ return;
+ }
+ var node = this.getNode(nodeInfo);
+ if(!node || !this.isSelected(node)){
+ //Roo.log("not selected");
+ return; // not selected.
+ }
+ // fireevent???
+ var ns = [];
+ Roo.each(this.selections, function(s) {
+ if (s == node ) {
+ Roo.fly(node).removeClass(this.selectedClass);
+
+ return;
+ }
+ ns.push(s);
+ },this);
+
+ this.selections= ns;
+ this.fireEvent("selectionchange", this, this.selections);
+ },
+
+ /**
+ * Gets a template node.
+ * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
+ * @return {HTMLElement} The node or null if it wasn't found
+ */
+ getNode : function(nodeInfo){
+ if(typeof nodeInfo == "string"){
+ return document.getElementById(nodeInfo);
+ }else if(typeof nodeInfo == "number"){
+ return this.nodes[nodeInfo];
+ }
+ return nodeInfo;
+ },
+
+ /**
+ * Gets a range template nodes.
+ * @param {Number} startIndex
+ * @param {Number} endIndex
+ * @return {Array} An array of nodes
+ */
+ getNodes : function(start, end){
+ var ns = this.nodes;
+ start = start || 0;
+ end = typeof end == "undefined" ? ns.length - 1 : end;
+ var nodes = [];
+ if(start <= end){
+ for(var i = start; i <= end; i++){
+ nodes.push(ns[i]);
+ }
+ } else{
+ for(var i = start; i >= end; i--){
+ nodes.push(ns[i]);
+ }
+ }
+ return nodes;
+ },
+
+ /**
+ * Finds the index of the passed node
+ * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
+ * @return {Number} The index of the node or -1
+ */
+ indexOf : function(node){
+ node = this.getNode(node);
+ if(typeof node.nodeIndex == "number"){
+ return node.nodeIndex;
+ }
+ var ns = this.nodes;
+ for(var i = 0, len = ns.length; i < len; i++){
+ if(ns[i] == node){
+ return i;
+ }
+ }
+ return -1;
+ }
+});
+/*
+ * - LGPL
+ *
+ * based on jquery fullcalendar
+ *
+ */
+
+Roo.bootstrap = Roo.bootstrap || {};
+/**
+ * @class Roo.bootstrap.Calendar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Calendar class
+ * @cfg {Boolean} loadMask (true|false) default false
+ * @cfg {Object} header generate the user specific header of the calendar, default false
+
+ * @constructor
+ * Create a new Container
+ * @param {Object} config The config object
+ */
+
+
+
+Roo.bootstrap.Calendar = function(config){
+ Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
+ this.addEvents({
+ /**
+ * @event select
+ * Fires when a date is selected
+ * @param {DatePicker} this
+ * @param {Date} date The selected date
+ */
+ 'select': true,
+ /**
+ * @event monthchange
+ * Fires when the displayed month changes
+ * @param {DatePicker} this
+ * @param {Date} date The selected month
+ */
+ 'monthchange': true,
+ /**
+ * @event evententer
+ * Fires when mouse over an event
+ * @param {Calendar} this
+ * @param {event} Event
+ */
+ 'evententer': true,
+ /**
+ * @event eventleave
+ * Fires when the mouse leaves an
+ * @param {Calendar} this
+ * @param {event}
+ */
+ 'eventleave': true,
+ /**
+ * @event eventclick
+ * Fires when the mouse click an
+ * @param {Calendar} this
+ * @param {event}
+ */
+ 'eventclick': true
+
+ });
+
+};
+
+Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
+
+ /**
+ * @cfg {Number} startDay
+ * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+ */
+ startDay : 0,
+
+ loadMask : false,
+
+ header : false,
+
+ getAutoCreate : function(){
+
+
+ var fc_button = function(name, corner, style, content ) {
+ return Roo.apply({},{
+ tag : 'span',
+ cls : 'fc-button fc-button-'+name+' fc-state-default ' +
+ (corner.length ?
+ 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
+ ''
+ ),
+ html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
+ unselectable: 'on'
+ });
+ };
+
+ var header = {};
+
+ if(!this.header){
+ header = {
+ tag : 'table',
+ cls : 'fc-header',
+ style : 'width:100%',
+ cn : [
+ {
+ tag: 'tr',
+ cn : [
+ {
+ tag : 'td',
+ cls : 'fc-header-left',
+ cn : [
+ fc_button('prev', 'left', 'arrow', '‹' ),
+ fc_button('next', 'right', 'arrow', '›' ),
+ { tag: 'span', cls: 'fc-header-space' },
+ fc_button('today', 'left right', '', 'today' ) // neds state disabled..
+
+
+ ]
+ },
+
+ {
+ tag : 'td',
+ cls : 'fc-header-center',
+ cn : [
+ {
+ tag: 'span',
+ cls: 'fc-header-title',
+ cn : {
+ tag: 'H2',
+ html : 'month / year'
+ }
+ }
+
+ ]
+ },
+ {
+ tag : 'td',
+ cls : 'fc-header-right',
+ cn : [
+ /* fc_button('month', 'left', '', 'month' ),
+ fc_button('week', '', '', 'week' ),
+ fc_button('day', 'right', '', 'day' )
+ */
+
+ ]
+ }
+
+ ]
+ }
+ ]
+ };
+ }
+
+ header = this.header;
+
+
+ var cal_heads = function() {
+ var ret = [];
+ // fixme - handle this.
+
+ for (var i =0; i < Date.dayNames.length; i++) {
+ var d = Date.dayNames[i];
+ ret.push({
+ tag: 'th',
+ cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
+ html : d.substring(0,3)
+ });
+
+ }
+ ret[0].cls += ' fc-first';
+ ret[6].cls += ' fc-last';
+ return ret;
+ };
+ var cal_cell = function(n) {
+ return {
+ tag: 'td',
+ cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
+ cn : [
+ {
+ cn : [
+ {
+ cls: 'fc-day-number',
+ html: 'D'
+ },
+ {
+ cls: 'fc-day-content',
+
+ cn : [
+ {
+ style: 'position: relative;' // height: 17px;
+ }
+ ]
+ }
+
+
+ ]
+ }
+ ]
+
+ }
+ };
+ var cal_rows = function() {
+
+ var ret = [];
+ for (var r = 0; r < 6; r++) {
+ var row= {
+ tag : 'tr',
+ cls : 'fc-week',
+ cn : []
+ };
+
+ for (var i =0; i < Date.dayNames.length; i++) {
+ var d = Date.dayNames[i];
+ row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
+
+ }
+ row.cn[0].cls+=' fc-first';
+ row.cn[0].cn[0].style = 'min-height:90px';
+ row.cn[6].cls+=' fc-last';
+ ret.push(row);
+
+ }
+ ret[0].cls += ' fc-first';
+ ret[4].cls += ' fc-prev-last';
+ ret[5].cls += ' fc-last';
+ return ret;
+
+ };
+
+ var cal_table = {
+ tag: 'table',
+ cls: 'fc-border-separate',
+ style : 'width:100%',
+ cellspacing : 0,
+ cn : [
+ {
+ tag: 'thead',
+ cn : [
+ {
+ tag: 'tr',
+ cls : 'fc-first fc-last',
+ cn : cal_heads()
+ }
+ ]
+ },
+ {
+ tag: 'tbody',
+ cn : cal_rows()
+ }
+
+ ]
+ };
+
+ var cfg = {
+ cls : 'fc fc-ltr',
+ cn : [
+ header,
+ {
+ cls : 'fc-content',
+ style : "position: relative;",
+ cn : [
+ {
+ cls : 'fc-view fc-view-month fc-grid',
+ style : 'position: relative',
+ unselectable : 'on',
+ cn : [
+ {
+ cls : 'fc-event-container',
+ style : 'position:absolute;z-index:8;top:0;left:0;'
+ },
+ cal_table
+ ]
+ }
+ ]
+
+ }
+ ]
+
+ };
+
+
+
+ return cfg;
+ },
+
+
+ initEvents : function()
+ {
+ if(!this.store){
+ throw "can not find store for calendar";
+ }
+
+ var mark = {
+ tag: "div",
+ cls:"x-dlg-mask",
+ style: "text-align:center",
+ cn: [
+ {
+ tag: "div",
+ style: "background-color:white;width:50%;margin:250 auto",
+ cn: [
+ {
+ tag: "img",
+ src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
+ },
+ {
+ tag: "span",
+ html: "Loading"
+ }
+
+ ]
+ }
+ ]
+ }
+ this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
+
+ var size = this.el.select('.fc-content', true).first().getSize();
+ this.maskEl.setSize(size.width, size.height);
+ this.maskEl.enableDisplayMode("block");
+ if(!this.loadMask){
+ this.maskEl.hide();
+ }
+
+ this.store = Roo.factory(this.store, Roo.data);
+ this.store.on('load', this.onLoad, this);
+ this.store.on('beforeload', this.onBeforeLoad, this);
+
+ this.resize();
+
+ this.cells = this.el.select('.fc-day',true);
+ //Roo.log(this.cells);
+ this.textNodes = this.el.query('.fc-day-number');
+ this.cells.addClassOnOver('fc-state-hover');
+
+ this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
+ this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
+ this.el.select('.fc-button-today',true).on('click', this.showToday, this);
+ this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
+
+ this.on('monthchange', this.onMonthChange, this);
+
+ this.update(new Date().clearTime());
+ },
+
+ resize : function() {
+ var sz = this.el.getSize();
+
+ this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
+ this.el.select('.fc-day-content div',true).setHeight(34);
+ },
+
+
+ // private
+ showPrevMonth : function(e){
+ this.update(this.activeDate.add("mo", -1));
+ },
+ showToday : function(e){
+ this.update(new Date().clearTime());
+ },
+ // private
+ showNextMonth : function(e){
+ this.update(this.activeDate.add("mo", 1));
+ },
+
+ // private
+ showPrevYear : function(){
+ this.update(this.activeDate.add("y", -1));
+ },
+
+ // private
+ showNextYear : function(){
+ this.update(this.activeDate.add("y", 1));
+ },
+
+
+ // private
+ update : function(date)
+ {
+ var vd = this.activeDate;
+ this.activeDate = date;
+// if(vd && this.el){
+// var t = date.getTime();
+// if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
+// Roo.log('using add remove');
+//
+// this.fireEvent('monthchange', this, date);
+//
+// this.cells.removeClass("fc-state-highlight");
+// this.cells.each(function(c){
+// if(c.dateValue == t){
+// c.addClass("fc-state-highlight");
+// setTimeout(function(){
+// try{c.dom.firstChild.focus();}catch(e){}
+// }, 50);
+// return false;
+// }
+// return true;
+// });
+// return;
+// }
+// }
+
+ var days = date.getDaysInMonth();
+
+ var firstOfMonth = date.getFirstDateOfMonth();
+ var startingPos = firstOfMonth.getDay()-this.startDay;
+
+ if(startingPos < this.startDay){
+ startingPos += 7;
+ }
+
+ var pm = date.add(Date.MONTH, -1);
+ var prevStart = pm.getDaysInMonth()-startingPos;
+//
+ this.cells = this.el.select('.fc-day',true);
+ this.textNodes = this.el.query('.fc-day-number');
+ this.cells.addClassOnOver('fc-state-hover');
+
+ var cells = this.cells.elements;
+ var textEls = this.textNodes;
+
+ Roo.each(cells, function(cell){
+ cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
+ });
+
+ days += startingPos;
+
+ // convert everything to numbers so it's fast
+ var day = 86400000;
+ var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
+ //Roo.log(d);
+ //Roo.log(pm);
+ //Roo.log(prevStart);
+
+ var today = new Date().clearTime().getTime();
+ var sel = date.clearTime().getTime();
+ var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
+ var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
+ var ddMatch = this.disabledDatesRE;
+ var ddText = this.disabledDatesText;
+ var ddays = this.disabledDays ? this.disabledDays.join("") : false;
+ var ddaysText = this.disabledDaysText;
+ var format = this.format;
+
+ var setCellClass = function(cal, cell){
+ cell.row = 0;
+ cell.events = [];
+ cell.more = [];
+ //Roo.log('set Cell Class');
+ cell.title = "";
+ var t = d.getTime();
+
+ //Roo.log(d);
+
+ cell.dateValue = t;
+ if(t == today){
+ cell.className += " fc-today";
+ cell.className += " fc-state-highlight";
+ cell.title = cal.todayText;
+ }
+ if(t == sel){
+ // disable highlight in other month..
+ //cell.className += " fc-state-highlight";
+
+ }
+ // disabling
+ if(t < min) {
+ cell.className = " fc-state-disabled";
+ cell.title = cal.minText;
+ return;
+ }
+ if(t > max) {
+ cell.className = " fc-state-disabled";
+ cell.title = cal.maxText;
+ return;
+ }
+ if(ddays){
+ if(ddays.indexOf(d.getDay()) != -1){
+ cell.title = ddaysText;
+ cell.className = " fc-state-disabled";
+ }
+ }
+ if(ddMatch && format){
+ var fvalue = d.dateFormat(format);
+ if(ddMatch.test(fvalue)){
+ cell.title = ddText.replace("%0", fvalue);
+ cell.className = " fc-state-disabled";
+ }
+ }
+
+ if (!cell.initialClassName) {
+ cell.initialClassName = cell.dom.className;
+ }
+
+ cell.dom.className = cell.initialClassName + ' ' + cell.className;
+ };
+
+ var i = 0;
+
+ for(; i < startingPos; i++) {
+ textEls[i].innerHTML = (++prevStart);
+ d.setDate(d.getDate()+1);
+
+ cells[i].className = "fc-past fc-other-month";
+ setCellClass(this, cells[i]);
+ }
+
+ var intDay = 0;
+
+ for(; i < days; i++){
+ intDay = i - startingPos + 1;
+ textEls[i].innerHTML = (intDay);
+ d.setDate(d.getDate()+1);
+
+ cells[i].className = ''; // "x-date-active";
+ setCellClass(this, cells[i]);
+ }
+ var extraDays = 0;
+
+ for(; i < 42; i++) {
+ textEls[i].innerHTML = (++extraDays);
+ d.setDate(d.getDate()+1);
+
+ cells[i].className = "fc-future fc-other-month";
+ setCellClass(this, cells[i]);
+ }
+
+ this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
+
+ var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
+
+ this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
+ this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
+
+ if(totalRows != 6){
+ this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
+ this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
+ }
+
+ this.fireEvent('monthchange', this, date);
+
+
+ /*
+ if(!this.internalRender){
+ var main = this.el.dom.firstChild;
+ var w = main.offsetWidth;
+ this.el.setWidth(w + this.el.getBorderWidth("lr"));
+ Roo.fly(main).setWidth(w);
+ this.internalRender = true;
+ // opera does not respect the auto grow header center column
+ // then, after it gets a width opera refuses to recalculate
+ // without a second pass
+ if(Roo.isOpera && !this.secondPass){
+ main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
+ this.secondPass = true;
+ this.update.defer(10, this, [date]);
+ }
+ }
+ */
+
+ },
+
+ findCell : function(dt) {
+ dt = dt.clearTime().getTime();
+ var ret = false;
+ this.cells.each(function(c){
+ //Roo.log("check " +c.dateValue + '?=' + dt);
+ if(c.dateValue == dt){
+ ret = c;
+ return false;
+ }
+ return true;
+ });
+
+ return ret;
+ },
+
+ findCells : function(ev) {
+ var s = ev.start.clone().clearTime().getTime();
+ // Roo.log(s);
+ var e= ev.end.clone().clearTime().getTime();
+ // Roo.log(e);
+ var ret = [];
+ this.cells.each(function(c){
+ ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
+
+ if(c.dateValue > e){
+ return ;
+ }
+ if(c.dateValue < s){
+ return ;
+ }
+ ret.push(c);
+ });
+
+ return ret;
+ },
+
+// findBestRow: function(cells)
+// {
+// var ret = 0;
+//
+// for (var i =0 ; i < cells.length;i++) {
+// ret = Math.max(cells[i].rows || 0,ret);
+// }
+// return ret;
+//
+// },
+
+
+ addItem : function(ev)
+ {
+ // look for vertical location slot in
+ var cells = this.findCells(ev);
+
+// ev.row = this.findBestRow(cells);
+
+ // work out the location.
+
+ var crow = false;
+ var rows = [];
+ for(var i =0; i < cells.length; i++) {
+
+ cells[i].row = cells[0].row;
+
+ if(i == 0){
+ cells[i].row = cells[i].row + 1;
+ }
+
+ if (!crow) {
+ crow = {
+ start : cells[i],
+ end : cells[i]
+ };
+ continue;
+ }
+ if (crow.start.getY() == cells[i].getY()) {
+ // on same row.
+ crow.end = cells[i];
+ continue;
+ }
+ // different row.
+ rows.push(crow);
+ crow = {
+ start: cells[i],
+ end : cells[i]
+ };
+
+ }
+
+ rows.push(crow);
+ ev.els = [];
+ ev.rows = rows;
+ ev.cells = cells;
+
+ cells[0].events.push(ev);
+
+ this.calevents.push(ev);
+ },
+
+ clearEvents: function() {
+
+ if(!this.calevents){
+ return;
+ }
+
+ Roo.each(this.cells.elements, function(c){
+ c.row = 0;
+ c.events = [];
+ c.more = [];
+ });
+
+ Roo.each(this.calevents, function(e) {
+ Roo.each(e.els, function(el) {
+ el.un('mouseenter' ,this.onEventEnter, this);
+ el.un('mouseleave' ,this.onEventLeave, this);
+ el.remove();
+ },this);
+ },this);
+
+ Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
+ e.remove();
+ });
+
+ },
+
+ renderEvents: function()
+ {
+ var _this = this;
+
+ this.cells.each(function(c) {
+
+ if(c.row < 5){
+ return;
+ }
+
+ var ev = c.events;
+
+ var r = 4;
+ if(c.row != c.events.length){
+ r = 4 - (4 - (c.row - c.events.length));
+ }
+
+ c.events = ev.slice(0, r);
+ c.more = ev.slice(r);
+
+ if(c.more.length && c.more.length == 1){
+ c.events.push(c.more.pop());
+ }
+
+ c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
+
+ });
+
+ this.cells.each(function(c) {
+
+ c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
+
+
+ for (var e = 0; e < c.events.length; e++){
+ var ev = c.events[e];
+ var rows = ev.rows;
+
+ for(var i = 0; i < rows.length; i++) {
+
+ // how many rows should it span..
+
+ var cfg = {
+ cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
+ style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
+
+ unselectable : "on",
+ cn : [
+ {
+ cls: 'fc-event-inner',
+ cn : [
+ // {
+ // tag:'span',
+ // cls: 'fc-event-time',
+ // html : cells.length > 1 ? '' : ev.time
+ // },
+ {
+ tag:'span',
+ cls: 'fc-event-title',
+ html : String.format('{0}', ev.title)
+ }
+
+
+ ]
+ },
+ {
+ cls: 'ui-resizable-handle ui-resizable-e',
+ html : '  '
+ }
+
+ ]
+ };
+
+ if (i == 0) {
+ cfg.cls += ' fc-event-start';
+ }
+ if ((i+1) == rows.length) {
+ cfg.cls += ' fc-event-end';
+ }
+
+ var ctr = _this.el.select('.fc-event-container',true).first();
+ var cg = ctr.createChild(cfg);
+
+ var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
+ var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
+
+ var r = (c.more.length) ? 1 : 0;
+ cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
+ cg.setWidth(ebox.right - sbox.x -2);
+
+ cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
+ cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
+ cg.on('click', _this.onEventClick, _this, ev);
+
+ ev.els.push(cg);
+
+ }
+
+ }
+
+
+ if(c.more.length){
+ var cfg = {
+ cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
+ style : 'position: absolute',
+ unselectable : "on",
+ cn : [
+ {
+ cls: 'fc-event-inner',
+ cn : [
+ {
+ tag:'span',
+ cls: 'fc-event-title',
+ html : 'More'
+ }
+
+
+ ]
+ },
+ {
+ cls: 'ui-resizable-handle ui-resizable-e',
+ html : '  '
+ }
+
+ ]
+ };
+
+ var ctr = _this.el.select('.fc-event-container',true).first();
+ var cg = ctr.createChild(cfg);
+
+ var sbox = c.select('.fc-day-content',true).first().getBox();
+ var ebox = c.select('.fc-day-content',true).first().getBox();
+ //Roo.log(cg);
+ cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
+ cg.setWidth(ebox.right - sbox.x -2);
+
+ cg.on('click', _this.onMoreEventClick, _this, c.more);
+
+ }
+
+ });
+
+
+
+ },
+
+ onEventEnter: function (e, el,event,d) {
+ this.fireEvent('evententer', this, el, event);
+ },
+
+ onEventLeave: function (e, el,event,d) {
+ this.fireEvent('eventleave', this, el, event);
+ },
+
+ onEventClick: function (e, el,event,d) {
+ this.fireEvent('eventclick', this, el, event);
+ },
+
+ onMonthChange: function () {
+ this.store.load();
+ },
+
+ onMoreEventClick: function(e, el, more)
+ {
+ var _this = this;
+
+ this.calpopover.placement = 'right';
+ this.calpopover.setTitle('More');
+
+ this.calpopover.setContent('');
+
+ var ctr = this.calpopover.el.select('.popover-content', true).first();
+
+ Roo.each(more, function(m){
+ var cfg = {
+ cls : 'fc-event-hori fc-event-draggable',
+ html : m.title
+ }
+ var cg = ctr.createChild(cfg);
+
+ cg.on('click', _this.onEventClick, _this, m);
+ });
+
+ this.calpopover.show(el);
+
+
+ },
+
+ onLoad: function ()
+ {
+ this.calevents = [];
+ var cal = this;
+
+ if(this.store.getCount() > 0){
+ this.store.data.each(function(d){
+ cal.addItem({
+ id : d.data.id,
+ start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
+ end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
+ time : d.data.start_time,
+ title : d.data.title,
+ description : d.data.description,
+ venue : d.data.venue
+ });
+ });
+ }
+
+ this.renderEvents();
+
+ if(this.calevents.length && this.loadMask){
+ this.maskEl.hide();
+ }
+ },
+
+ onBeforeLoad: function()
+ {
+ this.clearEvents();
+ if(this.loadMask){
+ this.maskEl.show();
+ }
+ }
+});
+
+
+ /*
+ * - LGPL
+ *
+ * element
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.Popover
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Popover class
+ * @cfg {String} html contents of the popover (or false to use children..)
+ * @cfg {String} title of popover (or false to hide)
+ * @cfg {String} placement how it is placed
+ * @cfg {String} trigger click || hover (or false to trigger manually)
+ * @cfg {String} over what (parent or false to trigger manually.)
+ * @cfg {Number} delay - delay before showing
+
+ * @constructor
+ * Create a new Popover
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Popover = function(config){
+ Roo.bootstrap.Popover.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
+
+ title: 'Fill in a title',
+ html: false,
+
+ placement : 'right',
+ trigger : 'hover', // hover
+
+ delay : 0,
+
+ over: 'parent',
+
+ can_build_overlaid : false,
+
+ getChildContainer : function()
+ {
+ return this.el.select('.popover-content',true).first();
+ },
+
+ getAutoCreate : function(){
+ Roo.log('make popover?');
+ var cfg = {
+ cls : 'popover roo-dynamic',
+ style: 'display:block',
+ cn : [
+ {
+ cls : 'arrow'
+ },
+ {
+ cls : 'popover-inner',
+ cn : [
+ {
+ tag: 'h3',
+ cls: 'popover-title',
+ html : this.title
+ },
+ {
+ cls : 'popover-content',
+ html : this.html
+ }
+ ]
+
+ }
+ ]
+ };
+
+ return cfg;
+ },
+ setTitle: function(str)
+ {
+ this.title = str;
+ this.el.select('.popover-title',true).first().dom.innerHTML = str;
+ },
+ setContent: function(str)
+ {
+ this.html = str;
+ this.el.select('.popover-content',true).first().dom.innerHTML = str;
+ },
+ // as it get's added to the bottom of the page.
+ onRender : function(ct, position)
+ {
+ Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
+ if(!this.el){
+ var cfg = Roo.apply({}, this.getAutoCreate());
+ cfg.id = Roo.id();
+
+ if (this.cls) {
+ cfg.cls += ' ' + this.cls;
+ }
+ if (this.style) {
+ cfg.style = this.style;
+ }
+ Roo.log("adding to ")
+ this.el = Roo.get(document.body).createChild(cfg, position);
+ Roo.log(this.el);
+ }
+ this.initEvents();
+ },
+
+ initEvents : function()
+ {
+ this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
+ this.el.enableDisplayMode('block');
+ this.el.hide();
+ if (this.over === false) {
+ return;
+ }
+ if (this.triggers === false) {
+ return;
+ }
+ var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
+ var triggers = this.trigger ? this.trigger.split(' ') : [];
+ Roo.each(triggers, function(trigger) {
+
+ if (trigger == 'click') {
+ on_el.on('click', this.toggle, this);
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
+
+ on_el.on(eventIn ,this.enter, this);
+ on_el.on(eventOut, this.leave, this);
+ }
+ }, this);
+
+ },
+
+
+ // private
+ timeout : null,
+ hoverState : null,
+
+ toggle : function () {
+ this.hoverState == 'in' ? this.leave() : this.enter();
+ },
+
+ enter : function () {
+
+
+ clearTimeout(this.timeout);
+
+ this.hoverState = 'in';
+
+ if (!this.delay || !this.delay.show) {
+ this.show();
+ return;
+ }
+ var _t = this;
+ this.timeout = setTimeout(function () {
+ if (_t.hoverState == 'in') {
+ _t.show();
+ }
+ }, this.delay.show)
+ },
+ leave : function() {
+ clearTimeout(this.timeout);
+
+ this.hoverState = 'out';
+
+ if (!this.delay || !this.delay.hide) {
+ this.hide();
+ return;
+ }
+ var _t = this;
+ this.timeout = setTimeout(function () {
+ if (_t.hoverState == 'out') {
+ _t.hide();
+ }
+ }, this.delay.hide)
+ },
+
+ show : function (on_el)
+ {
+ if (!on_el) {
+ on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
+ }
+ // set content.
+ this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
+ if (this.html !== false) {
+ this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
+ }
+ this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
+ if (!this.title.length) {
+ this.el.select('.popover-title',true).hide();
+ }
+
+ var placement = typeof this.placement == 'function' ?
+ this.placement.call(this, this.el, on_el) :
+ this.placement;
+
+ var autoToken = /\s?auto?\s?/i;
+ var autoPlace = autoToken.test(placement);
+ if (autoPlace) {
+ placement = placement.replace(autoToken, '') || 'top';
+ }
+
+ //this.el.detach()
+ //this.el.setXY([0,0]);
+ this.el.show();
+ this.el.dom.style.display='block';
+ this.el.addClass(placement);
+
+ //this.el.appendTo(on_el);
+
+ var p = this.getPosition();
+ var box = this.el.getBox();
+
+ if (autoPlace) {
+ // fixme..
+ }
+ var align = Roo.bootstrap.Popover.alignment[placement];
+ this.el.alignTo(on_el, align[0],align[1]);
+ //var arrow = this.el.select('.arrow',true).first();
+ //arrow.set(align[2],
+
+ this.el.addClass('in');
+
+
+ if (this.el.hasClass('fade')) {
+ // fade it?
+ }
+
+ },
+ hide : function()
+ {
+ this.el.setXY([0,0]);
+ this.el.removeClass('in');
+ this.el.hide();
+ this.hoverState = null;
+
+ }
+
+});
+
+Roo.bootstrap.Popover.alignment = {
+ 'left' : ['r-l', [-10,0], 'right'],
+ 'right' : ['l-r', [10,0], 'left'],
+ 'bottom' : ['t-b', [0,10], 'top'],
+ 'top' : [ 'b-t', [0,-10], 'bottom']
+};
+
+ /*
+ * - LGPL
+ *
+ * Progress
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.Progress
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Progress class
+ * @cfg {Boolean} striped striped of the progress bar
+ * @cfg {Boolean} active animated of the progress bar
+ *
+ *
+ * @constructor
+ * Create a new Progress
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Progress = function(config){
+ Roo.bootstrap.Progress.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
+
+ striped : false,
+ active: false,
+
+ getAutoCreate : function(){
+ var cfg = {
+ tag: 'div',
+ cls: 'progress'
+ };
+
+
+ if(this.striped){
+ cfg.cls += ' progress-striped';
+ }
+
+ if(this.active){
+ cfg.cls += ' active';
+ }
+
+
+ return cfg;
+ }
+
+});
+
+
+
+ /*
+ * - LGPL
+ *
+ * ProgressBar
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.ProgressBar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap ProgressBar class
+ * @cfg {Number} aria_valuenow aria-value now
+ * @cfg {Number} aria_valuemin aria-value min
+ * @cfg {Number} aria_valuemax aria-value max
+ * @cfg {String} label label for the progress bar
+ * @cfg {String} panel (success | info | warning | danger )
+ * @cfg {String} role role of the progress bar
+ * @cfg {String} sr_only text
+ *
+ *
+ * @constructor
+ * Create a new ProgressBar
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.ProgressBar = function(config){
+ Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
+
+ aria_valuenow : 0,
+ aria_valuemin : 0,
+ aria_valuemax : 100,
+ label : false,
+ panel : false,
+ role : false,
+ sr_only: false,
+
+ getAutoCreate : function()
+ {
+
+ var cfg = {
+ tag: 'div',
+ cls: 'progress-bar',
+ style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
+ };
+
+ if(this.sr_only){
+ cfg.cn = {
+ tag: 'span',
+ cls: 'sr-only',
+ html: this.sr_only
+ }
+ }
+
+ if(this.role){
+ cfg.role = this.role;
+ }
+
+ if(this.aria_valuenow){
+ cfg['aria-valuenow'] = this.aria_valuenow;
+ }
+
+ if(this.aria_valuemin){
+ cfg['aria-valuemin'] = this.aria_valuemin;
+ }
+
+ if(this.aria_valuemax){
+ cfg['aria-valuemax'] = this.aria_valuemax;
+ }
+
+ if(this.label && !this.sr_only){
+ cfg.html = this.label;
+ }
+
+ if(this.panel){
+ cfg.cls += ' progress-bar-' + this.panel;
+ }
+
+ return cfg;
+ },
+
+ update : function(aria_valuenow)
+ {
+ this.aria_valuenow = aria_valuenow;
+
+ this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
+ }
+
+});
+
+
+
+ /*
+ * - LGPL
+ *
+ * column
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.TabGroup
+ * @extends Roo.bootstrap.Column
+ * Bootstrap Column class
+ * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
+ * @cfg {Boolean} carousel true to make the group behave like a carousel
+ * @cfg {Number} bullets show the panel pointer.. default 0
+ * @cfg {Boolean} autoslide (true|false) auto slide .. default false
+ * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
+ * @cfg {Number} timer auto slide timer .. default 0 millisecond
+ *
+ * @constructor
+ * Create a new TabGroup
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.TabGroup = function(config){
+ Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
+ if (!this.navId) {
+ this.navId = Roo.id();
+ }
+ this.tabs = [];
+ Roo.bootstrap.TabGroup.register(this);
+
+};
+
+Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
+
+ carousel : false,
+ transition : false,
+ bullets : 0,
+ timer : 0,
+ autoslide : false,
+ slideFn : false,
+ slideOnTouch : false,
+
+ getAutoCreate : function()
+ {
+ var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
+
+ cfg.cls += ' tab-content';
+
+ Roo.log('get auto create...............');
+
+ if (this.carousel) {
+ cfg.cls += ' carousel slide';
+
+ cfg.cn = [{
+ cls : 'carousel-inner'
+ }];
+
+ if(this.bullets > 0 && !Roo.isTouch){
+
+ var bullets = {
+ cls : 'carousel-bullets',
+ cn : []
+ };
+
+ if(this.bullets_cls){
+ bullets.cls = bullets.cls + ' ' + this.bullets_cls;
+ }
+
+ for (var i = 0; i < this.bullets; i++){
+ bullets.cn.push({
+ cls : 'bullet bullet-' + i
+ });
+ }
+
+ bullets.cn.push({
+ cls : 'clear'
+ });
+
+ cfg.cn[0].cn = bullets;
+ }
}
- if(store){
-
- store.on("datachanged", this.refresh, this);
- store.on("add", this.onAdd, this);
- store.on("remove", this.onRemove, this);
- store.on("update", this.onUpdate, this);
- store.on("clear", this.refresh, this);
- store.on("beforeload", this.onBeforeLoad, this);
- store.on("load", this.onLoad, this);
- store.on("loadexception", this.onLoad, this);
+
+ return cfg;
+ },
+
+ initEvents: function()
+ {
+ Roo.log('-------- init events on tab group ---------');
+
+ if(this.bullets > 0 && !Roo.isTouch){
+ this.initBullet();
}
- if(store){
- this.refresh();
+ Roo.log(this);
+
+ if(Roo.isTouch && this.slideOnTouch){
+ this.el.on("touchstart", this.onTouchStart, this);
+ }
+
+ if(this.autoslide){
+ var _this = this;
+
+ this.slideFn = window.setInterval(function() {
+ _this.showPanelNext();
+ }, this.timer);
}
+
},
- /**
- * onbeforeLoad - masks the loading area.
- *
- */
- onBeforeLoad : function(store,opts)
+
+ onTouchStart : function(e, el, o)
{
- //Roo.log('onBeforeLoad');
- if (!opts.add) {
- this.el.update("");
+ if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
+ return;
}
- this.el.mask(this.mask ? this.mask : "Loading" );
+
+ this.showPanelNext();
},
- onLoad : function ()
+
+ getChildContainer : function()
{
- this.el.unmask();
+ return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
},
-
/**
- * Returns the template node the passed child belongs to or null if it doesn't belong to one.
- * @param {HTMLElement} node
- * @return {HTMLElement} The template node
- */
- findItemFromChild : function(node){
- var el = this.dataName ?
- this.el.child('.roo-tpl-' + this.dataName,true) :
- this.el.dom;
-
- if(!node || node.parentNode == el){
- return node;
- }
- var p = node.parentNode;
- while(p && p != el){
- if(p.parentNode == el){
- return p;
- }
- p = p.parentNode;
- }
- return null;
+ * register a Navigation item
+ * @param {Roo.bootstrap.NavItem} the navitem to add
+ */
+ register : function(item)
+ {
+ this.tabs.push( item);
+ item.navId = this.navId; // not really needed..
+
},
-
- /** @ignore */
- onClick : function(e){
- var item = this.findItemFromChild(e.getTarget());
- if(item){
- var index = this.indexOf(item);
- if(this.onItemClick(item, index, e) !== false){
- this.fireEvent("click", this, index, item, e);
+
+ getActivePanel : function()
+ {
+ var r = false;
+ Roo.each(this.tabs, function(t) {
+ if (t.active) {
+ r = t;
+ return false;
}
- }else{
- this.clearSelections();
- }
- },
-
- /** @ignore */
- onContextMenu : function(e){
- var item = this.findItemFromChild(e.getTarget());
- if(item){
- this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
- }
- },
-
- /** @ignore */
- onDblClick : function(e){
- var item = this.findItemFromChild(e.getTarget());
- if(item){
- this.fireEvent("dblclick", this, this.indexOf(item), item, e);
- }
+ return null;
+ });
+ return r;
+
},
-
- onItemClick : function(item, index, e)
+ getPanelByName : function(n)
{
- if(this.fireEvent("beforeclick", this, index, item, e) === false){
- return false;
- }
- if (this.toggleSelect) {
- var m = this.isSelected(item) ? 'unselect' : 'select';
- //Roo.log(m);
- var _t = this;
- _t[m](item, true, false);
- return true;
- }
- if(this.multiSelect || this.singleSelect){
- if(this.multiSelect && e.shiftKey && this.lastSelection){
- this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
- }else{
- this.select(item, this.multiSelect && e.ctrlKey);
- this.lastSelection = item;
- }
-
- if(!this.tickable){
- e.preventDefault();
+ var r = false;
+ Roo.each(this.tabs, function(t) {
+ if (t.tabId == n) {
+ r = t;
+ return false;
}
-
- }
- return true;
- },
-
- /**
- * Get the number of selected nodes.
- * @return {Number}
- */
- getSelectionCount : function(){
- return this.selections.length;
+ return null;
+ });
+ return r;
},
-
- /**
- * Get the currently selected nodes.
- * @return {Array} An array of HTMLElements
- */
- getSelectedNodes : function(){
- return this.selections;
+ indexOfPanel : function(p)
+ {
+ var r = false;
+ Roo.each(this.tabs, function(t,i) {
+ if (t.tabId == p.tabId) {
+ r = i;
+ return false;
+ }
+ return null;
+ });
+ return r;
},
-
/**
- * Get the indexes of the selected nodes.
- * @return {Array}
+ * show a specific panel
+ * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
+ * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
*/
- getSelectedIndexes : function(){
- var indexes = [], s = this.selections;
- for(var i = 0, len = s.length; i < len; i++){
- indexes.push(s[i].nodeIndex);
+ showPanel : function (pan)
+ {
+ if(this.transition){
+ Roo.log("waiting for the transitionend");
+ return;
}
- return indexes;
- },
-
- /**
- * Clear all selections
- * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
- */
- clearSelections : function(suppressEvent){
- if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
- this.cmp.elements = this.selections;
- this.cmp.removeClass(this.selectedClass);
- this.selections = [];
- if(!suppressEvent){
- this.fireEvent("selectionchange", this, this.selections);
- }
+
+ if (typeof(pan) == 'number') {
+ pan = this.tabs[pan];
}
- },
-
- /**
- * Returns true if the passed node is selected
- * @param {HTMLElement/Number} node The node or node index
- * @return {Boolean}
- */
- isSelected : function(node){
- var s = this.selections;
- if(s.length < 1){
- return false;
+ if (typeof(pan) == 'string') {
+ pan = this.getPanelByName(pan);
}
- node = this.getNode(node);
- return s.indexOf(node) !== -1;
- },
-
- /**
- * Selects nodes.
- * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
- * @param {Boolean} keepExisting (optional) true to keep existing selections
- * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
- */
- select : function(nodeInfo, keepExisting, suppressEvent){
- if(nodeInfo instanceof Array){
- if(!keepExisting){
- this.clearSelections(true);
- }
- for(var i = 0, len = nodeInfo.length; i < len; i++){
- this.select(nodeInfo[i], true, true);
- }
- return;
- }
- var node = this.getNode(nodeInfo);
- if(!node || this.isSelected(node)){
- return; // already selected.
+ if (pan.tabId == this.getActivePanel().tabId) {
+ return true;
+ }
+ var cur = this.getActivePanel();
+
+ if (false === cur.fireEvent('beforedeactivate')) {
+ return false;
}
- if(!keepExisting){
- this.clearSelections(true);
+
+ if(this.bullets > 0 && !Roo.isTouch){
+ this.setActiveBullet(this.indexOfPanel(pan));
}
- if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
- Roo.fly(node).addClass(this.selectedClass);
- this.selections.push(node);
- if(!suppressEvent){
- this.fireEvent("selectionchange", this, this.selections);
- }
+ if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
+
+ this.transition = true;
+ var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
+ var lr = dir == 'next' ? 'left' : 'right';
+ pan.el.addClass(dir); // or prev
+ pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
+ cur.el.addClass(lr); // or right
+ pan.el.addClass(lr);
+
+ var _this = this;
+ cur.el.on('transitionend', function() {
+ Roo.log("trans end?");
+
+ pan.el.removeClass([lr,dir]);
+ pan.setActive(true);
+
+ cur.el.removeClass([lr]);
+ cur.setActive(false);
+
+ _this.transition = false;
+
+ }, this, { single: true } );
+
+ return true;
}
+ cur.setActive(false);
+ pan.setActive(true);
+
+ return true;
},
- /**
- * Unselects nodes.
- * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
- * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
- * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
- */
- unselect : function(nodeInfo, keepExisting, suppressEvent)
+ showPanelNext : function()
{
- if(nodeInfo instanceof Array){
- Roo.each(this.selections, function(s) {
- this.unselect(s, nodeInfo);
- }, this);
+ var i = this.indexOfPanel(this.getActivePanel());
+
+ if (i >= this.tabs.length - 1 && !this.autoslide) {
return;
}
- var node = this.getNode(nodeInfo);
- if(!node || !this.isSelected(node)){
- //Roo.log("not selected");
- return; // not selected.
- }
- // fireevent???
- var ns = [];
- Roo.each(this.selections, function(s) {
- if (s == node ) {
- Roo.fly(node).removeClass(this.selectedClass);
-
- return;
- }
- ns.push(s);
- },this);
- this.selections= ns;
- this.fireEvent("selectionchange", this, this.selections);
- },
-
- /**
- * Gets a template node.
- * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
- * @return {HTMLElement} The node or null if it wasn't found
- */
- getNode : function(nodeInfo){
- if(typeof nodeInfo == "string"){
- return document.getElementById(nodeInfo);
- }else if(typeof nodeInfo == "number"){
- return this.nodes[nodeInfo];
- }
- return nodeInfo;
- },
-
- /**
- * Gets a range template nodes.
- * @param {Number} startIndex
- * @param {Number} endIndex
- * @return {Array} An array of nodes
- */
- getNodes : function(start, end){
- var ns = this.nodes;
- start = start || 0;
- end = typeof end == "undefined" ? ns.length - 1 : end;
- var nodes = [];
- if(start <= end){
- for(var i = start; i <= end; i++){
- nodes.push(ns[i]);
- }
- } else{
- for(var i = start; i >= end; i--){
- nodes.push(ns[i]);
- }
- }
- return nodes;
- },
-
- /**
- * Finds the index of the passed node
- * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
- * @return {Number} The index of the node or -1
- */
- indexOf : function(node){
- node = this.getNode(node);
- if(typeof node.nodeIndex == "number"){
- return node.nodeIndex;
- }
- var ns = this.nodes;
- for(var i = 0, len = ns.length; i < len; i++){
- if(ns[i] == node){
- return i;
- }
+ if (i >= this.tabs.length - 1 && this.autoslide) {
+ i = -1;
}
- return -1;
- }
-});
-/*
- * - LGPL
- *
- * based on jquery fullcalendar
- *
- */
-
-Roo.bootstrap = Roo.bootstrap || {};
-/**
- * @class Roo.bootstrap.Calendar
- * @extends Roo.bootstrap.Component
- * Bootstrap Calendar class
- * @cfg {Boolean} loadMask (true|false) default false
- * @cfg {Object} header generate the user specific header of the calendar, default false
-
- * @constructor
- * Create a new Container
- * @param {Object} config The config object
- */
-
-
-
-Roo.bootstrap.Calendar = function(config){
- Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
- this.addEvents({
- /**
- * @event select
- * Fires when a date is selected
- * @param {DatePicker} this
- * @param {Date} date The selected date
- */
- 'select': true,
- /**
- * @event monthchange
- * Fires when the displayed month changes
- * @param {DatePicker} this
- * @param {Date} date The selected month
- */
- 'monthchange': true,
- /**
- * @event evententer
- * Fires when mouse over an event
- * @param {Calendar} this
- * @param {event} Event
- */
- 'evententer': true,
- /**
- * @event eventleave
- * Fires when the mouse leaves an
- * @param {Calendar} this
- * @param {event}
- */
- 'eventleave': true,
- /**
- * @event eventclick
- * Fires when the mouse click an
- * @param {Calendar} this
- * @param {event}
- */
- 'eventclick': true
- });
-
-};
-
-Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
-
- /**
- * @cfg {Number} startDay
- * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
- */
- startDay : 0,
-
- loadMask : false,
+ this.showPanel(this.tabs[i+1]);
+ },
- header : false,
-
- getAutoCreate : function(){
-
+ showPanelPrev : function()
+ {
+ var i = this.indexOfPanel(this.getActivePanel());
- var fc_button = function(name, corner, style, content ) {
- return Roo.apply({},{
- tag : 'span',
- cls : 'fc-button fc-button-'+name+' fc-state-default ' +
- (corner.length ?
- 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
- ''
- ),
- html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
- unselectable: 'on'
- });
- };
+ if (i < 1 && !this.autoslide) {
+ return;
+ }
- var header = {};
+ if (i < 1 && this.autoslide) {
+ i = this.tabs.length;
+ }
- if(!this.header){
- header = {
- tag : 'table',
- cls : 'fc-header',
- style : 'width:100%',
- cn : [
- {
- tag: 'tr',
- cn : [
- {
- tag : 'td',
- cls : 'fc-header-left',
- cn : [
- fc_button('prev', 'left', 'arrow', '‹' ),
- fc_button('next', 'right', 'arrow', '›' ),
- { tag: 'span', cls: 'fc-header-space' },
- fc_button('today', 'left right', '', 'today' ) // neds state disabled..
+ this.showPanel(this.tabs[i-1]);
+ },
+
+ initBullet : function()
+ {
+ if(Roo.isTouch){
+ return;
+ }
+
+ var _this = this;
+
+ for (var i = 0; i < this.bullets; i++){
+ var bullet = this.el.select('.bullet-' + i, true).first();
+ if(!bullet){
+ continue;
+ }
- ]
- },
+ bullet.on('click', (function(e, el, o, ii, t){
- {
- tag : 'td',
- cls : 'fc-header-center',
- cn : [
- {
- tag: 'span',
- cls: 'fc-header-title',
- cn : {
- tag: 'H2',
- html : 'month / year'
- }
- }
+ e.preventDefault();
- ]
- },
- {
- tag : 'td',
- cls : 'fc-header-right',
- cn : [
- /* fc_button('month', 'left', '', 'month' ),
- fc_button('week', '', '', 'week' ),
- fc_button('day', 'right', '', 'day' )
- */
+ _this.showPanel(ii);
- ]
- }
+ if(_this.autoslide && _this.slideFn){
+ clearInterval(_this.slideFn);
+ _this.slideFn = window.setInterval(function() {
+ _this.showPanelNext();
+ }, _this.timer);
+ }
- ]
- }
- ]
- };
+ }).createDelegate(this, [i, bullet], true));
+ }
+ },
+
+ setActiveBullet : function(i)
+ {
+ if(Roo.isTouch){
+ return;
}
- header = this.header;
-
-
- var cal_heads = function() {
- var ret = [];
- // fixme - handle this.
-
- for (var i =0; i < Date.dayNames.length; i++) {
- var d = Date.dayNames[i];
- ret.push({
- tag: 'th',
- cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
- html : d.substring(0,3)
- });
-
- }
- ret[0].cls += ' fc-first';
- ret[6].cls += ' fc-last';
- return ret;
- };
- var cal_cell = function(n) {
- return {
- tag: 'td',
- cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
- cn : [
- {
- cn : [
- {
- cls: 'fc-day-number',
- html: 'D'
- },
- {
- cls: 'fc-day-content',
-
- cn : [
- {
- style: 'position: relative;' // height: 17px;
- }
- ]
- }
-
-
- ]
- }
- ]
-
- }
- };
- var cal_rows = function() {
-
- var ret = [];
- for (var r = 0; r < 6; r++) {
- var row= {
- tag : 'tr',
- cls : 'fc-week',
- cn : []
- };
-
- for (var i =0; i < Date.dayNames.length; i++) {
- var d = Date.dayNames[i];
- row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
+ Roo.each(this.el.select('.bullet', true).elements, function(el){
+ el.removeClass('selected');
+ });
- }
- row.cn[0].cls+=' fc-first';
- row.cn[0].cn[0].style = 'min-height:90px';
- row.cn[6].cls+=' fc-last';
- ret.push(row);
-
- }
- ret[0].cls += ' fc-first';
- ret[4].cls += ' fc-prev-last';
- ret[5].cls += ' fc-last';
- return ret;
-
- };
+ var bullet = this.el.select('.bullet-' + i, true).first();
- var cal_table = {
- tag: 'table',
- cls: 'fc-border-separate',
- style : 'width:100%',
- cellspacing : 0,
- cn : [
- {
- tag: 'thead',
- cn : [
- {
- tag: 'tr',
- cls : 'fc-first fc-last',
- cn : cal_heads()
- }
- ]
- },
- {
- tag: 'tbody',
- cn : cal_rows()
- }
-
- ]
- };
-
- var cfg = {
- cls : 'fc fc-ltr',
- cn : [
- header,
- {
- cls : 'fc-content',
- style : "position: relative;",
- cn : [
- {
- cls : 'fc-view fc-view-month fc-grid',
- style : 'position: relative',
- unselectable : 'on',
- cn : [
- {
- cls : 'fc-event-container',
- style : 'position:absolute;z-index:8;top:0;left:0;'
- },
- cal_table
- ]
- }
- ]
+ if(!bullet){
+ return;
+ }
+
+ bullet.addClass('selected');
+ }
+
+
+
+});
+
+
+
+
+
+Roo.apply(Roo.bootstrap.TabGroup, {
+
+ groups: {},
+ /**
+ * register a Navigation Group
+ * @param {Roo.bootstrap.NavGroup} the navgroup to add
+ */
+ register : function(navgrp)
+ {
+ this.groups[navgrp.navId] = navgrp;
+
+ },
+ /**
+ * fetch a Navigation Group based on the navigation ID
+ * if one does not exist , it will get created.
+ * @param {string} the navgroup to add
+ * @returns {Roo.bootstrap.NavGroup} the navgroup
+ */
+ get: function(navId) {
+ if (typeof(this.groups[navId]) == 'undefined') {
+ this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
+ }
+ return this.groups[navId] ;
+ }
+
+
+
+});
+
+ /*
+ * - LGPL
+ *
+ * TabPanel
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.TabPanel
+ * @extends Roo.bootstrap.Component
+ * Bootstrap TabPanel class
+ * @cfg {Boolean} active panel active
+ * @cfg {String} html panel content
+ * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
+ * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
+ *
+ *
+ * @constructor
+ * Create a new TabPanel
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.TabPanel = function(config){
+ Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
+ this.addEvents({
+ /**
+ * @event changed
+ * Fires when the active status changes
+ * @param {Roo.bootstrap.TabPanel} this
+ * @param {Boolean} state the new state
+
+ */
+ 'changed': true,
+ /**
+ * @event beforedeactivate
+ * Fires before a tab is de-activated - can be used to do validation on a form.
+ * @param {Roo.bootstrap.TabPanel} this
+ * @return {Boolean} false if there is an error
+
+ */
+ 'beforedeactivate': true
+ });
- }
- ]
-
+ this.tabId = this.tabId || Roo.id();
+
+};
+
+Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
+
+ active: false,
+ html: false,
+ tabId: false,
+ navId : false,
+
+ getAutoCreate : function(){
+ var cfg = {
+ tag: 'div',
+ // item is needed for carousel - not sure if it has any effect otherwise
+ cls: 'tab-pane item',
+ html: this.html || ''
};
-
+ if(this.active){
+ cfg.cls += ' active';
+ }
+
+ if(this.tabId){
+ cfg.tabId = this.tabId;
+ }
+
return cfg;
},
-
- initEvents : function()
+ initEvents: function()
{
- if(!this.store){
- throw "can not find store for calendar";
- }
+ Roo.log('-------- init events on tab panel ---------');
- var mark = {
- tag: "div",
- cls:"x-dlg-mask",
- style: "text-align:center",
- cn: [
- {
- tag: "div",
- style: "background-color:white;width:50%;margin:250 auto",
- cn: [
- {
- tag: "img",
- src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
- },
- {
- tag: "span",
- html: "Loading"
- }
-
- ]
- }
- ]
- }
- this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
+ var p = this.parent();
+ this.navId = this.navId || p.navId;
- var size = this.el.select('.fc-content', true).first().getSize();
- this.maskEl.setSize(size.width, size.height);
- this.maskEl.enableDisplayMode("block");
- if(!this.loadMask){
- this.maskEl.hide();
+ if (typeof(this.navId) != 'undefined') {
+ // not really needed.. but just in case.. parent should be a NavGroup.
+ var tg = Roo.bootstrap.TabGroup.get(this.navId);
+ Roo.log(['register', tg, this]);
+ tg.register(this);
+
+ var i = tg.tabs.length - 1;
+
+ if(this.active && tg.bullets > 0 && i < tg.bullets){
+ tg.setActiveBullet(i);
+ }
}
- this.store = Roo.factory(this.store, Roo.data);
- this.store.on('load', this.onLoad, this);
- this.store.on('beforeload', this.onBeforeLoad, this);
+ },
+
+
+ onRender : function(ct, position)
+ {
+ // Roo.log("Call onRender: " + this.xtype);
+
+ Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
- this.resize();
- this.cells = this.el.select('.fc-day',true);
- //Roo.log(this.cells);
- this.textNodes = this.el.query('.fc-day-number');
- this.cells.addClassOnOver('fc-state-hover');
- this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
- this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
- this.el.select('.fc-button-today',true).on('click', this.showToday, this);
- this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
- this.on('monthchange', this.onMonthChange, this);
- this.update(new Date().clearTime());
},
- resize : function() {
- var sz = this.el.getSize();
+ setActive: function(state)
+ {
+ Roo.log("panel - set active " + this.tabId + "=" + state);
- this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
- this.el.select('.fc-day-content div',true).setHeight(34);
- },
+ this.active = state;
+ if (!state) {
+ this.el.removeClass('active');
+
+ } else if (!this.el.hasClass('active')) {
+ this.el.addClass('active');
+ }
+
+ this.fireEvent('changed', this, state);
+ }
- // private
- showPrevMonth : function(e){
- this.update(this.activeDate.add("mo", -1));
+});
+
+
+
+
+ /*
+ * - LGPL
+ *
+ * DateField
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.DateField
+ * @extends Roo.bootstrap.Input
+ * Bootstrap DateField class
+ * @cfg {Number} weekStart default 0
+ * @cfg {String} viewMode default empty, (months|years)
+ * @cfg {String} minViewMode default empty, (months|years)
+ * @cfg {Number} startDate default -Infinity
+ * @cfg {Number} endDate default Infinity
+ * @cfg {Boolean} todayHighlight default false
+ * @cfg {Boolean} todayBtn default false
+ * @cfg {Boolean} calendarWeeks default false
+ * @cfg {Object} daysOfWeekDisabled default empty
+ * @cfg {Boolean} singleMode default false (true | false)
+ *
+ * @cfg {Boolean} keyboardNavigation default true
+ * @cfg {String} language default en
+ *
+ * @constructor
+ * Create a new DateField
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.DateField = function(config){
+ Roo.bootstrap.DateField.superclass.constructor.call(this, config);
+ this.addEvents({
+ /**
+ * @event show
+ * Fires when this field show.
+ * @param {Roo.bootstrap.DateField} this
+ * @param {Mixed} date The date value
+ */
+ show : true,
+ /**
+ * @event show
+ * Fires when this field hide.
+ * @param {Roo.bootstrap.DateField} this
+ * @param {Mixed} date The date value
+ */
+ hide : true,
+ /**
+ * @event select
+ * Fires when select a date.
+ * @param {Roo.bootstrap.DateField} this
+ * @param {Mixed} date The date value
+ */
+ select : true
+ });
+};
+
+Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
+
+ /**
+ * @cfg {String} format
+ * The default date format string which can be overriden for localization support. The format must be
+ * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
+ */
+ format : "m/d/y",
+ /**
+ * @cfg {String} altFormats
+ * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
+ * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
+ */
+ altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
+
+ weekStart : 0,
+
+ viewMode : '',
+
+ minViewMode : '',
+
+ todayHighlight : false,
+
+ todayBtn: false,
+
+ language: 'en',
+
+ keyboardNavigation: true,
+
+ calendarWeeks: false,
+
+ startDate: -Infinity,
+
+ endDate: Infinity,
+
+ daysOfWeekDisabled: [],
+
+ _events: [],
+
+ singleMode : false,
+
+ UTCDate: function()
+ {
+ return new Date(Date.UTC.apply(Date, arguments));
},
- showToday : function(e){
- this.update(new Date().clearTime());
+
+ UTCToday: function()
+ {
+ var today = new Date();
+ return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
},
- // private
- showNextMonth : function(e){
- this.update(this.activeDate.add("mo", 1));
+
+ getDate: function() {
+ var d = this.getUTCDate();
+ return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
},
-
- // private
- showPrevYear : function(){
- this.update(this.activeDate.add("y", -1));
+
+ getUTCDate: function() {
+ return this.date;
},
-
- // private
- showNextYear : function(){
- this.update(this.activeDate.add("y", 1));
+
+ setDate: function(d) {
+ this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
},
-
- // private
- update : function(date)
+ setUTCDate: function(d) {
+ this.date = d;
+ this.setValue(this.formatDate(this.date));
+ },
+
+ onRender: function(ct, position)
{
- var vd = this.activeDate;
- this.activeDate = date;
-// if(vd && this.el){
-// var t = date.getTime();
-// if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
-// Roo.log('using add remove');
-//
-// this.fireEvent('monthchange', this, date);
-//
-// this.cells.removeClass("fc-state-highlight");
-// this.cells.each(function(c){
-// if(c.dateValue == t){
-// c.addClass("fc-state-highlight");
-// setTimeout(function(){
-// try{c.dom.firstChild.focus();}catch(e){}
-// }, 50);
-// return false;
-// }
-// return true;
-// });
-// return;
-// }
-// }
- var days = date.getDaysInMonth();
+ Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
- var firstOfMonth = date.getFirstDateOfMonth();
- var startingPos = firstOfMonth.getDay()-this.startDay;
+ this.language = this.language || 'en';
+ this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
+ this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
- if(startingPos < this.startDay){
- startingPos += 7;
+ this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
+ this.format = this.format || 'm/d/y';
+ this.isInline = false;
+ this.isInput = true;
+ this.component = this.el.select('.add-on', true).first() || false;
+ this.component = (this.component && this.component.length === 0) ? false : this.component;
+ this.hasInput = this.component && this.inputEL().length;
+
+ if (typeof(this.minViewMode === 'string')) {
+ switch (this.minViewMode) {
+ case 'months':
+ this.minViewMode = 1;
+ break;
+ case 'years':
+ this.minViewMode = 2;
+ break;
+ default:
+ this.minViewMode = 0;
+ break;
+ }
}
- var pm = date.add(Date.MONTH, -1);
- var prevStart = pm.getDaysInMonth()-startingPos;
-//
- this.cells = this.el.select('.fc-day',true);
- this.textNodes = this.el.query('.fc-day-number');
- this.cells.addClassOnOver('fc-state-hover');
+ if (typeof(this.viewMode === 'string')) {
+ switch (this.viewMode) {
+ case 'months':
+ this.viewMode = 1;
+ break;
+ case 'years':
+ this.viewMode = 2;
+ break;
+ default:
+ this.viewMode = 0;
+ break;
+ }
+ }
+
+ this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
- var cells = this.cells.elements;
- var textEls = this.textNodes;
+// this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
- Roo.each(cells, function(cell){
- cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
- });
+ this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- days += startingPos;
-
- // convert everything to numbers so it's fast
- var day = 86400000;
- var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
- //Roo.log(d);
- //Roo.log(pm);
- //Roo.log(prevStart);
+ this.picker().on('mousedown', this.onMousedown, this);
+ this.picker().on('click', this.onClick, this);
- var today = new Date().clearTime().getTime();
- var sel = date.clearTime().getTime();
- var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
- var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
- var ddMatch = this.disabledDatesRE;
- var ddText = this.disabledDatesText;
- var ddays = this.disabledDays ? this.disabledDays.join("") : false;
- var ddaysText = this.disabledDaysText;
- var format = this.format;
+ this.picker().addClass('datepicker-dropdown');
- var setCellClass = function(cal, cell){
- cell.row = 0;
- cell.events = [];
- cell.more = [];
- //Roo.log('set Cell Class');
- cell.title = "";
- var t = d.getTime();
-
- //Roo.log(d);
+ this.startViewMode = this.viewMode;
+
+ if(this.singleMode){
+ Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
+ v.setVisibilityMode(Roo.Element.DISPLAY)
+ v.hide();
+ });
- cell.dateValue = t;
- if(t == today){
- cell.className += " fc-today";
- cell.className += " fc-state-highlight";
- cell.title = cal.todayText;
- }
- if(t == sel){
- // disable highlight in other month..
- //cell.className += " fc-state-highlight";
-
- }
- // disabling
- if(t < min) {
- cell.className = " fc-state-disabled";
- cell.title = cal.minText;
- return;
- }
- if(t > max) {
- cell.className = " fc-state-disabled";
- cell.title = cal.maxText;
+ Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
+ v.setStyle('width', '189px');
+ });
+ }
+
+ Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
+ if(!this.calendarWeeks){
+ v.remove();
return;
}
- if(ddays){
- if(ddays.indexOf(d.getDay()) != -1){
- cell.title = ddaysText;
- cell.className = " fc-state-disabled";
- }
- }
- if(ddMatch && format){
- var fvalue = d.dateFormat(format);
- if(ddMatch.test(fvalue)){
- cell.title = ddText.replace("%0", fvalue);
- cell.className = " fc-state-disabled";
- }
- }
- if (!cell.initialClassName) {
- cell.initialClassName = cell.dom.className;
- }
-
- cell.dom.className = cell.initialClassName + ' ' + cell.className;
- };
-
- var i = 0;
+ v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
+ v.attr('colspan', function(i, val){
+ return parseInt(val) + 1;
+ });
+ })
+
- for(; i < startingPos; i++) {
- textEls[i].innerHTML = (++prevStart);
- d.setDate(d.getDate()+1);
-
- cells[i].className = "fc-past fc-other-month";
- setCellClass(this, cells[i]);
- }
+ this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
- var intDay = 0;
+ this.setStartDate(this.startDate);
+ this.setEndDate(this.endDate);
- for(; i < days; i++){
- intDay = i - startingPos + 1;
- textEls[i].innerHTML = (intDay);
- d.setDate(d.getDate()+1);
-
- cells[i].className = ''; // "x-date-active";
- setCellClass(this, cells[i]);
- }
- var extraDays = 0;
+ this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
- for(; i < 42; i++) {
- textEls[i].innerHTML = (++extraDays);
- d.setDate(d.getDate()+1);
-
- cells[i].className = "fc-future fc-other-month";
- setCellClass(this, cells[i]);
- }
+ this.fillDow();
+ this.fillMonths();
+ this.update();
+ this.showMode();
- this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
+ if(this.isInline) {
+ this.show();
+ }
+ },
+
+ picker : function()
+ {
+ return this.pickerEl;
+// return this.el.select('.datepicker', true).first();
+ },
+
+ fillDow: function()
+ {
+ var dowCnt = this.weekStart;
- var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
+ var dow = {
+ tag: 'tr',
+ cn: [
+
+ ]
+ };
- this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
- this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
+ if(this.calendarWeeks){
+ dow.cn.push({
+ tag: 'th',
+ cls: 'cw',
+ html: ' '
+ })
+ }
- if(totalRows != 6){
- this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
- this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
+ while (dowCnt < this.weekStart + 7) {
+ dow.cn.push({
+ tag: 'th',
+ cls: 'dow',
+ html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
+ });
}
- this.fireEvent('monthchange', this, date);
+ this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
+ },
+
+ fillMonths: function()
+ {
+ var i = 0;
+ var months = this.picker().select('>.datepicker-months td', true).first();
+ months.dom.innerHTML = '';
- /*
- if(!this.internalRender){
- var main = this.el.dom.firstChild;
- var w = main.offsetWidth;
- this.el.setWidth(w + this.el.getBorderWidth("lr"));
- Roo.fly(main).setWidth(w);
- this.internalRender = true;
- // opera does not respect the auto grow header center column
- // then, after it gets a width opera refuses to recalculate
- // without a second pass
- if(Roo.isOpera && !this.secondPass){
- main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
- this.secondPass = true;
- this.update.defer(10, this, [date]);
+ while (i < 12) {
+ var month = {
+ tag: 'span',
+ cls: 'month',
+ html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
}
+
+ months.createChild(month);
}
- */
},
- findCell : function(dt) {
- dt = dt.clearTime().getTime();
- var ret = false;
- this.cells.each(function(c){
- //Roo.log("check " +c.dateValue + '?=' + dt);
- if(c.dateValue == dt){
- ret = c;
- return false;
- }
- return true;
- });
+ update: function()
+ {
+ this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
- return ret;
- },
-
- findCells : function(ev) {
- var s = ev.start.clone().clearTime().getTime();
- // Roo.log(s);
- var e= ev.end.clone().clearTime().getTime();
- // Roo.log(e);
- var ret = [];
- this.cells.each(function(c){
- ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
-
- if(c.dateValue > e){
- return ;
- }
- if(c.dateValue < s){
- return ;
- }
- ret.push(c);
- });
+ if (this.date < this.startDate) {
+ this.viewDate = new Date(this.startDate);
+ } else if (this.date > this.endDate) {
+ this.viewDate = new Date(this.endDate);
+ } else {
+ this.viewDate = new Date(this.date);
+ }
- return ret;
+ this.fill();
},
-// findBestRow: function(cells)
-// {
-// var ret = 0;
-//
-// for (var i =0 ; i < cells.length;i++) {
-// ret = Math.max(cells[i].rows || 0,ret);
-// }
-// return ret;
-//
-// },
-
-
- addItem : function(ev)
+ fill: function()
{
- // look for vertical location slot in
- var cells = this.findCells(ev);
+ var d = new Date(this.viewDate),
+ year = d.getUTCFullYear(),
+ month = d.getUTCMonth(),
+ startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
+ startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
+ endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
+ endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
+ currentDate = this.date && this.date.valueOf(),
+ today = this.UTCToday();
-// ev.row = this.findBestRow(cells);
+ this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
- // work out the location.
+// this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
- var crow = false;
- var rows = [];
- for(var i =0; i < cells.length; i++) {
+// this.picker.select('>tfoot th.today').
+// .text(dates[this.language].today)
+// .toggle(this.todayBtn !== false);
+
+ this.updateNavArrows();
+ this.fillMonths();
+
+ var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
+
+ day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
+
+ prevMonth.setUTCDate(day);
+
+ prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
+
+ var nextMonth = new Date(prevMonth);
+
+ nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
+
+ nextMonth = nextMonth.valueOf();
+
+ var fillMonths = false;
+
+ this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
+
+ while(prevMonth.valueOf() < nextMonth) {
+ var clsName = '';
- cells[i].row = cells[0].row;
+ if (prevMonth.getUTCDay() === this.weekStart) {
+ if(fillMonths){
+ this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
+ }
+
+ fillMonths = {
+ tag: 'tr',
+ cn: []
+ };
+
+ if(this.calendarWeeks){
+ // ISO 8601: First week contains first thursday.
+ // ISO also states week starts on Monday, but we can be more abstract here.
+ var
+ // Start of current week: based on weekstart/current date
+ ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
+ // Thursday of this week
+ th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
+ // First Thursday of year, year from thursday
+ yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
+ // Calendar week: ms between thursdays, div ms per day, div 7 days
+ calWeek = (th - yth) / 864e5 / 7 + 1;
+
+ fillMonths.cn.push({
+ tag: 'td',
+ cls: 'cw',
+ html: calWeek
+ });
+ }
+ }
- if(i == 0){
- cells[i].row = cells[i].row + 1;
+ if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
+ clsName += ' old';
+ } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
+ clsName += ' new';
+ }
+ if (this.todayHighlight &&
+ prevMonth.getUTCFullYear() == today.getFullYear() &&
+ prevMonth.getUTCMonth() == today.getMonth() &&
+ prevMonth.getUTCDate() == today.getDate()) {
+ clsName += ' today';
}
- if (!crow) {
- crow = {
- start : cells[i],
- end : cells[i]
- };
- continue;
+ if (currentDate && prevMonth.valueOf() === currentDate) {
+ clsName += ' active';
}
- if (crow.start.getY() == cells[i].getY()) {
- // on same row.
- crow.end = cells[i];
- continue;
+
+ if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
+ this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
+ clsName += ' disabled';
}
- // different row.
- rows.push(crow);
- crow = {
- start: cells[i],
- end : cells[i]
- };
+ fillMonths.cn.push({
+ tag: 'td',
+ cls: 'day ' + clsName,
+ html: prevMonth.getDate()
+ })
+
+ prevMonth.setDate(prevMonth.getDate()+1);
}
+
+ var currentYear = this.date && this.date.getUTCFullYear();
+ var currentMonth = this.date && this.date.getUTCMonth();
- rows.push(crow);
- ev.els = [];
- ev.rows = rows;
- ev.cells = cells;
+ this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
- cells[0].events.push(ev);
+ Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
+ v.removeClass('active');
+
+ if(currentYear === year && k === currentMonth){
+ v.addClass('active');
+ }
+
+ if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
+ v.addClass('disabled');
+ }
+
+ });
+
+
+ year = parseInt(year/10, 10) * 10;
+
+ this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
+
+ this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
+
+ year -= 1;
+ for (var i = -1; i < 11; i++) {
+ this.picker().select('>.datepicker-years tbody td',true).first().createChild({
+ tag: 'span',
+ cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
+ html: year
+ })
+
+ year += 1;
+ }
+ },
+
+ showMode: function(dir)
+ {
+ if (dir) {
+ this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
+ }
- this.calevents.push(ev);
+ Roo.each(this.picker().select('>div',true).elements, function(v){
+ v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ v.hide();
+ });
+ this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
},
- clearEvents: function() {
+ place: function()
+ {
+ if(this.isInline) return;
- if(!this.calevents){
+ this.picker().removeClass(['bottom', 'top']);
+
+ if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
+ /*
+ * place to the top of element!
+ *
+ */
+
+ this.picker().addClass('top');
+ this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+
return;
}
- Roo.each(this.cells.elements, function(c){
- c.row = 0;
- c.events = [];
- c.more = [];
- });
-
- Roo.each(this.calevents, function(e) {
- Roo.each(e.els, function(el) {
- el.un('mouseenter' ,this.onEventEnter, this);
- el.un('mouseleave' ,this.onEventLeave, this);
- el.remove();
- },this);
- },this);
-
- Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
- e.remove();
- });
+ this.picker().addClass('bottom');
+ this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
},
- renderEvents: function()
- {
- var _this = this;
-
- this.cells.each(function(c) {
-
- if(c.row < 5){
- return;
- }
-
- var ev = c.events;
-
- var r = 4;
- if(c.row != c.events.length){
- r = 4 - (4 - (c.row - c.events.length));
- }
-
- c.events = ev.slice(0, r);
- c.more = ev.slice(r);
-
- if(c.more.length && c.more.length == 1){
- c.events.push(c.more.pop());
- }
-
- c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
-
- });
-
- this.cells.each(function(c) {
-
- c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
-
-
- for (var e = 0; e < c.events.length; e++){
- var ev = c.events[e];
- var rows = ev.rows;
-
- for(var i = 0; i < rows.length; i++) {
-
- // how many rows should it span..
-
- var cfg = {
- cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
- style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
-
- unselectable : "on",
- cn : [
- {
- cls: 'fc-event-inner',
- cn : [
- // {
- // tag:'span',
- // cls: 'fc-event-time',
- // html : cells.length > 1 ? '' : ev.time
- // },
- {
- tag:'span',
- cls: 'fc-event-title',
- html : String.format('{0}', ev.title)
- }
-
-
- ]
- },
- {
- cls: 'ui-resizable-handle ui-resizable-e',
- html : '  '
- }
-
- ]
- };
-
- if (i == 0) {
- cfg.cls += ' fc-event-start';
- }
- if ((i+1) == rows.length) {
- cfg.cls += ' fc-event-end';
- }
-
- var ctr = _this.el.select('.fc-event-container',true).first();
- var cg = ctr.createChild(cfg);
-
- var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
- var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
-
- var r = (c.more.length) ? 1 : 0;
- cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
- cg.setWidth(ebox.right - sbox.x -2);
-
- cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
- cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
- cg.on('click', _this.onEventClick, _this, ev);
-
- ev.els.push(cg);
-
- }
-
+ parseDate : function(value)
+ {
+ if(!value || value instanceof Date){
+ return value;
+ }
+ var v = Date.parseDate(value, this.format);
+ if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
+ v = Date.parseDate(value, 'Y-m-d');
+ }
+ if(!v && this.altFormats){
+ if(!this.altFormatsArray){
+ this.altFormatsArray = this.altFormats.split("|");
}
-
-
- if(c.more.length){
- var cfg = {
- cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
- style : 'position: absolute',
- unselectable : "on",
- cn : [
- {
- cls: 'fc-event-inner',
- cn : [
- {
- tag:'span',
- cls: 'fc-event-title',
- html : 'More'
- }
-
-
- ]
- },
- {
- cls: 'ui-resizable-handle ui-resizable-e',
- html : '  '
- }
-
- ]
- };
-
- var ctr = _this.el.select('.fc-event-container',true).first();
- var cg = ctr.createChild(cfg);
-
- var sbox = c.select('.fc-day-content',true).first().getBox();
- var ebox = c.select('.fc-day-content',true).first().getBox();
- //Roo.log(cg);
- cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
- cg.setWidth(ebox.right - sbox.x -2);
-
- cg.on('click', _this.onMoreEventClick, _this, c.more);
-
+ for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
+ v = Date.parseDate(value, this.altFormatsArray[i]);
}
-
- });
-
+ }
+ return v;
+ },
+
+ formatDate : function(date, fmt)
+ {
+ return (!date || !(date instanceof Date)) ?
+ date : date.dateFormat(fmt || this.format);
+ },
+
+ onFocus : function()
+ {
+ Roo.bootstrap.DateField.superclass.onFocus.call(this);
+ this.show();
+ },
+
+ onBlur : function()
+ {
+ Roo.bootstrap.DateField.superclass.onBlur.call(this);
+ var d = this.inputEl().getValue();
+ this.setValue(d);
+
+ this.hide();
},
- onEventEnter: function (e, el,event,d) {
- this.fireEvent('evententer', this, el, event);
+ show : function()
+ {
+ this.picker().show();
+ this.update();
+ this.place();
+
+ this.fireEvent('show', this, this.date);
},
- onEventLeave: function (e, el,event,d) {
- this.fireEvent('eventleave', this, el, event);
+ hide : function()
+ {
+ if(this.isInline) return;
+ this.picker().hide();
+ this.viewMode = this.startViewMode;
+ this.showMode();
+
+ this.fireEvent('hide', this, this.date);
+
},
- onEventClick: function (e, el,event,d) {
- this.fireEvent('eventclick', this, el, event);
+ onMousedown: function(e)
+ {
+ e.stopPropagation();
+ e.preventDefault();
},
- onMonthChange: function () {
- this.store.load();
+ keyup: function(e)
+ {
+ Roo.bootstrap.DateField.superclass.keyup.call(this);
+ this.update();
},
-
- onMoreEventClick: function(e, el, more)
+
+ setValue: function(v)
{
- var _this = this;
- this.calpopover.placement = 'right';
- this.calpopover.setTitle('More');
+ // v can be a string or a date..
+
- this.calpopover.setContent('');
+ var d = new Date(this.parseDate(v) ).clearTime();
- var ctr = this.calpopover.el.select('.popover-content', true).first();
+ if(isNaN(d.getTime())){
+ this.date = this.viewDate = '';
+ Roo.bootstrap.DateField.superclass.setValue.call(this, '');
+ return;
+ }
- Roo.each(more, function(m){
- var cfg = {
- cls : 'fc-event-hori fc-event-draggable',
- html : m.title
- }
- var cg = ctr.createChild(cfg);
-
- cg.on('click', _this.onEventClick, _this, m);
- });
+ v = this.formatDate(d);
- this.calpopover.show(el);
+ Roo.bootstrap.DateField.superclass.setValue.call(this, v);
+ this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
+
+ this.update();
+
+ this.fireEvent('select', this, this.date);
},
- onLoad: function ()
- {
- this.calevents = [];
- var cal = this;
-
- if(this.store.getCount() > 0){
- this.store.data.each(function(d){
- cal.addItem({
- id : d.data.id,
- start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
- end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
- time : d.data.start_time,
- title : d.data.title,
- description : d.data.description,
- venue : d.data.venue
- });
- });
+ getValue: function()
+ {
+ return this.formatDate(this.date);
+ },
+
+ fireKey: function(e)
+ {
+ if (!this.picker().isVisible()){
+ if (e.keyCode == 27) // allow escape to hide and re-show picker
+ this.show();
+ return;
}
- this.renderEvents();
+ var dateChanged = false,
+ dir, day, month,
+ newDate, newViewDate;
- if(this.calevents.length && this.loadMask){
- this.maskEl.hide();
+ switch(e.keyCode){
+ case 27: // escape
+ this.hide();
+ e.preventDefault();
+ break;
+ case 37: // left
+ case 39: // right
+ if (!this.keyboardNavigation) break;
+ dir = e.keyCode == 37 ? -1 : 1;
+
+ if (e.ctrlKey){
+ newDate = this.moveYear(this.date, dir);
+ newViewDate = this.moveYear(this.viewDate, dir);
+ } else if (e.shiftKey){
+ newDate = this.moveMonth(this.date, dir);
+ newViewDate = this.moveMonth(this.viewDate, dir);
+ } else {
+ newDate = new Date(this.date);
+ newDate.setUTCDate(this.date.getUTCDate() + dir);
+ newViewDate = new Date(this.viewDate);
+ newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
+ }
+ if (this.dateWithinRange(newDate)){
+ this.date = newDate;
+ this.viewDate = newViewDate;
+ this.setValue(this.formatDate(this.date));
+// this.update();
+ e.preventDefault();
+ dateChanged = true;
+ }
+ break;
+ case 38: // up
+ case 40: // down
+ if (!this.keyboardNavigation) break;
+ dir = e.keyCode == 38 ? -1 : 1;
+ if (e.ctrlKey){
+ newDate = this.moveYear(this.date, dir);
+ newViewDate = this.moveYear(this.viewDate, dir);
+ } else if (e.shiftKey){
+ newDate = this.moveMonth(this.date, dir);
+ newViewDate = this.moveMonth(this.viewDate, dir);
+ } else {
+ newDate = new Date(this.date);
+ newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
+ newViewDate = new Date(this.viewDate);
+ newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
+ }
+ if (this.dateWithinRange(newDate)){
+ this.date = newDate;
+ this.viewDate = newViewDate;
+ this.setValue(this.formatDate(this.date));
+// this.update();
+ e.preventDefault();
+ dateChanged = true;
+ }
+ break;
+ case 13: // enter
+ this.setValue(this.formatDate(this.date));
+ this.hide();
+ e.preventDefault();
+ break;
+ case 9: // tab
+ this.setValue(this.formatDate(this.date));
+ this.hide();
+ break;
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ break;
+ default :
+ this.hide();
+
}
},
- onBeforeLoad: function()
- {
- this.clearEvents();
- if(this.loadMask){
- this.maskEl.show();
- }
- }
-});
-
-
- /*
- * - LGPL
- *
- * element
- *
- */
-
-/**
- * @class Roo.bootstrap.Popover
- * @extends Roo.bootstrap.Component
- * Bootstrap Popover class
- * @cfg {String} html contents of the popover (or false to use children..)
- * @cfg {String} title of popover (or false to hide)
- * @cfg {String} placement how it is placed
- * @cfg {String} trigger click || hover (or false to trigger manually)
- * @cfg {String} over what (parent or false to trigger manually.)
- * @cfg {Number} delay - delay before showing
-
- * @constructor
- * Create a new Popover
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.Popover = function(config){
- Roo.bootstrap.Popover.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
-
- title: 'Fill in a title',
- html: false,
-
- placement : 'right',
- trigger : 'hover', // hover
-
- delay : 0,
-
- over: 'parent',
-
- can_build_overlaid : false,
- getChildContainer : function()
+ onClick: function(e)
{
- return this.el.select('.popover-content',true).first();
- },
-
- getAutoCreate : function(){
- Roo.log('make popover?');
- var cfg = {
- cls : 'popover roo-dynamic',
- style: 'display:block',
- cn : [
- {
- cls : 'arrow'
- },
- {
- cls : 'popover-inner',
- cn : [
- {
- tag: 'h3',
- cls: 'popover-title',
- html : this.title
- },
- {
- cls : 'popover-content',
- html : this.html
+ e.stopPropagation();
+ e.preventDefault();
+
+ var target = e.getTarget();
+
+ if(target.nodeName.toLowerCase() === 'i'){
+ target = Roo.get(target).dom.parentNode;
+ }
+
+ var nodeName = target.nodeName;
+ var className = target.className;
+ var html = target.innerHTML;
+ //Roo.log(nodeName);
+
+ switch(nodeName.toLowerCase()) {
+ case 'th':
+ switch(className) {
+ case 'switch':
+ this.showMode(1);
+ break;
+ case 'prev':
+ case 'next':
+ var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
+ switch(this.viewMode){
+ case 0:
+ this.viewDate = this.moveMonth(this.viewDate, dir);
+ break;
+ case 1:
+ case 2:
+ this.viewDate = this.moveYear(this.viewDate, dir);
+ break;
}
- ]
+ this.fill();
+ break;
+ case 'today':
+ var date = new Date();
+ this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
+// this.fill()
+ this.setValue(this.formatDate(this.date));
+
+ this.hide();
+ break;
+ }
+ break;
+ case 'span':
+ if (className.indexOf('disabled') < 0) {
+ this.viewDate.setUTCDate(1);
+ if (className.indexOf('month') > -1) {
+ this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
+ } else {
+ var year = parseInt(html, 10) || 0;
+ this.viewDate.setUTCFullYear(year);
+
+ }
+
+ if(this.singleMode){
+ this.setValue(this.formatDate(this.viewDate));
+ this.hide();
+ return;
+ }
+ this.showMode(-1);
+ this.fill();
}
- ]
- };
-
- return cfg;
+ break;
+
+ case 'td':
+ //Roo.log(className);
+ if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
+ var day = parseInt(html, 10) || 1;
+ var year = this.viewDate.getUTCFullYear(),
+ month = this.viewDate.getUTCMonth();
+
+ if (className.indexOf('old') > -1) {
+ if(month === 0 ){
+ month = 11;
+ year -= 1;
+ }else{
+ month -= 1;
+ }
+ } else if (className.indexOf('new') > -1) {
+ if (month == 11) {
+ month = 0;
+ year += 1;
+ } else {
+ month += 1;
+ }
+ }
+ //Roo.log([year,month,day]);
+ this.date = this.UTCDate(year, month, day,0,0,0,0);
+ this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
+// this.fill();
+ //Roo.log(this.formatDate(this.date));
+ this.setValue(this.formatDate(this.date));
+ this.hide();
+ }
+ break;
+ }
},
- setTitle: function(str)
+
+ setStartDate: function(startDate)
{
- this.el.select('.popover-title',true).first().dom.innerHTML = str;
+ this.startDate = startDate || -Infinity;
+ if (this.startDate !== -Infinity) {
+ this.startDate = this.parseDate(this.startDate);
+ }
+ this.update();
+ this.updateNavArrows();
},
- setContent: function(str)
+
+ setEndDate: function(endDate)
{
- this.el.select('.popover-content',true).first().dom.innerHTML = str;
+ this.endDate = endDate || Infinity;
+ if (this.endDate !== Infinity) {
+ this.endDate = this.parseDate(this.endDate);
+ }
+ this.update();
+ this.updateNavArrows();
},
- // as it get's added to the bottom of the page.
- onRender : function(ct, position)
+
+ setDaysOfWeekDisabled: function(daysOfWeekDisabled)
{
- Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
- if(!this.el){
- var cfg = Roo.apply({}, this.getAutoCreate());
- cfg.id = Roo.id();
-
- if (this.cls) {
- cfg.cls += ' ' + this.cls;
- }
- if (this.style) {
- cfg.style = this.style;
- }
- Roo.log("adding to ")
- this.el = Roo.get(document.body).createChild(cfg, position);
- Roo.log(this.el);
+ this.daysOfWeekDisabled = daysOfWeekDisabled || [];
+ if (typeof(this.daysOfWeekDisabled) !== 'object') {
+ this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
}
- this.initEvents();
+ this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
+ return parseInt(d, 10);
+ });
+ this.update();
+ this.updateNavArrows();
},
- initEvents : function()
+ updateNavArrows: function()
{
- this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
- this.el.enableDisplayMode('block');
- this.el.hide();
- if (this.over === false) {
- return;
- }
- if (this.triggers === false) {
+ if(this.singleMode){
return;
}
- var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
- var triggers = this.trigger ? this.trigger.split(' ') : [];
- Roo.each(triggers, function(trigger) {
- if (trigger == 'click') {
- on_el.on('click', this.toggle, this);
- } else if (trigger != 'manual') {
- var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
- var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
-
- on_el.on(eventIn ,this.enter, this);
- on_el.on(eventOut, this.leave, this);
- }
- }, this);
+ var d = new Date(this.viewDate),
+ year = d.getUTCFullYear(),
+ month = d.getUTCMonth();
- },
-
-
- // private
- timeout : null,
- hoverState : null,
-
- toggle : function () {
- this.hoverState == 'in' ? this.leave() : this.enter();
- },
-
- enter : function () {
-
-
- clearTimeout(this.timeout);
-
- this.hoverState = 'in';
-
- if (!this.delay || !this.delay.show) {
- this.show();
- return;
- }
- var _t = this;
- this.timeout = setTimeout(function () {
- if (_t.hoverState == 'in') {
- _t.show();
+ Roo.each(this.picker().select('.prev', true).elements, function(v){
+ v.show();
+ switch (this.viewMode) {
+ case 0:
+
+ if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
+ v.hide();
+ }
+ break;
+ case 1:
+ case 2:
+ if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
+ v.hide();
+ }
+ break;
}
- }, this.delay.show)
- },
- leave : function() {
- clearTimeout(this.timeout);
-
- this.hoverState = 'out';
-
- if (!this.delay || !this.delay.hide) {
- this.hide();
- return;
- }
- var _t = this;
- this.timeout = setTimeout(function () {
- if (_t.hoverState == 'out') {
- _t.hide();
+ });
+
+ Roo.each(this.picker().select('.next', true).elements, function(v){
+ v.show();
+ switch (this.viewMode) {
+ case 0:
+
+ if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
+ v.hide();
+ }
+ break;
+ case 1:
+ case 2:
+ if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
+ v.hide();
+ }
+ break;
}
- }, this.delay.hide)
+ })
},
- show : function (on_el)
+ moveMonth: function(date, dir)
{
- if (!on_el) {
- on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
- }
- // set content.
- this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
- if (this.html !== false) {
- this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
- }
- this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
- if (!this.title.length) {
- this.el.select('.popover-title',true).hide();
- }
-
- var placement = typeof this.placement == 'function' ?
- this.placement.call(this, this.el, on_el) :
- this.placement;
-
- var autoToken = /\s?auto?\s?/i;
- var autoPlace = autoToken.test(placement);
- if (autoPlace) {
- placement = placement.replace(autoToken, '') || 'top';
- }
-
- //this.el.detach()
- //this.el.setXY([0,0]);
- this.el.show();
- this.el.dom.style.display='block';
- this.el.addClass(placement);
-
- //this.el.appendTo(on_el);
-
- var p = this.getPosition();
- var box = this.el.getBox();
-
- if (autoPlace) {
- // fixme..
+ if (!dir) return date;
+ var new_date = new Date(date.valueOf()),
+ day = new_date.getUTCDate(),
+ month = new_date.getUTCMonth(),
+ mag = Math.abs(dir),
+ new_month, test;
+ dir = dir > 0 ? 1 : -1;
+ if (mag == 1){
+ test = dir == -1
+ // If going back one month, make sure month is not current month
+ // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
+ ? function(){
+ return new_date.getUTCMonth() == month;
+ }
+ // If going forward one month, make sure month is as expected
+ // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
+ : function(){
+ return new_date.getUTCMonth() != new_month;
+ };
+ new_month = month + dir;
+ new_date.setUTCMonth(new_month);
+ // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
+ if (new_month < 0 || new_month > 11)
+ new_month = (new_month + 12) % 12;
+ } else {
+ // For magnitudes >1, move one month at a time...
+ for (var i=0; i<mag; i++)
+ // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
+ new_date = this.moveMonth(new_date, dir);
+ // ...then reset the day, keeping it in the new month
+ new_month = new_date.getUTCMonth();
+ new_date.setUTCDate(day);
+ test = function(){
+ return new_month != new_date.getUTCMonth();
+ };
}
- var align = Roo.bootstrap.Popover.alignment[placement];
- this.el.alignTo(on_el, align[0],align[1]);
- //var arrow = this.el.select('.arrow',true).first();
- //arrow.set(align[2],
-
- this.el.addClass('in');
- this.hoverState = null;
-
- if (this.el.hasClass('fade')) {
- // fade it?
+ // Common date-resetting loop -- if date is beyond end of month, make it
+ // end of month
+ while (test()){
+ new_date.setUTCDate(--day);
+ new_date.setUTCMonth(new_month);
}
-
+ return new_date;
},
- hide : function()
- {
- this.el.setXY([0,0]);
- this.el.removeClass('in');
- this.el.hide();
-
- }
-
-});
-
-Roo.bootstrap.Popover.alignment = {
- 'left' : ['r-l', [-10,0], 'right'],
- 'right' : ['l-r', [10,0], 'left'],
- 'bottom' : ['t-b', [0,10], 'top'],
- 'top' : [ 'b-t', [0,-10], 'bottom']
-};
-
- /*
- * - LGPL
- *
- * Progress
- *
- */
-/**
- * @class Roo.bootstrap.Progress
- * @extends Roo.bootstrap.Component
- * Bootstrap Progress class
- * @cfg {Boolean} striped striped of the progress bar
- * @cfg {Boolean} active animated of the progress bar
- *
- *
- * @constructor
- * Create a new Progress
- * @param {Object} config The config object
- */
+ moveYear: function(date, dir)
+ {
+ return this.moveMonth(date, dir*12);
+ },
-Roo.bootstrap.Progress = function(config){
- Roo.bootstrap.Progress.superclass.constructor.call(this, config);
-};
+ dateWithinRange: function(date)
+ {
+ return date >= this.startDate && date <= this.endDate;
+ },
-Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
-
- striped : false,
- active: false,
- getAutoCreate : function(){
- var cfg = {
- tag: 'div',
- cls: 'progress'
- };
-
-
- if(this.striped){
- cfg.cls += ' progress-striped';
- }
-
- if(this.active){
- cfg.cls += ' active';
- }
-
-
- return cfg;
+ remove: function()
+ {
+ this.picker().remove();
}
});
-
-
- /*
- * - LGPL
- *
- * ProgressBar
- *
- */
-
-/**
- * @class Roo.bootstrap.ProgressBar
- * @extends Roo.bootstrap.Component
- * Bootstrap ProgressBar class
- * @cfg {Number} aria_valuenow aria-value now
- * @cfg {Number} aria_valuemin aria-value min
- * @cfg {Number} aria_valuemax aria-value max
- * @cfg {String} label label for the progress bar
- * @cfg {String} panel (success | info | warning | danger )
- * @cfg {String} role role of the progress bar
- * @cfg {String} sr_only text
- *
- *
- * @constructor
- * Create a new ProgressBar
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.ProgressBar = function(config){
- Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
-};
+Roo.apply(Roo.bootstrap.DateField, {
+
+ head : {
+ tag: 'thead',
+ cn: [
+ {
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'th',
+ cls: 'prev',
+ html: '<i class="fa fa-arrow-left"/>'
+ },
+ {
+ tag: 'th',
+ cls: 'switch',
+ colspan: '5'
+ },
+ {
+ tag: 'th',
+ cls: 'next',
+ html: '<i class="fa fa-arrow-right"/>'
+ }
-Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
+ ]
+ }
+ ]
+ },
- aria_valuenow : 0,
- aria_valuemin : 0,
- aria_valuemax : 100,
- label : false,
- panel : false,
- role : false,
- sr_only: false,
+ content : {
+ tag: 'tbody',
+ cn: [
+ {
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'td',
+ colspan: '7'
+ }
+ ]
+ }
+ ]
+ },
- getAutoCreate : function()
+ footer : {
+ tag: 'tfoot',
+ cn: [
+ {
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'th',
+ colspan: '7',
+ cls: 'today'
+ }
+
+ ]
+ }
+ ]
+ },
+
+ dates:{
+ en: {
+ days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+ daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+ daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+ today: "Today"
+ }
+ },
+
+ modes: [
{
-
- var cfg = {
+ clsName: 'days',
+ navFnc: 'Month',
+ navStep: 1
+ },
+ {
+ clsName: 'months',
+ navFnc: 'FullYear',
+ navStep: 1
+ },
+ {
+ clsName: 'years',
+ navFnc: 'FullYear',
+ navStep: 10
+ }]
+});
+
+Roo.apply(Roo.bootstrap.DateField, {
+
+ template : {
+ tag: 'div',
+ cls: 'datepicker dropdown-menu roo-dynamic',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'datepicker-days',
+ cn: [
+ {
+ tag: 'table',
+ cls: 'table-condensed',
+ cn:[
+ Roo.bootstrap.DateField.head,
+ {
+ tag: 'tbody'
+ },
+ Roo.bootstrap.DateField.footer
+ ]
+ }
+ ]
+ },
+ {
+ tag: 'div',
+ cls: 'datepicker-months',
+ cn: [
+ {
+ tag: 'table',
+ cls: 'table-condensed',
+ cn:[
+ Roo.bootstrap.DateField.head,
+ Roo.bootstrap.DateField.content,
+ Roo.bootstrap.DateField.footer
+ ]
+ }
+ ]
+ },
+ {
tag: 'div',
- cls: 'progress-bar',
- style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
- };
-
- if(this.sr_only){
- cfg.cn = {
- tag: 'span',
- cls: 'sr-only',
- html: this.sr_only
+ cls: 'datepicker-years',
+ cn: [
+ {
+ tag: 'table',
+ cls: 'table-condensed',
+ cn:[
+ Roo.bootstrap.DateField.head,
+ Roo.bootstrap.DateField.content,
+ Roo.bootstrap.DateField.footer
+ ]
}
+ ]
}
-
- if(this.role){
- cfg.role = this.role;
- }
-
- if(this.aria_valuenow){
- cfg['aria-valuenow'] = this.aria_valuenow;
- }
-
- if(this.aria_valuemin){
- cfg['aria-valuemin'] = this.aria_valuemin;
- }
-
- if(this.aria_valuemax){
- cfg['aria-valuemax'] = this.aria_valuemax;
- }
-
- if(this.label && !this.sr_only){
- cfg.html = this.label;
- }
-
- if(this.panel){
- cfg.cls += ' progress-bar-' + this.panel;
- }
-
- return cfg;
- },
-
- update : function(aria_valuenow)
- {
- this.aria_valuenow = aria_valuenow;
-
- this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
+ ]
}
-
});
/*
* - LGPL
*
- * column
+ * TimeField
*
*/
/**
- * @class Roo.bootstrap.TabGroup
- * @extends Roo.bootstrap.Column
- * Bootstrap Column class
- * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
- * @cfg {Boolean} carousel true to make the group behave like a carousel
- * @cfg {Number} bullets show the panel pointer.. default 0
- * @cfg {Boolean} autoslide (true|false) auto slide .. default false
- * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
- * @cfg {Number} timer auto slide timer .. default 0 millisecond
+ * @class Roo.bootstrap.TimeField
+ * @extends Roo.bootstrap.Input
+ * Bootstrap DateField class
+ *
*
* @constructor
- * Create a new TabGroup
+ * Create a new TimeField
* @param {Object} config The config object
*/
-Roo.bootstrap.TabGroup = function(config){
- Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
- if (!this.navId) {
- this.navId = Roo.id();
- }
- this.tabs = [];
- Roo.bootstrap.TabGroup.register(this);
-
+Roo.bootstrap.TimeField = function(config){
+ Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
+ this.addEvents({
+ /**
+ * @event show
+ * Fires when this field show.
+ * @param {Roo.bootstrap.DateField} thisthis
+ * @param {Mixed} date The date value
+ */
+ show : true,
+ /**
+ * @event show
+ * Fires when this field hide.
+ * @param {Roo.bootstrap.DateField} this
+ * @param {Mixed} date The date value
+ */
+ hide : true,
+ /**
+ * @event select
+ * Fires when select a date.
+ * @param {Roo.bootstrap.DateField} this
+ * @param {Mixed} date The date value
+ */
+ select : true
+ });
};
-Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
-
- carousel : false,
- transition : false,
- bullets : 0,
- timer : 0,
- autoslide : false,
- slideFn : false,
- slideOnTouch : false,
+Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
- getAutoCreate : function()
+ /**
+ * @cfg {String} format
+ * The default time format string which can be overriden for localization support. The format must be
+ * valid according to {@link Date#parseDate} (defaults to 'H:i').
+ */
+ format : "H:i",
+
+ onRender: function(ct, position)
{
- var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
-
- cfg.cls += ' tab-content';
-
- Roo.log('get auto create...............');
-
- if (this.carousel) {
- cfg.cls += ' carousel slide';
-
- cfg.cn = [{
- cls : 'carousel-inner'
- }];
- if(this.bullets > 0 && !Roo.isTouch){
-
- var bullets = {
- cls : 'carousel-bullets',
- cn : []
- };
-
- if(this.bullets_cls){
- bullets.cls = bullets.cls + ' ' + this.bullets_cls;
- }
-
- for (var i = 0; i < this.bullets; i++){
- bullets.cn.push({
- cls : 'bullet bullet-' + i
- });
- }
-
- bullets.cn.push({
- cls : 'clear'
- });
+ Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
- cfg.cn[0].cn = bullets;
- }
- }
-
- return cfg;
- },
-
- initEvents: function()
- {
- Roo.log('-------- init events on tab group ---------');
+ this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
- if(this.bullets > 0 && !Roo.isTouch){
- this.initBullet();
- }
+ this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- Roo.log(this);
+ this.pop = this.picker().select('>.datepicker-time',true).first();
+ this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- if(Roo.isTouch && this.slideOnTouch){
- this.el.on("touchstart", this.onTouchStart, this);
- }
+ this.picker().on('mousedown', this.onMousedown, this);
+ this.picker().on('click', this.onClick, this);
- if(this.autoslide){
- var _this = this;
+ this.picker().addClass('datepicker-dropdown');
+
+ this.fillTime();
+ this.update();
- this.slideFn = window.setInterval(function() {
- _this.showPanelNext();
- }, this.timer);
- }
-
+ this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
+ this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
+ this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
+ this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
+ this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
+ this.pop.select('button.ok', true).first().on('click', this.setTime, this);
+
},
- onTouchStart : function(e, el, o)
- {
- if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
+ fireKey: function(e){
+ if (!this.picker().isVisible()){
+ if (e.keyCode == 27) { // allow escape to hide and re-show picker
+ this.show();
+ }
return;
}
+
+ e.preventDefault();
- this.showPanelNext();
- },
-
- getChildContainer : function()
- {
- return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
- },
-
- /**
- * register a Navigation item
- * @param {Roo.bootstrap.NavItem} the navitem to add
- */
- register : function(item)
- {
- this.tabs.push( item);
- item.navId = this.navId; // not really needed..
+ switch(e.keyCode){
+ case 27: // escape
+ this.hide();
+ break;
+ case 37: // left
+ case 39: // right
+ this.onTogglePeriod();
+ break;
+ case 38: // up
+ this.onIncrementMinutes();
+ break;
+ case 40: // down
+ this.onDecrementMinutes();
+ break;
+ case 13: // enter
+ case 9: // tab
+ this.setTime();
+ break;
+ }
+ },
+ onClick: function(e) {
+ e.stopPropagation();
+ e.preventDefault();
},
- getActivePanel : function()
+ picker : function()
{
- var r = false;
- Roo.each(this.tabs, function(t) {
- if (t.active) {
- r = t;
- return false;
- }
- return null;
+ return this.el.select('.datepicker', true).first();
+ },
+
+ fillTime: function()
+ {
+ var time = this.pop.select('tbody', true).first();
+
+ time.dom.innerHTML = '';
+
+ time.createChild({
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'a',
+ href: '#',
+ cls: 'btn',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'hours-up glyphicon glyphicon-chevron-up'
+ }
+ ]
+ }
+ ]
+ },
+ {
+ tag: 'td',
+ cls: 'separator'
+ },
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'a',
+ href: '#',
+ cls: 'btn',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'minutes-up glyphicon glyphicon-chevron-up'
+ }
+ ]
+ }
+ ]
+ },
+ {
+ tag: 'td',
+ cls: 'separator'
+ }
+ ]
});
- return r;
- },
- getPanelByName : function(n)
- {
- var r = false;
- Roo.each(this.tabs, function(t) {
- if (t.tabId == n) {
- r = t;
- return false;
- }
- return null;
+ time.createChild({
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'timepicker-hour',
+ html: '00'
+ }
+ ]
+ },
+ {
+ tag: 'td',
+ cls: 'separator',
+ html: ':'
+ },
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'timepicker-minute',
+ html: '00'
+ }
+ ]
+ },
+ {
+ tag: 'td',
+ cls: 'separator'
+ },
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'button',
+ type: 'button',
+ cls: 'btn btn-primary period',
+ html: 'AM'
+
+ }
+ ]
+ }
+ ]
});
- return r;
- },
- indexOfPanel : function(p)
- {
- var r = false;
- Roo.each(this.tabs, function(t,i) {
- if (t.tabId == p.tabId) {
- r = i;
- return false;
- }
- return null;
+
+ time.createChild({
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'a',
+ href: '#',
+ cls: 'btn',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'hours-down glyphicon glyphicon-chevron-down'
+ }
+ ]
+ }
+ ]
+ },
+ {
+ tag: 'td',
+ cls: 'separator'
+ },
+ {
+ tag: 'td',
+ cn: [
+ {
+ tag: 'a',
+ href: '#',
+ cls: 'btn',
+ cn: [
+ {
+ tag: 'span',
+ cls: 'minutes-down glyphicon glyphicon-chevron-down'
+ }
+ ]
+ }
+ ]
+ },
+ {
+ tag: 'td',
+ cls: 'separator'
+ }
+ ]
});
- return r;
+
},
- /**
- * show a specific panel
- * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
- * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
- */
- showPanel : function (pan)
+
+ update: function()
{
- if(this.transition){
- Roo.log("waiting for the transitionend");
- return;
- }
- if (typeof(pan) == 'number') {
- pan = this.tabs[pan];
- }
- if (typeof(pan) == 'string') {
- pan = this.getPanelByName(pan);
- }
- if (pan.tabId == this.getActivePanel().tabId) {
- return true;
- }
- var cur = this.getActivePanel();
+ this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
- if (false === cur.fireEvent('beforedeactivate')) {
- return false;
- }
+ this.fill();
+ },
+
+ fill: function()
+ {
+ var hours = this.time.getHours();
+ var minutes = this.time.getMinutes();
+ var period = 'AM';
- if(this.bullets > 0 && !Roo.isTouch){
- this.setActiveBullet(this.indexOfPanel(pan));
+ if(hours > 11){
+ period = 'PM';
}
- if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
-
- this.transition = true;
- var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
- var lr = dir == 'next' ? 'left' : 'right';
- pan.el.addClass(dir); // or prev
- pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
- cur.el.addClass(lr); // or right
- pan.el.addClass(lr);
-
- var _this = this;
- cur.el.on('transitionend', function() {
- Roo.log("trans end?");
-
- pan.el.removeClass([lr,dir]);
- pan.setActive(true);
-
- cur.el.removeClass([lr]);
- cur.setActive(false);
-
- _this.transition = false;
-
- }, this, { single: true } );
-
- return true;
+ if(hours == 0){
+ hours = 12;
}
- cur.setActive(false);
- pan.setActive(true);
-
- return true;
-
- },
- showPanelNext : function()
- {
- var i = this.indexOfPanel(this.getActivePanel());
-
- if (i >= this.tabs.length - 1 && !this.autoslide) {
- return;
+
+ if(hours > 12){
+ hours = hours - 12;
}
- if (i >= this.tabs.length - 1 && this.autoslide) {
- i = -1;
+ if(hours < 10){
+ hours = '0' + hours;
}
- this.showPanel(this.tabs[i+1]);
+ if(minutes < 10){
+ minutes = '0' + minutes;
+ }
+
+ this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
+ this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
+ this.pop.select('button', true).first().dom.innerHTML = period;
+
},
- showPanelPrev : function()
- {
- var i = this.indexOfPanel(this.getActivePanel());
+ place: function()
+ {
+ this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
- if (i < 1 && !this.autoslide) {
- return;
+ var cls = ['bottom'];
+
+ if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
+ cls.pop();
+ cls.push('top');
}
- if (i < 1 && this.autoslide) {
- i = this.tabs.length;
+ cls.push('right');
+
+ if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
+ cls.pop();
+ cls.push('left');
}
- this.showPanel(this.tabs[i-1]);
+ this.picker().addClass(cls.join('-'));
+
+ var _this = this;
+
+ Roo.each(cls, function(c){
+ if(c == 'bottom'){
+ _this.picker().setTop(_this.inputEl().getHeight());
+ return;
+ }
+ if(c == 'top'){
+ _this.picker().setTop(0 - _this.picker().getHeight());
+ return;
+ }
+
+ if(c == 'left'){
+ _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
+ return;
+ }
+ if(c == 'right'){
+ _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
+ return;
+ }
+ });
+
+ },
+
+ onFocus : function()
+ {
+ Roo.bootstrap.TimeField.superclass.onFocus.call(this);
+ this.show();
},
- initBullet : function()
+ onBlur : function()
{
- if(Roo.isTouch){
- return;
- }
+ Roo.bootstrap.TimeField.superclass.onBlur.call(this);
+ this.hide();
+ },
+
+ show : function()
+ {
+ this.picker().show();
+ this.pop.show();
+ this.update();
+ this.place();
- var _this = this;
+ this.fireEvent('show', this, this.date);
+ },
+
+ hide : function()
+ {
+ this.picker().hide();
+ this.pop.hide();
- for (var i = 0; i < this.bullets; i++){
- var bullet = this.el.select('.bullet-' + i, true).first();
-
- if(!bullet){
- continue;
- }
-
- bullet.on('click', (function(e, el, o, ii, t){
-
- e.preventDefault();
-
- _this.showPanel(ii);
-
- if(_this.autoslide && _this.slideFn){
- clearInterval(_this.slideFn);
- _this.slideFn = window.setInterval(function() {
- _this.showPanelNext();
- }, _this.timer);
- }
-
- }).createDelegate(this, [i, bullet], true));
- }
+ this.fireEvent('hide', this, this.date);
},
- setActiveBullet : function(i)
+ setTime : function()
{
- if(Roo.isTouch){
- return;
- }
+ this.hide();
+ this.setValue(this.time.format(this.format));
- Roo.each(this.el.select('.bullet', true).elements, function(el){
- el.removeClass('selected');
- });
-
- var bullet = this.el.select('.bullet-' + i, true).first();
+ this.fireEvent('select', this, this.date);
- if(!bullet){
- return;
- }
- bullet.addClass('selected');
- }
+ },
+ onMousedown: function(e){
+ e.stopPropagation();
+ e.preventDefault();
+ },
-
+ onIncrementHours: function()
+ {
+ Roo.log('onIncrementHours');
+ this.time = this.time.add(Date.HOUR, 1);
+ this.update();
+
+ },
+
+ onDecrementHours: function()
+ {
+ Roo.log('onDecrementHours');
+ this.time = this.time.add(Date.HOUR, -1);
+ this.update();
+ },
+
+ onIncrementMinutes: function()
+ {
+ Roo.log('onIncrementMinutes');
+ this.time = this.time.add(Date.MINUTE, 1);
+ this.update();
+ },
+
+ onDecrementMinutes: function()
+ {
+ Roo.log('onDecrementMinutes');
+ this.time = this.time.add(Date.MINUTE, -1);
+ this.update();
+ },
+
+ onTogglePeriod: function()
+ {
+ Roo.log('onTogglePeriod');
+ this.time = this.time.add(Date.HOUR, 12);
+ this.update();
+ }
+
+
});
-
-
-
-
-Roo.apply(Roo.bootstrap.TabGroup, {
+Roo.apply(Roo.bootstrap.TimeField, {
- groups: {},
- /**
- * register a Navigation Group
- * @param {Roo.bootstrap.NavGroup} the navgroup to add
- */
- register : function(navgrp)
- {
- this.groups[navgrp.navId] = navgrp;
-
+ content : {
+ tag: 'tbody',
+ cn: [
+ {
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'td',
+ colspan: '7'
+ }
+ ]
+ }
+ ]
},
- /**
- * fetch a Navigation Group based on the navigation ID
- * if one does not exist , it will get created.
- * @param {string} the navgroup to add
- * @returns {Roo.bootstrap.NavGroup} the navgroup
- */
- get: function(navId) {
- if (typeof(this.groups[navId]) == 'undefined') {
- this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
- }
- return this.groups[navId] ;
+
+ footer : {
+ tag: 'tfoot',
+ cn: [
+ {
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'th',
+ colspan: '7',
+ cls: '',
+ cn: [
+ {
+ tag: 'button',
+ cls: 'btn btn-info ok',
+ html: 'OK'
+ }
+ ]
+ }
+
+ ]
+ }
+ ]
+ }
+});
+
+Roo.apply(Roo.bootstrap.TimeField, {
+
+ template : {
+ tag: 'div',
+ cls: 'datepicker dropdown-menu',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'datepicker-time',
+ cn: [
+ {
+ tag: 'table',
+ cls: 'table-condensed',
+ cn:[
+ Roo.bootstrap.TimeField.content,
+ Roo.bootstrap.TimeField.footer
+ ]
+ }
+ ]
+ }
+ ]
}
-
-
-
});
+
+
/*
* - LGPL
*
- * TabPanel
+ * MonthField
*
*/
/**
- * @class Roo.bootstrap.TabPanel
- * @extends Roo.bootstrap.Component
- * Bootstrap TabPanel class
- * @cfg {Boolean} active panel active
- * @cfg {String} html panel content
- * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
- * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
+ * @class Roo.bootstrap.MonthField
+ * @extends Roo.bootstrap.Input
+ * Bootstrap MonthField class
*
+ * @cfg {String} language default en
*
* @constructor
- * Create a new TabPanel
+ * Create a new MonthField
* @param {Object} config The config object
*/
-Roo.bootstrap.TabPanel = function(config){
- Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
+Roo.bootstrap.MonthField = function(config){
+ Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
+
this.addEvents({
/**
- * @event changed
- * Fires when the active status changes
- * @param {Roo.bootstrap.TabPanel} this
- * @param {Boolean} state the new state
-
+ * @event show
+ * Fires when this field show.
+ * @param {Roo.bootstrap.MonthField} this
+ * @param {Mixed} date The date value
*/
- 'changed': true,
+ show : true,
/**
- * @event beforedeactivate
- * Fires before a tab is de-activated - can be used to do validation on a form.
- * @param {Roo.bootstrap.TabPanel} this
- * @return {Boolean} false if there is an error
-
+ * @event show
+ * Fires when this field hide.
+ * @param {Roo.bootstrap.MonthField} this
+ * @param {Mixed} date The date value
*/
- 'beforedeactivate': true
- });
-
- this.tabId = this.tabId || Roo.id();
-
+ hide : true,
+ /**
+ * @event select
+ * Fires when select a date.
+ * @param {Roo.bootstrap.MonthField} this
+ * @param {String} oldvalue The old value
+ * @param {String} newvalue The new value
+ */
+ select : true
+ });
};
-Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
+Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
- active: false,
- html: false,
- tabId: false,
- navId : false,
+ onRender: function(ct, position)
+ {
+
+ Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
+
+ this.language = this.language || 'en';
+ this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
+ this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
+
+ this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
+ this.isInline = false;
+ this.isInput = true;
+ this.component = this.el.select('.add-on', true).first() || false;
+ this.component = (this.component && this.component.length === 0) ? false : this.component;
+ this.hasInput = this.component && this.inputEL().length;
+
+ this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
+
+ this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.picker().on('mousedown', this.onMousedown, this);
+ this.picker().on('click', this.onClick, this);
+
+ this.picker().addClass('datepicker-dropdown');
+
+ Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
+ v.setStyle('width', '189px');
+ });
+
+ this.fillMonths();
+
+ this.update();
+
+ if(this.isInline) {
+ this.show();
+ }
+
+ },
- getAutoCreate : function(){
- var cfg = {
- tag: 'div',
- // item is needed for carousel - not sure if it has any effect otherwise
- cls: 'tab-pane item',
- html: this.html || ''
- };
+ setValue: function(v, suppressEvent)
+ {
+ var o = this.getValue();
- if(this.active){
- cfg.cls += ' active';
+ Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
+
+ this.update();
+
+ if(suppressEvent !== true){
+ this.fireEvent('select', this, o, v);
}
- if(this.tabId){
- cfg.tabId = this.tabId;
+ },
+
+ getValue: function()
+ {
+ return this.value;
+ },
+
+ onClick: function(e)
+ {
+ e.stopPropagation();
+ e.preventDefault();
+
+ var target = e.getTarget();
+
+ if(target.nodeName.toLowerCase() === 'i'){
+ target = Roo.get(target).dom.parentNode;
}
+ var nodeName = target.nodeName;
+ var className = target.className;
+ var html = target.innerHTML;
- return cfg;
+ if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
+ return;
+ }
+
+ this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
+
+ this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+
+ this.hide();
+
},
- initEvents: function()
+ picker : function()
{
- Roo.log('-------- init events on tab panel ---------');
+ return this.pickerEl;
+ },
+
+ fillMonths: function()
+ {
+ var i = 0;
+ var months = this.picker().select('>.datepicker-months td', true).first();
- var p = this.parent();
- this.navId = this.navId || p.navId;
+ months.dom.innerHTML = '';
- if (typeof(this.navId) != 'undefined') {
- // not really needed.. but just in case.. parent should be a NavGroup.
- var tg = Roo.bootstrap.TabGroup.get(this.navId);
- Roo.log(['register', tg, this]);
- tg.register(this);
+ while (i < 12) {
+ var month = {
+ tag: 'span',
+ cls: 'month',
+ html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
+ }
- var i = tg.tabs.length - 1;
+ months.createChild(month);
+ }
+
+ },
+
+ update: function()
+ {
+ var _this = this;
+
+ if(typeof(this.vIndex) == 'undefined' && this.value.length){
+ this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
+ }
+
+ Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
+ e.removeClass('active');
- if(this.active && tg.bullets > 0 && i < tg.bullets){
- tg.setActiveBullet(i);
+ if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
+ e.addClass('active');
}
+ })
+ },
+
+ place: function()
+ {
+ if(this.isInline) return;
+
+ this.picker().removeClass(['bottom', 'top']);
+
+ if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
+ /*
+ * place to the top of element!
+ *
+ */
+
+ this.picker().addClass('top');
+ this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+
+ return;
}
+ this.picker().addClass('bottom');
+
+ this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
+ },
+
+ onFocus : function()
+ {
+ Roo.bootstrap.MonthField.superclass.onFocus.call(this);
+ this.show();
+ },
+
+ onBlur : function()
+ {
+ Roo.bootstrap.MonthField.superclass.onBlur.call(this);
+
+ var d = this.inputEl().getValue();
+
+ this.setValue(d);
+
+ this.hide();
+ },
+
+ show : function()
+ {
+ this.picker().show();
+ this.picker().select('>.datepicker-months', true).first().show();
+ this.update();
+ this.place();
+
+ this.fireEvent('show', this, this.date);
+ },
+
+ hide : function()
+ {
+ if(this.isInline) return;
+ this.picker().hide();
+ this.fireEvent('hide', this, this.date);
+
},
+ onMousedown: function(e)
+ {
+ e.stopPropagation();
+ e.preventDefault();
+ },
- onRender : function(ct, position)
+ keyup: function(e)
{
- // Roo.log("Call onRender: " + this.xtype);
-
- Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
-
-
-
+ Roo.bootstrap.MonthField.superclass.keyup.call(this);
+ this.update();
+ },
+
+ fireKey: function(e)
+ {
+ if (!this.picker().isVisible()){
+ if (e.keyCode == 27) // allow escape to hide and re-show picker
+ this.show();
+ return;
+ }
+ var dir;
+ switch(e.keyCode){
+ case 27: // escape
+ this.hide();
+ e.preventDefault();
+ break;
+ case 37: // left
+ case 39: // right
+ dir = e.keyCode == 37 ? -1 : 1;
+
+ this.vIndex = this.vIndex + dir;
+
+ if(this.vIndex < 0){
+ this.vIndex = 0;
+ }
+
+ if(this.vIndex > 11){
+ this.vIndex = 11;
+ }
+
+ if(isNaN(this.vIndex)){
+ this.vIndex = 0;
+ }
+
+ this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+
+ break;
+ case 38: // up
+ case 40: // down
+
+ dir = e.keyCode == 38 ? -1 : 1;
+
+ this.vIndex = this.vIndex + dir * 4;
+
+ if(this.vIndex < 0){
+ this.vIndex = 0;
+ }
+
+ if(this.vIndex > 11){
+ this.vIndex = 11;
+ }
+
+ if(isNaN(this.vIndex)){
+ this.vIndex = 0;
+ }
+
+ this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+ break;
+
+ case 13: // enter
+
+ if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
+ this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+ }
+
+ this.hide();
+ e.preventDefault();
+ break;
+ case 9: // tab
+ if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
+ this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+ }
+ this.hide();
+ break;
+ case 16: // shift
+ case 17: // ctrl
+ case 18: // alt
+ break;
+ default :
+ this.hide();
+
+ }
},
- setActive: function(state)
+ remove: function()
{
- Roo.log("panel - set active " + this.tabId + "=" + state);
-
- this.active = state;
- if (!state) {
- this.el.removeClass('active');
-
- } else if (!this.el.hasClass('active')) {
- this.el.addClass('active');
- }
-
- this.fireEvent('changed', this, state);
+ this.picker().remove();
}
+
+});
+
+Roo.apply(Roo.bootstrap.MonthField, {
+ content : {
+ tag: 'tbody',
+ cn: [
+ {
+ tag: 'tr',
+ cn: [
+ {
+ tag: 'td',
+ colspan: '7'
+ }
+ ]
+ }
+ ]
+ },
+ dates:{
+ en: {
+ months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+ monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+ }
+ }
+});
+
+Roo.apply(Roo.bootstrap.MonthField, {
+
+ template : {
+ tag: 'div',
+ cls: 'datepicker dropdown-menu roo-dynamic',
+ cn: [
+ {
+ tag: 'div',
+ cls: 'datepicker-months',
+ cn: [
+ {
+ tag: 'table',
+ cls: 'table-condensed',
+ cn:[
+ Roo.bootstrap.DateField.content
+ ]
+ }
+ ]
+ }
+ ]
+ }
});
-
+
/*
* - LGPL
*
- * DateField
+ * CheckBox
*
*/
/**
- * @class Roo.bootstrap.DateField
+ * @class Roo.bootstrap.CheckBox
* @extends Roo.bootstrap.Input
- * Bootstrap DateField class
- * @cfg {Number} weekStart default 0
- * @cfg {String} viewMode default empty, (months|years)
- * @cfg {String} minViewMode default empty, (months|years)
- * @cfg {Number} startDate default -Infinity
- * @cfg {Number} endDate default Infinity
- * @cfg {Boolean} todayHighlight default false
- * @cfg {Boolean} todayBtn default false
- * @cfg {Boolean} calendarWeeks default false
- * @cfg {Object} daysOfWeekDisabled default empty
- * @cfg {Boolean} singleMode default false (true | false)
- *
- * @cfg {Boolean} keyboardNavigation default true
- * @cfg {String} language default en
+ * Bootstrap CheckBox class
*
- * @constructor
- * Create a new DateField
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.DateField = function(config){
- Roo.bootstrap.DateField.superclass.constructor.call(this, config);
- this.addEvents({
- /**
- * @event show
- * Fires when this field show.
- * @param {Roo.bootstrap.DateField} this
- * @param {Mixed} date The date value
- */
- show : true,
- /**
- * @event show
- * Fires when this field hide.
- * @param {Roo.bootstrap.DateField} this
- * @param {Mixed} date The date value
- */
- hide : true,
- /**
- * @event select
- * Fires when select a date.
- * @param {Roo.bootstrap.DateField} this
- * @param {Mixed} date The date value
- */
- select : true
- });
-};
-
-Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
-
- /**
- * @cfg {String} format
- * The default date format string which can be overriden for localization support. The format must be
- * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
- */
- format : "m/d/y",
- /**
- * @cfg {String} altFormats
- * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
- * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
- */
- altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
-
- weekStart : 0,
-
- viewMode : '',
-
- minViewMode : '',
-
- todayHighlight : false,
-
- todayBtn: false,
-
- language: 'en',
-
- keyboardNavigation: true,
-
- calendarWeeks: false,
-
- startDate: -Infinity,
-
- endDate: Infinity,
-
- daysOfWeekDisabled: [],
-
- _events: [],
-
- singleMode : false,
+ * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
+ * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
+ * @cfg {String} boxLabel The text that appears beside the checkbox
+ * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
+ * @cfg {Boolean} checked initnal the element
+ * @cfg {Boolean} inline inline the element (default false)
+ * @cfg {String} groupId the checkbox group id // normal just use for checkbox
+ *
+ * @constructor
+ * Create a new CheckBox
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.CheckBox = function(config){
+ Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
+
+ this.addEvents({
+ /**
+ * @event check
+ * Fires when the element is checked or unchecked.
+ * @param {Roo.bootstrap.CheckBox} this This input
+ * @param {Boolean} checked The new checked value
+ */
+ check : true
+ });
- UTCDate: function()
- {
- return new Date(Date.UTC.apply(Date, arguments));
- },
+};
+
+Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
+
+ inputType: 'checkbox',
+ inputValue: 1,
+ valueOff: 0,
+ boxLabel: false,
+ checked: false,
+ weight : false,
+ inline: false,
- UTCToday: function()
+ getAutoCreate : function()
{
- var today = new Date();
- return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
- },
-
- getDate: function() {
- var d = this.getUTCDate();
- return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
- },
-
- getUTCDate: function() {
- return this.date;
- },
-
- setDate: function(d) {
- this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
- },
-
- setUTCDate: function(d) {
- this.date = d;
- this.setValue(this.formatDate(this.date));
- },
+ var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
- onRender: function(ct, position)
- {
+ var id = Roo.id();
- Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
+ var cfg = {};
- this.language = this.language || 'en';
- this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
- this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
+ cfg.cls = 'form-group ' + this.inputType; //input-group
- this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
- this.format = this.format || 'm/d/y';
- this.isInline = false;
- this.isInput = true;
- this.component = this.el.select('.add-on', true).first() || false;
- this.component = (this.component && this.component.length === 0) ? false : this.component;
- this.hasInput = this.component && this.inputEL().length;
+ if(this.inline){
+ cfg.cls += ' ' + this.inputType + '-inline';
+ }
- if (typeof(this.minViewMode === 'string')) {
- switch (this.minViewMode) {
- case 'months':
- this.minViewMode = 1;
- break;
- case 'years':
- this.minViewMode = 2;
- break;
- default:
- this.minViewMode = 0;
- break;
- }
+ var input = {
+ tag: 'input',
+ id : id,
+ type : this.inputType,
+ value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
+ cls : 'roo-' + this.inputType, //'form-box',
+ placeholder : this.placeholder || ''
+
+ };
+
+ if (this.weight) { // Validity check?
+ cfg.cls += " " + this.inputType + "-" + this.weight;
}
- if (typeof(this.viewMode === 'string')) {
- switch (this.viewMode) {
- case 'months':
- this.viewMode = 1;
- break;
- case 'years':
- this.viewMode = 2;
- break;
- default:
- this.viewMode = 0;
- break;
- }
+ if (this.disabled) {
+ input.disabled=true;
}
-
- this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
-// this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
+ if(this.checked){
+ input.checked = this.checked;
+ }
- this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ if (this.name) {
+ input.name = this.name;
+ }
- this.picker().on('mousedown', this.onMousedown, this);
- this.picker().on('click', this.onClick, this);
+ if (this.size) {
+ input.cls += ' input-' + this.size;
+ }
- this.picker().addClass('datepicker-dropdown');
+ var settings=this;
- this.startViewMode = this.viewMode;
+ ['xs','sm','md','lg'].map(function(size){
+ if (settings[size]) {
+ cfg.cls += ' col-' + size + '-' + settings[size];
+ }
+ });
- if(this.singleMode){
- Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
- v.setVisibilityMode(Roo.Element.DISPLAY)
- v.hide();
- });
+ var inputblock = input;
+
+ if (this.before || this.after) {
+
+ inputblock = {
+ cls : 'input-group',
+ cn : []
+ };
+
+ if (this.before) {
+ inputblock.cn.push({
+ tag :'span',
+ cls : 'input-group-addon',
+ html : this.before
+ });
+ }
+
+ inputblock.cn.push(input);
+
+ if (this.after) {
+ inputblock.cn.push({
+ tag :'span',
+ cls : 'input-group-addon',
+ html : this.after
+ });
+ }
- Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
- v.setStyle('width', '189px');
- });
}
- Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
- if(!this.calendarWeeks){
- v.remove();
- return;
+ if (align ==='left' && this.fieldLabel.length) {
+ Roo.log("left and has label");
+ cfg.cn = [
+
+ {
+ tag: 'label',
+ 'for' : id,
+ cls : 'control-label col-md-' + this.labelWidth,
+ html : this.fieldLabel
+
+ },
+ {
+ cls : "col-md-" + (12 - this.labelWidth),
+ cn: [
+ inputblock
+ ]
+ }
+
+ ];
+ } else if ( this.fieldLabel.length) {
+ Roo.log(" label");
+ cfg.cn = [
+
+ {
+ tag: this.boxLabel ? 'span' : 'label',
+ 'for': id,
+ cls: 'control-label box-input-label',
+ //cls : 'input-group-addon',
+ html : this.fieldLabel
+
+ },
+
+ inputblock
+
+ ];
+
+ } else {
+
+ Roo.log(" no label && no align");
+ cfg.cn = [ inputblock ] ;
+
+
+ }
+ if(this.boxLabel){
+ var boxLabelCfg = {
+ tag: 'label',
+ //'for': id, // box label is handled by onclick - so no for...
+ cls: 'box-label',
+ html: this.boxLabel
}
- v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
- v.attr('colspan', function(i, val){
- return parseInt(val) + 1;
- });
- })
-
-
- this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
-
- this.setStartDate(this.startDate);
- this.setEndDate(this.endDate);
-
- this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
-
- this.fillDow();
- this.fillMonths();
- this.update();
- this.showMode();
-
- if(this.isInline) {
- this.show();
+ if(this.tooltip){
+ boxLabelCfg.tooltip = this.tooltip;
+ }
+
+ cfg.cn.push(boxLabelCfg);
}
+
+
+
+ return cfg;
+
},
- picker : function()
+ /**
+ * return the real input element.
+ */
+ inputEl: function ()
{
- return this.pickerEl;
-// return this.el.select('.datepicker', true).first();
+ return this.el.select('input.roo-' + this.inputType,true).first();
},
- fillDow: function()
+ labelEl: function()
{
- var dowCnt = this.weekStart;
+ return this.el.select('label.control-label',true).first();
+ },
+ /* depricated... */
+
+ label: function()
+ {
+ return this.labelEl();
+ },
+
+ initEvents : function()
+ {
+// Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
- var dow = {
- tag: 'tr',
- cn: [
-
- ]
- };
+ this.inputEl().on('click', this.onClick, this);
- if(this.calendarWeeks){
- dow.cn.push({
- tag: 'th',
- cls: 'cw',
- html: ' '
- })
+ if (this.boxLabel) {
+ this.el.select('label.box-label',true).first().on('click', this.onClick, this);
}
- while (dowCnt < this.weekStart + 7) {
- dow.cn.push({
- tag: 'th',
- cls: 'dow',
- html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
- });
- }
+ this.startValue = this.getValue();
- this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
+ if(this.groupId){
+ Roo.bootstrap.CheckBox.register(this);
+ }
},
- fillMonths: function()
- {
- var i = 0;
- var months = this.picker().select('>.datepicker-months td', true).first();
-
- months.dom.innerHTML = '';
+ onClick : function()
+ {
+ this.setChecked(!this.checked);
+ },
+
+ setChecked : function(state,suppressEvent)
+ {
+ this.startValue = this.getValue();
- while (i < 12) {
- var month = {
- tag: 'span',
- cls: 'month',
- html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
+ if(this.inputType == 'radio'){
+
+ Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+ e.dom.checked = false;
+ });
+
+ this.inputEl().dom.checked = true;
+
+ this.inputEl().dom.value = this.inputValue;
+
+ if(suppressEvent !== true){
+ this.fireEvent('check', this, true);
}
- months.createChild(month);
+ this.validate();
+
+ return;
}
- },
-
- update: function()
- {
- this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
+ this.checked = state;
- if (this.date < this.startDate) {
- this.viewDate = new Date(this.startDate);
- } else if (this.date > this.endDate) {
- this.viewDate = new Date(this.endDate);
- } else {
- this.viewDate = new Date(this.date);
+ this.inputEl().dom.checked = state;
+
+ this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
+
+ if(suppressEvent !== true){
+ this.fireEvent('check', this, state);
}
- this.fill();
+ this.validate();
},
- fill: function()
+ getValue : function()
{
- var d = new Date(this.viewDate),
- year = d.getUTCFullYear(),
- month = d.getUTCMonth(),
- startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
- startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
- endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
- endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
- currentDate = this.date && this.date.valueOf(),
- today = this.UTCToday();
-
- this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
+ if(this.inputType == 'radio'){
+ return this.getGroupValue();
+ }
-// this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
+ return this.inputEl().getValue();
-// this.picker.select('>tfoot th.today').
-// .text(dates[this.language].today)
-// .toggle(this.todayBtn !== false);
+ },
- this.updateNavArrows();
- this.fillMonths();
-
- var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
-
- day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
-
- prevMonth.setUTCDate(day);
-
- prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
-
- var nextMonth = new Date(prevMonth);
-
- nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
+ getGroupValue : function()
+ {
+ if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
+ return '';
+ }
- nextMonth = nextMonth.valueOf();
+ return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
+ },
+
+ setValue : function(v,suppressEvent)
+ {
+ if(this.inputType == 'radio'){
+ this.setGroupValue(v, suppressEvent);
+ return;
+ }
- var fillMonths = false;
+ this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
- this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
+ this.validate();
+ },
+
+ setGroupValue : function(v, suppressEvent)
+ {
+ this.startValue = this.getValue();
- while(prevMonth.valueOf() < nextMonth) {
- var clsName = '';
-
- if (prevMonth.getUTCDay() === this.weekStart) {
- if(fillMonths){
- this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
- }
-
- fillMonths = {
- tag: 'tr',
- cn: []
- };
-
- if(this.calendarWeeks){
- // ISO 8601: First week contains first thursday.
- // ISO also states week starts on Monday, but we can be more abstract here.
- var
- // Start of current week: based on weekstart/current date
- ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
- // Thursday of this week
- th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
- // First Thursday of year, year from thursday
- yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
- // Calendar week: ms between thursdays, div ms per day, div 7 days
- calWeek = (th - yth) / 864e5 / 7 + 1;
-
- fillMonths.cn.push({
- tag: 'td',
- cls: 'cw',
- html: calWeek
- });
- }
- }
-
- if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
- clsName += ' old';
- } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
- clsName += ' new';
- }
- if (this.todayHighlight &&
- prevMonth.getUTCFullYear() == today.getFullYear() &&
- prevMonth.getUTCMonth() == today.getMonth() &&
- prevMonth.getUTCDate() == today.getDate()) {
- clsName += ' today';
- }
-
- if (currentDate && prevMonth.valueOf() === currentDate) {
- clsName += ' active';
- }
+ Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+ e.dom.checked = false;
- if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
- this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
- clsName += ' disabled';
+ if(e.dom.value == v){
+ e.dom.checked = true;
}
-
- fillMonths.cn.push({
- tag: 'td',
- cls: 'day ' + clsName,
- html: prevMonth.getDate()
- })
-
- prevMonth.setDate(prevMonth.getDate()+1);
+ });
+
+ if(suppressEvent !== true){
+ this.fireEvent('check', this, true);
+ }
+
+ this.validate();
+
+ return;
+ },
+
+ validate : function()
+ {
+ if(
+ this.disabled ||
+ (this.inputType == 'radio' && this.validateRadio()) ||
+ (this.inputType == 'checkbox' && this.validateCheckbox())
+ ){
+ this.markValid();
+ return true;
}
-
- var currentYear = this.date && this.date.getUTCFullYear();
- var currentMonth = this.date && this.date.getUTCMonth();
- this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
+ this.markInvalid();
+ return false;
+ },
+
+ validateRadio : function()
+ {
+ var valid = false;
- Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
- v.removeClass('active');
-
- if(currentYear === year && k === currentMonth){
- v.addClass('active');
+ Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+ if(!e.dom.checked){
+ return;
}
- if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
- v.addClass('disabled');
- }
+ valid = true;
+ return false;
});
+ return valid;
+ },
+
+ validateCheckbox : function()
+ {
+ if(!this.groupId){
+ return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
+ }
- year = parseInt(year/10, 10) * 10;
+ var group = Roo.bootstrap.CheckBox.get(this.groupId);
- this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
+ if(!group){
+ return false;
+ }
- this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
+ var r = false;
- year -= 1;
- for (var i = -1; i < 11; i++) {
- this.picker().select('>.datepicker-years tbody td',true).first().createChild({
- tag: 'span',
- cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
- html: year
- })
+ for(var i in group){
+ if(r){
+ break;
+ }
- year += 1;
+ r = (group[i].getValue() == group[i].inputValue) ? true : false;
}
+
+ return r;
},
- showMode: function(dir)
+ /**
+ * Mark this field as valid
+ */
+ markValid : function()
{
- if (dir) {
- this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
+ if(this.allowBlank){
+ return;
}
- Roo.each(this.picker().select('>div',true).elements, function(v){
- v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- v.hide();
- });
- this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
- },
-
- place: function()
- {
- if(this.isInline) return;
+ var _this = this;
- this.picker().removeClass(['bottom', 'top']);
+ this.fireEvent('valid', this);
- if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
- /*
- * place to the top of element!
- *
- */
-
- this.picker().addClass('top');
- this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+ if(this.inputType == 'radio'){
+ Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+ e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
+ e.findParent('.form-group', false, true).addClass(_this.validClass);
+ });
return;
}
- this.picker().addClass('bottom');
+ if(!this.groupId){
+ this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
+ this.el.findParent('.form-group', false, true).addClass(this.validClass);
+ return;
+ }
- this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
+ var group = Roo.bootstrap.CheckBox.get(this.groupId);
+
+ if(!group){
+ return;
+ }
+
+ for(var i in group){
+ group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
+ group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
+ }
},
- parseDate : function(value)
+ /**
+ * Mark this field as invalid
+ * @param {String} msg The validation message
+ */
+ markInvalid : function(msg)
{
- if(!value || value instanceof Date){
- return value;
+ if(this.allowBlank){
+ return;
}
- var v = Date.parseDate(value, this.format);
- if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
- v = Date.parseDate(value, 'Y-m-d');
+
+ var _this = this;
+
+ this.fireEvent('invalid', this, msg);
+
+ if(this.inputType == 'radio'){
+ Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+ e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
+ e.findParent('.form-group', false, true).addClass(_this.invalidClass);
+ });
+
+ return;
}
- if(!v && this.altFormats){
- if(!this.altFormatsArray){
- this.altFormatsArray = this.altFormats.split("|");
- }
- for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
- v = Date.parseDate(value, this.altFormatsArray[i]);
- }
+
+ if(!this.groupId){
+ this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
+ this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
+ return;
}
- return v;
- },
+
+ var group = Roo.bootstrap.CheckBox.get(this.groupId);
+
+ if(!group){
+ return;
+ }
+
+ for(var i in group){
+ group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
+ group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
+ }
+
+ }
- formatDate : function(date, fmt)
- {
- return (!date || !(date instanceof Date)) ?
- date : date.dateFormat(fmt || this.format);
- },
+});
+
+Roo.apply(Roo.bootstrap.CheckBox, {
- onFocus : function()
- {
- Roo.bootstrap.DateField.superclass.onFocus.call(this);
- this.show();
- },
+ groups: {},
- onBlur : function()
+ /**
+ * register a CheckBox Group
+ * @param {Roo.bootstrap.CheckBox} the CheckBox to add
+ */
+ register : function(checkbox)
{
- Roo.bootstrap.DateField.superclass.onBlur.call(this);
+ if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
+ this.groups[checkbox.groupId] = {};
+ }
- var d = this.inputEl().getValue();
+ if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
+ return;
+ }
- this.setValue(d);
-
- this.hide();
+ this.groups[checkbox.groupId][checkbox.name] = checkbox;
+
},
-
- show : function()
- {
- this.picker().show();
- this.update();
- this.place();
+ /**
+ * fetch a CheckBox Group based on the group ID
+ * @param {string} the group ID
+ * @returns {Roo.bootstrap.CheckBox} the CheckBox group
+ */
+ get: function(groupId) {
+ if (typeof(this.groups[groupId]) == 'undefined') {
+ return false;
+ }
- this.fireEvent('show', this, this.date);
- },
+ return this.groups[groupId] ;
+ }
- hide : function()
- {
- if(this.isInline) return;
- this.picker().hide();
- this.viewMode = this.startViewMode;
- this.showMode();
-
- this.fireEvent('hide', this, this.date);
-
- },
- onMousedown: function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- },
+});
+/*
+ * - LGPL
+ *
+ * Radio
+ *
+ *
+ * not inline
+ *<div class="radio">
+ <label>
+ <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
+ Option one is this and that—be sure to include why it's great
+ </label>
+</div>
+ *
+ *
+ *inline
+ *<span>
+ *<label class="radio-inline">fieldLabel</label>
+ *<label class="radio-inline">
+ <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
+</label>
+<span>
+ *
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.Radio
+ * @extends Roo.bootstrap.CheckBox
+ * Bootstrap Radio class
+
+ * @constructor
+ * Create a new Radio
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Radio = function(config){
+ Roo.bootstrap.Radio.superclass.constructor.call(this, config);
+
+};
+
+Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
+
+ inputType: 'radio',
+ inputValue: '',
+ valueOff: '',
- keyup: function(e)
- {
- Roo.bootstrap.DateField.superclass.keyup.call(this);
- this.update();
- },
-
- setValue: function(v)
+ getAutoCreate : function()
{
+ var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
+ align = align || 'left'; // default...
- // v can be a string or a date..
-
-
- var d = new Date(this.parseDate(v) ).clearTime();
-
- if(isNaN(d.getTime())){
- this.date = this.viewDate = '';
- Roo.bootstrap.DateField.superclass.setValue.call(this, '');
- return;
- }
-
- v = this.formatDate(d);
- Roo.bootstrap.DateField.superclass.setValue.call(this, v);
- this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
-
- this.update();
-
- this.fireEvent('select', this, this.date);
+ var id = Roo.id();
- },
-
- getValue: function()
- {
- return this.formatDate(this.date);
- },
-
- fireKey: function(e)
- {
- if (!this.picker().isVisible()){
- if (e.keyCode == 27) // allow escape to hide and re-show picker
- this.show();
- return;
- }
+ var cfg = {
+ tag : this.inline ? 'span' : 'div',
+ cls : '',
+ cn : []
+ };
- var dateChanged = false,
- dir, day, month,
- newDate, newViewDate;
+ var inline = this.inline ? ' radio-inline' : '';
- switch(e.keyCode){
- case 27: // escape
- this.hide();
- e.preventDefault();
- break;
- case 37: // left
- case 39: // right
- if (!this.keyboardNavigation) break;
- dir = e.keyCode == 37 ? -1 : 1;
-
- if (e.ctrlKey){
- newDate = this.moveYear(this.date, dir);
- newViewDate = this.moveYear(this.viewDate, dir);
- } else if (e.shiftKey){
- newDate = this.moveMonth(this.date, dir);
- newViewDate = this.moveMonth(this.viewDate, dir);
- } else {
- newDate = new Date(this.date);
- newDate.setUTCDate(this.date.getUTCDate() + dir);
- newViewDate = new Date(this.viewDate);
- newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
- }
- if (this.dateWithinRange(newDate)){
- this.date = newDate;
- this.viewDate = newViewDate;
- this.setValue(this.formatDate(this.date));
-// this.update();
- e.preventDefault();
- dateChanged = true;
- }
- break;
- case 38: // up
- case 40: // down
- if (!this.keyboardNavigation) break;
- dir = e.keyCode == 38 ? -1 : 1;
- if (e.ctrlKey){
- newDate = this.moveYear(this.date, dir);
- newViewDate = this.moveYear(this.viewDate, dir);
- } else if (e.shiftKey){
- newDate = this.moveMonth(this.date, dir);
- newViewDate = this.moveMonth(this.viewDate, dir);
- } else {
- newDate = new Date(this.date);
- newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
- newViewDate = new Date(this.viewDate);
- newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
- }
- if (this.dateWithinRange(newDate)){
- this.date = newDate;
- this.viewDate = newViewDate;
- this.setValue(this.formatDate(this.date));
-// this.update();
- e.preventDefault();
- dateChanged = true;
- }
- break;
- case 13: // enter
- this.setValue(this.formatDate(this.date));
- this.hide();
- e.preventDefault();
- break;
- case 9: // tab
- this.setValue(this.formatDate(this.date));
- this.hide();
- break;
- case 16: // shift
- case 17: // ctrl
- case 18: // alt
- break;
- default :
- this.hide();
-
- }
- },
-
-
- onClick: function(e)
- {
- e.stopPropagation();
- e.preventDefault();
+ var lbl = {
+ tag: 'label' ,
+ // does not need for, as we wrap the input with it..
+ 'for' : id,
+ cls : 'control-label box-label' + inline,
+ cn : []
+ };
+ var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
- var target = e.getTarget();
+ var fieldLabel = {
+ tag: 'label' ,
+ //cls : 'control-label' + inline,
+ html : this.fieldLabel,
+ style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
+ };
- if(target.nodeName.toLowerCase() === 'i'){
- target = Roo.get(target).dom.parentNode;
- }
+
- var nodeName = target.nodeName;
- var className = target.className;
- var html = target.innerHTML;
- //Roo.log(nodeName);
- switch(nodeName.toLowerCase()) {
- case 'th':
- switch(className) {
- case 'switch':
- this.showMode(1);
- break;
- case 'prev':
- case 'next':
- var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
- switch(this.viewMode){
- case 0:
- this.viewDate = this.moveMonth(this.viewDate, dir);
- break;
- case 1:
- case 2:
- this.viewDate = this.moveYear(this.viewDate, dir);
- break;
- }
- this.fill();
- break;
- case 'today':
- var date = new Date();
- this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
-// this.fill()
- this.setValue(this.formatDate(this.date));
-
- this.hide();
- break;
- }
- break;
- case 'span':
- if (className.indexOf('disabled') < 0) {
- this.viewDate.setUTCDate(1);
- if (className.indexOf('month') > -1) {
- this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
- } else {
- var year = parseInt(html, 10) || 0;
- this.viewDate.setUTCFullYear(year);
-
- }
-
- if(this.singleMode){
- this.setValue(this.formatDate(this.viewDate));
- this.hide();
- return;
- }
-
- this.showMode(-1);
- this.fill();
- }
- break;
-
- case 'td':
- //Roo.log(className);
- if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
- var day = parseInt(html, 10) || 1;
- var year = this.viewDate.getUTCFullYear(),
- month = this.viewDate.getUTCMonth();
-
- if (className.indexOf('old') > -1) {
- if(month === 0 ){
- month = 11;
- year -= 1;
- }else{
- month -= 1;
- }
- } else if (className.indexOf('new') > -1) {
- if (month == 11) {
- month = 0;
- year += 1;
- } else {
- month += 1;
- }
- }
- //Roo.log([year,month,day]);
- this.date = this.UTCDate(year, month, day,0,0,0,0);
- this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
-// this.fill();
- //Roo.log(this.formatDate(this.date));
- this.setValue(this.formatDate(this.date));
- this.hide();
- }
- break;
+ var input = {
+ tag: 'input',
+ id : id,
+ type : this.inputType,
+ //value : (!this.checked) ? this.valueOff : this.inputValue,
+ value : this.inputValue,
+ cls : 'roo-radio',
+ placeholder : this.placeholder || '' // ?? needed????
+
+ };
+ if (this.weight) { // Validity check?
+ input.cls += " radio-" + this.weight;
}
- },
-
- setStartDate: function(startDate)
- {
- this.startDate = startDate || -Infinity;
- if (this.startDate !== -Infinity) {
- this.startDate = this.parseDate(this.startDate);
+ if (this.disabled) {
+ input.disabled=true;
}
- this.update();
- this.updateNavArrows();
- },
-
- setEndDate: function(endDate)
- {
- this.endDate = endDate || Infinity;
- if (this.endDate !== Infinity) {
- this.endDate = this.parseDate(this.endDate);
+
+ if(this.checked){
+ input.checked = this.checked;
}
- this.update();
- this.updateNavArrows();
- },
-
- setDaysOfWeekDisabled: function(daysOfWeekDisabled)
- {
- this.daysOfWeekDisabled = daysOfWeekDisabled || [];
- if (typeof(this.daysOfWeekDisabled) !== 'object') {
- this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
+
+ if (this.name) {
+ input.name = this.name;
}
- this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
- return parseInt(d, 10);
- });
- this.update();
- this.updateNavArrows();
- },
-
- updateNavArrows: function()
- {
- if(this.singleMode){
- return;
+
+ if (this.size) {
+ input.cls += ' input-' + this.size;
}
- var d = new Date(this.viewDate),
- year = d.getUTCFullYear(),
- month = d.getUTCMonth();
+ //?? can span's inline have a width??
- Roo.each(this.picker().select('.prev', true).elements, function(v){
- v.show();
- switch (this.viewMode) {
- case 0:
-
- if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
- v.hide();
- }
- break;
- case 1:
- case 2:
- if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
- v.hide();
- }
- break;
+ var settings=this;
+ ['xs','sm','md','lg'].map(function(size){
+ if (settings[size]) {
+ cfg.cls += ' col-' + size + '-' + settings[size];
}
});
- Roo.each(this.picker().select('.next', true).elements, function(v){
- v.show();
- switch (this.viewMode) {
- case 0:
-
- if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
- v.hide();
- }
- break;
- case 1:
- case 2:
- if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
- v.hide();
- }
- break;
- }
- })
- },
-
- moveMonth: function(date, dir)
- {
- if (!dir) return date;
- var new_date = new Date(date.valueOf()),
- day = new_date.getUTCDate(),
- month = new_date.getUTCMonth(),
- mag = Math.abs(dir),
- new_month, test;
- dir = dir > 0 ? 1 : -1;
- if (mag == 1){
- test = dir == -1
- // If going back one month, make sure month is not current month
- // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
- ? function(){
- return new_date.getUTCMonth() == month;
- }
- // If going forward one month, make sure month is as expected
- // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
- : function(){
- return new_date.getUTCMonth() != new_month;
- };
- new_month = month + dir;
- new_date.setUTCMonth(new_month);
- // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
- if (new_month < 0 || new_month > 11)
- new_month = (new_month + 12) % 12;
- } else {
- // For magnitudes >1, move one month at a time...
- for (var i=0; i<mag; i++)
- // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
- new_date = this.moveMonth(new_date, dir);
- // ...then reset the day, keeping it in the new month
- new_month = new_date.getUTCMonth();
- new_date.setUTCDate(day);
- test = function(){
- return new_month != new_date.getUTCMonth();
+ var inputblock = input;
+
+ if (this.before || this.after) {
+
+ inputblock = {
+ cls : 'input-group',
+ tag : 'span',
+ cn : []
};
- }
- // Common date-resetting loop -- if date is beyond end of month, make it
- // end of month
- while (test()){
- new_date.setUTCDate(--day);
- new_date.setUTCMonth(new_month);
- }
- return new_date;
- },
-
- moveYear: function(date, dir)
- {
- return this.moveMonth(date, dir*12);
- },
-
- dateWithinRange: function(date)
- {
- return date >= this.startDate && date <= this.endDate;
- },
-
-
- remove: function()
- {
- this.picker().remove();
- }
-
-});
-
-Roo.apply(Roo.bootstrap.DateField, {
-
- head : {
- tag: 'thead',
- cn: [
- {
- tag: 'tr',
- cn: [
- {
- tag: 'th',
- cls: 'prev',
- html: '<i class="fa fa-arrow-left"/>'
- },
- {
- tag: 'th',
- cls: 'switch',
- colspan: '5'
- },
- {
- tag: 'th',
- cls: 'next',
- html: '<i class="fa fa-arrow-right"/>'
+ if (this.before) {
+ inputblock.cn.push({
+ tag :'span',
+ cls : 'input-group-addon',
+ html : this.before
+ });
}
-
- ]
- }
- ]
- },
-
- content : {
- tag: 'tbody',
- cn: [
- {
- tag: 'tr',
- cn: [
- {
- tag: 'td',
- colspan: '7'
+ inputblock.cn.push(input);
+ if (this.after) {
+ inputblock.cn.push({
+ tag :'span',
+ cls : 'input-group-addon',
+ html : this.after
+ });
}
- ]
+
+ };
+
+
+ if (this.fieldLabel && this.fieldLabel.length) {
+ cfg.cn.push(fieldLabel);
}
- ]
- },
-
- footer : {
- tag: 'tfoot',
- cn: [
- {
- tag: 'tr',
+
+ // normal bootstrap puts the input inside the label.
+ // however with our styled version - it has to go after the input.
+
+ //lbl.cn.push(inputblock);
+
+ var lblwrap = {
+ tag: 'span',
+ cls: 'radio' + inline,
cn: [
- {
- tag: 'th',
- colspan: '7',
- cls: 'today'
- }
-
+ inputblock,
+ lbl
]
+ };
+
+ cfg.cn.push( lblwrap);
+
+ if(this.boxLabel){
+ lbl.cn.push({
+ tag: 'span',
+ html: this.boxLabel
+ })
}
- ]
+
+
+ return cfg;
+
},
- dates:{
- en: {
- days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
- daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
- daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
- months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
- monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
- today: "Today"
+ initEvents : function()
+ {
+// Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
+
+ this.inputEl().on('click', this.onClick, this);
+ if (this.boxLabel) {
+ Roo.log('find label')
+ this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
}
+
},
- modes: [
+ inputEl: function ()
{
- clsName: 'days',
- navFnc: 'Month',
- navStep: 1
+ return this.el.select('input.roo-radio',true).first();
+ },
+ onClick : function()
+ {
+ Roo.log("click");
+ this.setChecked(true);
},
+
+ setChecked : function(state,suppressEvent)
{
- clsName: 'months',
- navFnc: 'FullYear',
- navStep: 1
+ if(state){
+ Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
+ v.dom.checked = false;
+ });
+ }
+ Roo.log(this.inputEl().dom);
+ this.checked = state;
+ this.inputEl().dom.checked = state;
+
+ if(suppressEvent !== true){
+ this.fireEvent('check', this, state);
+ }
+
+ //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
+
},
+
+ getGroupValue : function()
{
- clsName: 'years',
- navFnc: 'FullYear',
- navStep: 10
- }]
-});
-
-Roo.apply(Roo.bootstrap.DateField, {
-
- template : {
- tag: 'div',
- cls: 'datepicker dropdown-menu roo-dynamic',
- cn: [
- {
- tag: 'div',
- cls: 'datepicker-days',
- cn: [
- {
- tag: 'table',
- cls: 'table-condensed',
- cn:[
- Roo.bootstrap.DateField.head,
- {
- tag: 'tbody'
- },
- Roo.bootstrap.DateField.footer
- ]
- }
- ]
- },
- {
- tag: 'div',
- cls: 'datepicker-months',
- cn: [
- {
- tag: 'table',
- cls: 'table-condensed',
- cn:[
- Roo.bootstrap.DateField.head,
- Roo.bootstrap.DateField.content,
- Roo.bootstrap.DateField.footer
- ]
- }
- ]
- },
- {
- tag: 'div',
- cls: 'datepicker-years',
- cn: [
- {
- tag: 'table',
- cls: 'table-condensed',
- cn:[
- Roo.bootstrap.DateField.head,
- Roo.bootstrap.DateField.content,
- Roo.bootstrap.DateField.footer
- ]
+ var value = '';
+ Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
+ if(v.dom.checked == true){
+ value = v.dom.value;
}
- ]
- }
- ]
+ });
+
+ return value;
+ },
+
+ /**
+ * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
+ * @return {Mixed} value The field value
+ */
+ getValue : function(){
+ return this.getGroupValue();
}
+
});
+//<script type="text/javascript">
- /*
- * - LGPL
+/*
+ * Based Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ * LGPL
*
- * TimeField
- *
*/
-
+
/**
- * @class Roo.bootstrap.TimeField
- * @extends Roo.bootstrap.Input
- * Bootstrap DateField class
- *
- *
- * @constructor
- * Create a new TimeField
- * @param {Object} config The config object
+ * @class Roo.HtmlEditorCore
+ * @extends Roo.Component
+ * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
+ *
+ * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
*/
-Roo.bootstrap.TimeField = function(config){
- Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
+Roo.HtmlEditorCore = function(config){
+
+
+ Roo.HtmlEditorCore.superclass.constructor.call(this, config);
+
+
this.addEvents({
- /**
- * @event show
- * Fires when this field show.
- * @param {Roo.bootstrap.DateField} thisthis
- * @param {Mixed} date The date value
- */
- show : true,
- /**
- * @event show
- * Fires when this field hide.
- * @param {Roo.bootstrap.DateField} this
- * @param {Mixed} date The date value
- */
- hide : true,
- /**
- * @event select
- * Fires when select a date.
- * @param {Roo.bootstrap.DateField} this
- * @param {Mixed} date The date value
- */
- select : true
- });
+ /**
+ * @event initialize
+ * Fires when the editor is fully initialized (including the iframe)
+ * @param {Roo.HtmlEditorCore} this
+ */
+ initialize: true,
+ /**
+ * @event activate
+ * Fires when the editor is first receives the focus. Any insertion must wait
+ * until after this event.
+ * @param {Roo.HtmlEditorCore} this
+ */
+ activate: true,
+ /**
+ * @event beforesync
+ * Fires before the textarea is updated with content from the editor iframe. Return false
+ * to cancel the sync.
+ * @param {Roo.HtmlEditorCore} this
+ * @param {String} html
+ */
+ beforesync: true,
+ /**
+ * @event beforepush
+ * Fires before the iframe editor is updated with content from the textarea. Return false
+ * to cancel the push.
+ * @param {Roo.HtmlEditorCore} this
+ * @param {String} html
+ */
+ beforepush: true,
+ /**
+ * @event sync
+ * Fires when the textarea is updated with content from the editor iframe.
+ * @param {Roo.HtmlEditorCore} this
+ * @param {String} html
+ */
+ sync: true,
+ /**
+ * @event push
+ * Fires when the iframe editor is updated with content from the textarea.
+ * @param {Roo.HtmlEditorCore} this
+ * @param {String} html
+ */
+ push: true,
+
+ /**
+ * @event editorevent
+ * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+ * @param {Roo.HtmlEditorCore} this
+ */
+ editorevent: true
+
+ });
+
+ // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
+
+ // defaults : white / black...
+ this.applyBlacklists();
+
+
+
};
-Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
+
+Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
+
+
+ /**
+ * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
+ */
+
+ owner : false,
+
+ /**
+ * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
+ * Roo.resizable.
+ */
+ resizable : false,
+ /**
+ * @cfg {Number} height (in pixels)
+ */
+ height: 300,
+ /**
+ * @cfg {Number} width (in pixels)
+ */
+ width: 500,
/**
- * @cfg {String} format
- * The default time format string which can be overriden for localization support. The format must be
- * valid according to {@link Date#parseDate} (defaults to 'H:i').
+ * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
+ *
*/
- format : "H:i",
-
- onRender: function(ct, position)
- {
-
- Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
-
- this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
-
- this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-
- this.pop = this.picker().select('>.datepicker-time',true).first();
- this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-
- this.picker().on('mousedown', this.onMousedown, this);
- this.picker().on('click', this.onClick, this);
-
- this.picker().addClass('datepicker-dropdown');
+ stylesheets: false,
- this.fillTime();
- this.update();
-
- this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
- this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
- this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
- this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
- this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
- this.pop.select('button.ok', true).first().on('click', this.setTime, this);
-
- },
+ // id of frame..
+ frameId: false,
- fireKey: function(e){
- if (!this.picker().isVisible()){
- if (e.keyCode == 27) { // allow escape to hide and re-show picker
- this.show();
- }
- return;
- }
-
- e.preventDefault();
-
- switch(e.keyCode){
- case 27: // escape
- this.hide();
- break;
- case 37: // left
- case 39: // right
- this.onTogglePeriod();
- break;
- case 38: // up
- this.onIncrementMinutes();
- break;
- case 40: // down
- this.onDecrementMinutes();
- break;
- case 13: // enter
- case 9: // tab
- this.setTime();
- break;
- }
- },
+ // private properties
+ validationEvent : false,
+ deferHeight: true,
+ initialized : false,
+ activated : false,
+ sourceEditMode : false,
+ onFocus : Roo.emptyFn,
+ iframePad:3,
+ hideMode:'offsets',
- onClick: function(e) {
- e.stopPropagation();
- e.preventDefault();
- },
+ clearUp: true,
- picker : function()
- {
- return this.el.select('.datepicker', true).first();
- },
+ // blacklist + whitelisted elements..
+ black: false,
+ white: false,
+
- fillTime: function()
- {
- var time = this.pop.select('tbody', true).first();
-
- time.dom.innerHTML = '';
-
- time.createChild({
- tag: 'tr',
- cn: [
- {
- tag: 'td',
- cn: [
- {
- tag: 'a',
- href: '#',
- cls: 'btn',
- cn: [
- {
- tag: 'span',
- cls: 'hours-up glyphicon glyphicon-chevron-up'
- }
- ]
- }
- ]
- },
- {
- tag: 'td',
- cls: 'separator'
- },
- {
- tag: 'td',
- cn: [
- {
- tag: 'a',
- href: '#',
- cls: 'btn',
- cn: [
- {
- tag: 'span',
- cls: 'minutes-up glyphicon glyphicon-chevron-up'
- }
- ]
- }
- ]
- },
- {
- tag: 'td',
- cls: 'separator'
- }
- ]
- });
-
- time.createChild({
- tag: 'tr',
- cn: [
- {
- tag: 'td',
- cn: [
- {
- tag: 'span',
- cls: 'timepicker-hour',
- html: '00'
- }
- ]
- },
- {
- tag: 'td',
- cls: 'separator',
- html: ':'
- },
- {
- tag: 'td',
- cn: [
- {
- tag: 'span',
- cls: 'timepicker-minute',
- html: '00'
- }
- ]
- },
- {
- tag: 'td',
- cls: 'separator'
- },
- {
- tag: 'td',
- cn: [
- {
- tag: 'button',
- type: 'button',
- cls: 'btn btn-primary period',
- html: 'AM'
-
- }
- ]
- }
- ]
- });
-
- time.createChild({
- tag: 'tr',
- cn: [
- {
- tag: 'td',
- cn: [
- {
- tag: 'a',
- href: '#',
- cls: 'btn',
- cn: [
- {
- tag: 'span',
- cls: 'hours-down glyphicon glyphicon-chevron-down'
- }
- ]
- }
- ]
- },
- {
- tag: 'td',
- cls: 'separator'
- },
- {
- tag: 'td',
- cn: [
- {
- tag: 'a',
- href: '#',
- cls: 'btn',
- cn: [
- {
- tag: 'span',
- cls: 'minutes-down glyphicon glyphicon-chevron-down'
- }
- ]
- }
- ]
- },
- {
- tag: 'td',
- cls: 'separator'
- }
- ]
- });
+
+ /**
+ * Protected method that will not generally be called directly. It
+ * is called when the editor initializes the iframe with HTML contents. Override this method if you
+ * want to change the initialization markup of the iframe (e.g. to add stylesheets).
+ */
+ getDocMarkup : function(){
+ // body styles..
+ var st = '';
- },
-
- update: function()
- {
+ // inherit styels from page...??
+ if (this.stylesheets === false) {
+
+ Roo.get(document.head).select('style').each(function(node) {
+ st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+ });
+
+ Roo.get(document.head).select('link').each(function(node) {
+ st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+ });
+
+ } else if (!this.stylesheets.length) {
+ // simple..
+ st = '<style type="text/css">' +
+ 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+ '</style>';
+ } else {
+
+ }
- this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
+ st += '<style type="text/css">' +
+ 'IMG { cursor: pointer } ' +
+ '</style>';
+
- this.fill();
+ return '<html><head>' + st +
+ //<style type="text/css">' +
+ //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
+ //'</style>' +
+ ' </head><body class="roo-htmleditor-body"></body></html>';
},
-
- fill: function()
+
+ // private
+ onRender : function(ct, position)
{
- var hours = this.time.getHours();
- var minutes = this.time.getMinutes();
- var period = 'AM';
+ var _t = this;
+ //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
+ this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
- if(hours > 11){
- period = 'PM';
- }
- if(hours == 0){
- hours = 12;
- }
+ this.el.dom.style.border = '0 none';
+ this.el.dom.setAttribute('tabIndex', -1);
+ this.el.addClass('x-hidden hide');
- if(hours > 12){
- hours = hours - 12;
- }
- if(hours < 10){
- hours = '0' + hours;
+ if(Roo.isIE){ // fix IE 1px bogus margin
+ this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
}
+
- if(minutes < 10){
- minutes = '0' + minutes;
- }
+ this.frameId = Roo.id();
- this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
- this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
- this.pop.select('button', true).first().dom.innerHTML = period;
+
- },
-
- place: function()
- {
- this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
+ var iframe = this.owner.wrap.createChild({
+ tag: 'iframe',
+ cls: 'form-control', // bootstrap..
+ id: this.frameId,
+ name: this.frameId,
+ frameBorder : 'no',
+ 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
+ }, this.el
+ );
- var cls = ['bottom'];
- if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
- cls.pop();
- cls.push('top');
- }
+ this.iframe = iframe.dom;
+
+ this.assignDocWin();
- cls.push('right');
+ this.doc.designMode = 'on';
+
+ this.doc.open();
+ this.doc.write(this.getDocMarkup());
+ this.doc.close();
+
- if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
- cls.pop();
- cls.push('left');
+ var task = { // must defer to wait for browser to be ready
+ run : function(){
+ //console.log("run task?" + this.doc.readyState);
+ this.assignDocWin();
+ if(this.doc.body || this.doc.readyState == 'complete'){
+ try {
+ this.doc.designMode="on";
+ } catch (e) {
+ return;
+ }
+ Roo.TaskMgr.stop(task);
+ this.initEditor.defer(10, this);
+ }
+ },
+ interval : 10,
+ duration: 10000,
+ scope: this
+ };
+ Roo.TaskMgr.start(task);
+
+ },
+
+ // private
+ onResize : function(w, h)
+ {
+ Roo.log('resize: ' +w + ',' + h );
+ //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
+ if(!this.iframe){
+ return;
+ }
+ if(typeof w == 'number'){
+
+ this.iframe.style.width = w + 'px';
+ }
+ if(typeof h == 'number'){
+
+ this.iframe.style.height = h + 'px';
+ if(this.doc){
+ (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
+ }
}
- this.picker().addClass(cls.join('-'));
+ },
+
+ /**
+ * Toggles the editor between standard and source edit mode.
+ * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+ */
+ toggleSourceEdit : function(sourceEditMode){
- var _this = this;
+ this.sourceEditMode = sourceEditMode === true;
- Roo.each(cls, function(c){
- if(c == 'bottom'){
- _this.picker().setTop(_this.inputEl().getHeight());
- return;
+ if(this.sourceEditMode){
+
+ Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
+
+ }else{
+ Roo.get(this.iframe).removeClass(['x-hidden','hide']);
+ //this.iframe.className = '';
+ this.deferFocus();
+ }
+ //this.setSize(this.owner.wrap.getSize());
+ //this.fireEvent('editmodechange', this, this.sourceEditMode);
+ },
+
+
+
+
+ /**
+ * Protected method that will not generally be called directly. If you need/want
+ * custom HTML cleanup, this is the method you should override.
+ * @param {String} html The HTML to be cleaned
+ * return {String} The cleaned HTML
+ */
+ cleanHtml : function(html){
+ html = String(html);
+ if(html.length > 5){
+ if(Roo.isSafari){ // strip safari nonsense
+ html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
}
- if(c == 'top'){
- _this.picker().setTop(0 - _this.picker().getHeight());
- return;
+ }
+ if(html == ' '){
+ html = '';
+ }
+ return html;
+ },
+
+ /**
+ * HTML Editor -> Textarea
+ * Protected method that will not generally be called directly. Syncs the contents
+ * of the editor iframe with the textarea.
+ */
+ syncValue : function(){
+ if(this.initialized){
+ var bd = (this.doc.body || this.doc.documentElement);
+ //this.cleanUpPaste(); -- this is done else where and causes havoc..
+ var html = bd.innerHTML;
+ if(Roo.isSafari){
+ var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
+ var m = bs ? bs.match(/text-align:(.*?);/i) : false;
+ if(m && m[1]){
+ html = '<div style="'+m[0]+'">' + html + '</div>';
+ }
}
-
- if(c == 'left'){
- _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
- return;
+ html = this.cleanHtml(html);
+ // fix up the special chars.. normaly like back quotes in word...
+ // however we do not want to do this with chinese..
+ html = html.replace(/([\x80-\uffff])/g, function (a, b) {
+ var cc = b.charCodeAt();
+ if (
+ (cc >= 0x4E00 && cc < 0xA000 ) ||
+ (cc >= 0x3400 && cc < 0x4E00 ) ||
+ (cc >= 0xf900 && cc < 0xfb00 )
+ ) {
+ return b;
+ }
+ return "&#"+cc+";"
+ });
+ if(this.owner.fireEvent('beforesync', this, html) !== false){
+ this.el.dom.value = html;
+ this.owner.fireEvent('sync', this, html);
}
- if(c == 'right'){
- _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
- return;
+ }
+ },
+
+ /**
+ * Protected method that will not generally be called directly. Pushes the value of the textarea
+ * into the iframe editor.
+ */
+ pushValue : function(){
+ if(this.initialized){
+ var v = this.el.dom.value.trim();
+
+// if(v.length < 1){
+// v = ' ';
+// }
+
+ if(this.owner.fireEvent('beforepush', this, v) !== false){
+ var d = (this.doc.body || this.doc.documentElement);
+ d.innerHTML = v;
+ this.cleanUpPaste();
+ this.el.dom.value = d.innerHTML;
+ this.owner.fireEvent('push', this, v);
}
- });
-
+ }
},
-
- onFocus : function()
- {
- Roo.bootstrap.TimeField.superclass.onFocus.call(this);
- this.show();
+
+ // private
+ deferFocus : function(){
+ this.focus.defer(10, this);
},
-
- onBlur : function()
- {
- Roo.bootstrap.TimeField.superclass.onBlur.call(this);
- this.hide();
+
+ // doc'ed in Field
+ focus : function(){
+ if(this.win && !this.sourceEditMode){
+ this.win.focus();
+ }else{
+ this.el.focus();
+ }
},
- show : function()
+ assignDocWin: function()
{
- this.picker().show();
- this.pop.show();
- this.update();
- this.place();
+ var iframe = this.iframe;
- this.fireEvent('show', this, this.date);
+ if(Roo.isIE){
+ this.doc = iframe.contentWindow.document;
+ this.win = iframe.contentWindow;
+ } else {
+// if (!Roo.get(this.frameId)) {
+// return;
+// }
+// this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+// this.win = Roo.get(this.frameId).dom.contentWindow;
+
+ if (!Roo.get(this.frameId) && !iframe.contentDocument) {
+ return;
+ }
+
+ this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
+ this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
+ }
},
- hide : function()
- {
- this.picker().hide();
- this.pop.hide();
+ // private
+ initEditor : function(){
+ //console.log("INIT EDITOR");
+ this.assignDocWin();
- this.fireEvent('hide', this, this.date);
- },
-
- setTime : function()
- {
- this.hide();
- this.setValue(this.time.format(this.format));
- this.fireEvent('select', this, this.date);
+ this.doc.designMode="on";
+ this.doc.open();
+ this.doc.write(this.getDocMarkup());
+ this.doc.close();
- },
-
- onMousedown: function(e){
- e.stopPropagation();
- e.preventDefault();
- },
-
- onIncrementHours: function()
- {
- Roo.log('onIncrementHours');
- this.time = this.time.add(Date.HOUR, 1);
- this.update();
+ var dbody = (this.doc.body || this.doc.documentElement);
+ //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
+ // this copies styles from the containing element into thsi one..
+ // not sure why we need all of this..
+ //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
- },
-
- onDecrementHours: function()
- {
- Roo.log('onDecrementHours');
- this.time = this.time.add(Date.HOUR, -1);
- this.update();
- },
-
- onIncrementMinutes: function()
- {
- Roo.log('onIncrementMinutes');
- this.time = this.time.add(Date.MINUTE, 1);
- this.update();
- },
-
- onDecrementMinutes: function()
- {
- Roo.log('onDecrementMinutes');
- this.time = this.time.add(Date.MINUTE, -1);
- this.update();
- },
-
- onTogglePeriod: function()
- {
- Roo.log('onTogglePeriod');
- this.time = this.time.add(Date.HOUR, 12);
- this.update();
- }
-
-
-});
+ //var ss = this.el.getStyles( 'background-image', 'background-repeat');
+ //ss['background-attachment'] = 'fixed'; // w3c
+ dbody.bgProperties = 'fixed'; // ie
+ //Roo.DomHelper.applyStyles(dbody, ss);
+ Roo.EventManager.on(this.doc, {
+ //'mousedown': this.onEditorEvent,
+ 'mouseup': this.onEditorEvent,
+ 'dblclick': this.onEditorEvent,
+ 'click': this.onEditorEvent,
+ 'keyup': this.onEditorEvent,
+ buffer:100,
+ scope: this
+ });
+ if(Roo.isGecko){
+ Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
+ }
+ if(Roo.isIE || Roo.isSafari || Roo.isOpera){
+ Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
+ }
+ this.initialized = true;
-Roo.apply(Roo.bootstrap.TimeField, {
-
- content : {
- tag: 'tbody',
- cn: [
- {
- tag: 'tr',
- cn: [
- {
- tag: 'td',
- colspan: '7'
- }
- ]
- }
- ]
+ this.owner.fireEvent('initialize', this);
+ this.pushValue();
},
-
- footer : {
- tag: 'tfoot',
- cn: [
- {
- tag: 'tr',
- cn: [
- {
- tag: 'th',
- colspan: '7',
- cls: '',
- cn: [
- {
- tag: 'button',
- cls: 'btn btn-info ok',
- html: 'OK'
- }
- ]
- }
-
- ]
- }
- ]
- }
-});
-
-Roo.apply(Roo.bootstrap.TimeField, {
-
- template : {
- tag: 'div',
- cls: 'datepicker dropdown-menu',
- cn: [
- {
- tag: 'div',
- cls: 'datepicker-time',
- cn: [
- {
- tag: 'table',
- cls: 'table-condensed',
- cn:[
- Roo.bootstrap.TimeField.content,
- Roo.bootstrap.TimeField.footer
- ]
- }
- ]
- }
- ]
- }
-});
-
-
-
- /*
- * - LGPL
- *
- * MonthField
- *
- */
-
-/**
- * @class Roo.bootstrap.MonthField
- * @extends Roo.bootstrap.Input
- * Bootstrap MonthField class
- *
- * @cfg {String} language default en
- *
- * @constructor
- * Create a new MonthField
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.MonthField = function(config){
- Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
-
- this.addEvents({
- /**
- * @event show
- * Fires when this field show.
- * @param {Roo.bootstrap.MonthField} this
- * @param {Mixed} date The date value
- */
- show : true,
- /**
- * @event show
- * Fires when this field hide.
- * @param {Roo.bootstrap.MonthField} this
- * @param {Mixed} date The date value
- */
- hide : true,
- /**
- * @event select
- * Fires when select a date.
- * @param {Roo.bootstrap.MonthField} this
- * @param {String} oldvalue The old value
- * @param {String} newvalue The new value
- */
- select : true
- });
-};
-Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
-
- onRender: function(ct, position)
- {
-
- Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
-
- this.language = this.language || 'en';
- this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
- this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
+ // private
+ onDestroy : function(){
- this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
- this.isInline = false;
- this.isInput = true;
- this.component = this.el.select('.add-on', true).first() || false;
- this.component = (this.component && this.component.length === 0) ? false : this.component;
- this.hasInput = this.component && this.inputEL().length;
- this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
- this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ if(this.rendered){
+
+ //for (var i =0; i < this.toolbars.length;i++) {
+ // // fixme - ask toolbars for heights?
+ // this.toolbars[i].onDestroy();
+ // }
+
+ //this.wrap.dom.innerHTML = '';
+ //this.wrap.remove();
+ }
+ },
+
+ // private
+ onFirstFocus : function(){
- this.picker().on('mousedown', this.onMousedown, this);
- this.picker().on('click', this.onClick, this);
+ this.assignDocWin();
- this.picker().addClass('datepicker-dropdown');
- Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
- v.setStyle('width', '189px');
- });
+ this.activated = true;
+
+
+ if(Roo.isGecko){ // prevent silly gecko errors
+ this.win.focus();
+ var s = this.win.getSelection();
+ if(!s.focusNode || s.focusNode.nodeType != 3){
+ var r = s.getRangeAt(0);
+ r.selectNodeContents((this.doc.body || this.doc.documentElement));
+ r.collapse(true);
+ this.deferFocus();
+ }
+ try{
+ this.execCmd('useCSS', true);
+ this.execCmd('styleWithCSS', false);
+ }catch(e){}
+ }
+ this.owner.fireEvent('activate', this);
+ },
+
+ // private
+ adjustFont: function(btn){
+ var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
+ //if(Roo.isSafari){ // safari
+ // adjust *= 2;
+ // }
+ var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
+ if(Roo.isSafari){ // safari
+ var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
+ v = (v < 10) ? 10 : v;
+ v = (v > 48) ? 48 : v;
+ v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
+
+ }
- this.fillMonths();
- this.update();
+ v = Math.max(1, v+adjust);
- if(this.isInline) {
- this.show();
+ this.execCmd('FontSize', v );
+ },
+
+ onEditorEvent : function(e)
+ {
+ this.owner.fireEvent('editorevent', this, e);
+ // this.updateToolbar();
+ this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
+ },
+
+ insertTag : function(tg)
+ {
+ // could be a bit smarter... -> wrap the current selected tRoo..
+ if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+
+ range = this.createRange(this.getSelection());
+ var wrappingNode = this.doc.createElement(tg.toLowerCase());
+ wrappingNode.appendChild(range.extractContents());
+ range.insertNode(wrappingNode);
+
+ return;
+
+
+
}
+ this.execCmd("formatblock", tg);
},
- setValue: function(v, suppressEvent)
- {
- var o = this.getValue();
+ insertText : function(txt)
+ {
- Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
- this.update();
+ var range = this.createRange();
+ range.deleteContents();
+ //alert(Sender.getAttribute('label'));
+
+ range.insertNode(this.doc.createTextNode(txt));
+ } ,
+
+
- if(suppressEvent !== true){
- this.fireEvent('select', this, o, v);
- }
-
+ /**
+ * Executes a Midas editor command on the editor document and performs necessary focus and
+ * toolbar updates. <b>This should only be called after the editor is initialized.</b>
+ * @param {String} cmd The Midas command
+ * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+ */
+ relayCmd : function(cmd, value){
+ this.win.focus();
+ this.execCmd(cmd, value);
+ this.owner.fireEvent('editorevent', this);
+ //this.updateToolbar();
+ this.owner.deferFocus();
},
-
- getValue: function()
- {
- return this.value;
+
+ /**
+ * Executes a Midas editor command directly on the editor document.
+ * For visual commands, you should use {@link #relayCmd} instead.
+ * <b>This should only be called after the editor is initialized.</b>
+ * @param {String} cmd The Midas command
+ * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+ */
+ execCmd : function(cmd, value){
+ this.doc.execCommand(cmd, false, value === undefined ? null : value);
+ this.syncValue();
},
-
- onClick: function(e)
+
+
+
+ /**
+ * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
+ * to insert tRoo.
+ * @param {String} text | dom node..
+ */
+ insertAtCursor : function(text)
{
- e.stopPropagation();
- e.preventDefault();
- var target = e.getTarget();
-
- if(target.nodeName.toLowerCase() === 'i'){
- target = Roo.get(target).dom.parentNode;
- }
- var nodeName = target.nodeName;
- var className = target.className;
- var html = target.innerHTML;
- if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
+ if(!this.activated){
return;
}
-
- this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
-
- this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
-
- this.hide();
-
- },
-
- picker : function()
- {
- return this.pickerEl;
+ /*
+ if(Roo.isIE){
+ this.win.focus();
+ var r = this.doc.selection.createRange();
+ if(r){
+ r.collapse(true);
+ r.pasteHTML(text);
+ this.syncValue();
+ this.deferFocus();
+
+ }
+ return;
+ }
+ */
+ if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
+ this.win.focus();
+
+
+ // from jquery ui (MIT licenced)
+ var range, node;
+ var win = this.win;
+
+ if (win.getSelection && win.getSelection().getRangeAt) {
+ range = win.getSelection().getRangeAt(0);
+ node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
+ range.insertNode(node);
+ } else if (win.document.selection && win.document.selection.createRange) {
+ // no firefox support
+ var txt = typeof(text) == 'string' ? text : text.outerHTML;
+ win.document.selection.createRange().pasteHTML(txt);
+ } else {
+ // no firefox support
+ var txt = typeof(text) == 'string' ? text : text.outerHTML;
+ this.execCmd('InsertHTML', txt);
+ }
+
+ this.syncValue();
+
+ this.deferFocus();
+ }
},
-
- fillMonths: function()
- {
- var i = 0;
- var months = this.picker().select('>.datepicker-months td', true).first();
-
- months.dom.innerHTML = '';
-
- while (i < 12) {
- var month = {
- tag: 'span',
- cls: 'month',
- html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
+ // private
+ mozKeyPress : function(e){
+ if(e.ctrlKey){
+ var c = e.getCharCode(), cmd;
+
+ if(c > 0){
+ c = String.fromCharCode(c).toLowerCase();
+ switch(c){
+ case 'b':
+ cmd = 'bold';
+ break;
+ case 'i':
+ cmd = 'italic';
+ break;
+
+ case 'u':
+ cmd = 'underline';
+ break;
+
+ case 'v':
+ this.cleanUpPaste.defer(100, this);
+ return;
+
+ }
+ if(cmd){
+ this.win.focus();
+ this.execCmd(cmd);
+ this.deferFocus();
+ e.preventDefault();
+ }
+
}
-
- months.createChild(month);
}
-
},
-
- update: function()
- {
- var _this = this;
-
- if(typeof(this.vIndex) == 'undefined' && this.value.length){
- this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
+
+ // private
+ fixKeys : function(){ // load time branching for fastest keydown performance
+ if(Roo.isIE){
+ return function(e){
+ var k = e.getKey(), r;
+ if(k == e.TAB){
+ e.stopEvent();
+ r = this.doc.selection.createRange();
+ if(r){
+ r.collapse(true);
+ r.pasteHTML('    ');
+ this.deferFocus();
+ }
+ return;
+ }
+
+ if(k == e.ENTER){
+ r = this.doc.selection.createRange();
+ if(r){
+ var target = r.parentElement();
+ if(!target || target.tagName.toLowerCase() != 'li'){
+ e.stopEvent();
+ r.pasteHTML('<br />');
+ r.collapse(false);
+ r.select();
+ }
+ }
+ }
+ if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+ this.cleanUpPaste.defer(100, this);
+ return;
+ }
+
+
+ };
+ }else if(Roo.isOpera){
+ return function(e){
+ var k = e.getKey();
+ if(k == e.TAB){
+ e.stopEvent();
+ this.win.focus();
+ this.execCmd('InsertHTML','    ');
+ this.deferFocus();
+ }
+ if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+ this.cleanUpPaste.defer(100, this);
+ return;
+ }
+
+ };
+ }else if(Roo.isSafari){
+ return function(e){
+ var k = e.getKey();
+
+ if(k == e.TAB){
+ e.stopEvent();
+ this.execCmd('InsertText','\t');
+ this.deferFocus();
+ return;
+ }
+ if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+ this.cleanUpPaste.defer(100, this);
+ return;
+ }
+
+ };
}
-
- Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
- e.removeClass('active');
-
- if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
- e.addClass('active');
- }
- })
- },
+ }(),
- place: function()
+ getAllAncestors: function()
{
- if(this.isInline) return;
-
- this.picker().removeClass(['bottom', 'top']);
-
- if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
- /*
- * place to the top of element!
- *
- */
-
- this.picker().addClass('top');
- this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
-
- return;
+ var p = this.getSelectedNode();
+ var a = [];
+ if (!p) {
+ a.push(p); // push blank onto stack..
+ p = this.getParentElement();
}
- this.picker().addClass('bottom');
- this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
+ while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
+ a.push(p);
+ p = p.parentNode;
+ }
+ a.push(this.doc.body);
+ return a;
},
+ lastSel : false,
+ lastSelNode : false,
- onFocus : function()
- {
- Roo.bootstrap.MonthField.superclass.onFocus.call(this);
- this.show();
- },
- onBlur : function()
+ getSelection : function()
{
- Roo.bootstrap.MonthField.superclass.onBlur.call(this);
-
- var d = this.inputEl().getValue();
-
- this.setValue(d);
-
- this.hide();
+ this.assignDocWin();
+ return Roo.isIE ? this.doc.selection : this.win.getSelection();
},
- show : function()
+ getSelectedNode: function()
{
- this.picker().show();
- this.picker().select('>.datepicker-months', true).first().show();
- this.update();
- this.place();
+ // this may only work on Gecko!!!
- this.fireEvent('show', this, this.date);
- },
-
- hide : function()
- {
- if(this.isInline) return;
- this.picker().hide();
- this.fireEvent('hide', this, this.date);
+ // should we cache this!!!!
- },
-
- onMousedown: function(e)
- {
- e.stopPropagation();
- e.preventDefault();
- },
-
- keyup: function(e)
- {
- Roo.bootstrap.MonthField.superclass.keyup.call(this);
- this.update();
- },
-
- fireKey: function(e)
- {
- if (!this.picker().isVisible()){
- if (e.keyCode == 27) // allow escape to hide and re-show picker
- this.show();
- return;
- }
- var dir;
- switch(e.keyCode){
- case 27: // escape
- this.hide();
- e.preventDefault();
- break;
- case 37: // left
- case 39: // right
- dir = e.keyCode == 37 ? -1 : 1;
-
- this.vIndex = this.vIndex + dir;
-
- if(this.vIndex < 0){
- this.vIndex = 0;
- }
-
- if(this.vIndex > 11){
- this.vIndex = 11;
- }
-
- if(isNaN(this.vIndex)){
- this.vIndex = 0;
- }
-
- this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
-
- break;
- case 38: // up
- case 40: // down
-
- dir = e.keyCode == 38 ? -1 : 1;
-
- this.vIndex = this.vIndex + dir * 4;
-
- if(this.vIndex < 0){
- this.vIndex = 0;
- }
-
- if(this.vIndex > 11){
- this.vIndex = 11;
- }
-
- if(isNaN(this.vIndex)){
- this.vIndex = 0;
- }
-
- this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
- break;
-
- case 13: // enter
-
- if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
- this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
- }
-
- this.hide();
- e.preventDefault();
- break;
- case 9: // tab
- if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
- this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
+
+ var range = this.createRange(this.getSelection()).cloneRange();
+
+ if (Roo.isIE) {
+ var parent = range.parentElement();
+ while (true) {
+ var testRange = range.duplicate();
+ testRange.moveToElementText(parent);
+ if (testRange.inRange(range)) {
+ break;
}
- this.hide();
- break;
- case 16: // shift
- case 17: // ctrl
- case 18: // alt
- break;
- default :
- this.hide();
-
+ if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
+ break;
+ }
+ parent = parent.parentElement;
+ }
+ return parent;
+ }
+
+ // is ancestor a text element.
+ var ac = range.commonAncestorContainer;
+ if (ac.nodeType == 3) {
+ ac = ac.parentNode;
+ }
+
+ var ar = ac.childNodes;
+
+ var nodes = [];
+ var other_nodes = [];
+ var has_other_nodes = false;
+ for (var i=0;i<ar.length;i++) {
+ if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
+ continue;
+ }
+ // fullly contained node.
+
+ if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
+ nodes.push(ar[i]);
+ continue;
+ }
+
+ // probably selected..
+ if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
+ other_nodes.push(ar[i]);
+ continue;
+ }
+ // outer..
+ if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
+ continue;
+ }
+
+
+ has_other_nodes = true;
+ }
+ if (!nodes.length && other_nodes.length) {
+ nodes= other_nodes;
+ }
+ if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
+ return false;
}
+
+ return nodes[0];
},
-
- remove: function()
+ createRange: function(sel)
{
- this.picker().remove();
- }
-
-});
-
-Roo.apply(Roo.bootstrap.MonthField, {
-
- content : {
- tag: 'tbody',
- cn: [
- {
- tag: 'tr',
- cn: [
- {
- tag: 'td',
- colspan: '7'
+ // this has strange effects when using with
+ // top toolbar - not sure if it's a great idea.
+ //this.editor.contentWindow.focus();
+ if (typeof sel != "undefined") {
+ try {
+ return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
+ } catch(e) {
+ return this.doc.createRange();
}
- ]
+ } else {
+ return this.doc.createRange();
}
- ]
},
+ getParentElement: function()
+ {
+
+ this.assignDocWin();
+ var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
+
+ var range = this.createRange(sel);
+
+ try {
+ var p = range.commonAncestorContainer;
+ while (p.nodeType == 3) { // text node
+ p = p.parentNode;
+ }
+ return p;
+ } catch (e) {
+ return null;
+ }
- dates:{
- en: {
- months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
- monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+ },
+ /***
+ *
+ * Range intersection.. the hard stuff...
+ * '-1' = before
+ * '0' = hits..
+ * '1' = after.
+ * [ -- selected range --- ]
+ * [fail] [fail]
+ *
+ * basically..
+ * if end is before start or hits it. fail.
+ * if start is after end or hits it fail.
+ *
+ * if either hits (but other is outside. - then it's not
+ *
+ *
+ **/
+
+
+ // @see http://www.thismuchiknow.co.uk/?p=64.
+ rangeIntersectsNode : function(range, node)
+ {
+ var nodeRange = node.ownerDocument.createRange();
+ try {
+ nodeRange.selectNode(node);
+ } catch (e) {
+ nodeRange.selectNodeContents(node);
}
- }
-});
-
-Roo.apply(Roo.bootstrap.MonthField, {
-
- template : {
- tag: 'div',
- cls: 'datepicker dropdown-menu roo-dynamic',
- cn: [
- {
- tag: 'div',
- cls: 'datepicker-months',
- cn: [
- {
- tag: 'table',
- cls: 'table-condensed',
- cn:[
- Roo.bootstrap.DateField.content
- ]
- }
- ]
- }
- ]
- }
-});
-
-
-
-
- /*
- * - LGPL
- *
- * CheckBox
- *
- */
-
-/**
- * @class Roo.bootstrap.CheckBox
- * @extends Roo.bootstrap.Input
- * Bootstrap CheckBox class
- *
- * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
- * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
- * @cfg {String} boxLabel The text that appears beside the checkbox
- * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
- * @cfg {Boolean} checked initnal the element
- * @cfg {Boolean} inline inline the element (default false)
- * @cfg {String} groupId the checkbox group id // normal just use for checkbox
- *
- * @constructor
- * Create a new CheckBox
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.CheckBox = function(config){
- Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
-
- this.addEvents({
- /**
- * @event check
- * Fires when the element is checked or unchecked.
- * @param {Roo.bootstrap.CheckBox} this This input
- * @param {Boolean} checked The new checked value
- */
- check : true
- });
-};
-
-Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
-
- inputType: 'checkbox',
- inputValue: 1,
- valueOff: 0,
- boxLabel: false,
- checked: false,
- weight : false,
- inline: false,
+ var rangeStartRange = range.cloneRange();
+ rangeStartRange.collapse(true);
- getAutoCreate : function()
+ var rangeEndRange = range.cloneRange();
+ rangeEndRange.collapse(false);
+
+ var nodeStartRange = nodeRange.cloneRange();
+ nodeStartRange.collapse(true);
+
+ var nodeEndRange = nodeRange.cloneRange();
+ nodeEndRange.collapse(false);
+
+ return rangeStartRange.compareBoundaryPoints(
+ Range.START_TO_START, nodeEndRange) == -1 &&
+ rangeEndRange.compareBoundaryPoints(
+ Range.START_TO_START, nodeStartRange) == 1;
+
+
+ },
+ rangeCompareNode : function(range, node)
{
- var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
+ var nodeRange = node.ownerDocument.createRange();
+ try {
+ nodeRange.selectNode(node);
+ } catch (e) {
+ nodeRange.selectNodeContents(node);
+ }
- var id = Roo.id();
- var cfg = {};
+ range.collapse(true);
+
+ nodeRange.collapse(true);
+
+ var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
+ var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
+
+ //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
+
+ var nodeIsBefore = ss == 1;
+ var nodeIsAfter = ee == -1;
+
+ if (nodeIsBefore && nodeIsAfter)
+ return 0; // outer
+ if (!nodeIsBefore && nodeIsAfter)
+ return 1; //right trailed.
- cfg.cls = 'form-group ' + this.inputType; //input-group
+ if (nodeIsBefore && !nodeIsAfter)
+ return 2; // left trailed.
+ // fully contined.
+ return 3;
+ },
+
+ // private? - in a new class?
+ cleanUpPaste : function()
+ {
+ // cleans up the whole document..
+ Roo.log('cleanuppaste');
- if(this.inline){
- cfg.cls += ' ' + this.inputType + '-inline';
+ this.cleanUpChildren(this.doc.body);
+ var clean = this.cleanWordChars(this.doc.body.innerHTML);
+ if (clean != this.doc.body.innerHTML) {
+ this.doc.body.innerHTML = clean;
}
- var input = {
- tag: 'input',
- id : id,
- type : this.inputType,
- value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
- cls : 'roo-' + this.inputType, //'form-box',
- placeholder : this.placeholder || ''
+ },
+
+ cleanWordChars : function(input) {// change the chars to hex code
+ var he = Roo.HtmlEditorCore;
+
+ var output = input;
+ Roo.each(he.swapCodes, function(sw) {
+ var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
- };
+ output = output.replace(swapper, sw[1]);
+ });
- if (this.weight) { // Validity check?
- cfg.cls += " " + this.inputType + "-" + this.weight;
+ return output;
+ },
+
+
+ cleanUpChildren : function (n)
+ {
+ if (!n.childNodes.length) {
+ return;
+ }
+ for (var i = n.childNodes.length-1; i > -1 ; i--) {
+ this.cleanUpChild(n.childNodes[i]);
}
+ },
+
+
- if (this.disabled) {
- input.disabled=true;
+
+ cleanUpChild : function (node)
+ {
+ var ed = this;
+ //console.log(node);
+ if (node.nodeName == "#text") {
+ // clean up silly Windows -- stuff?
+ return;
+ }
+ if (node.nodeName == "#comment") {
+ node.parentNode.removeChild(node);
+ // clean up silly Windows -- stuff?
+ return;
}
+ var lcname = node.tagName.toLowerCase();
+ // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
+ // whitelist of tags..
- if(this.checked){
- input.checked = this.checked;
+ if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
+ // remove node.
+ node.parentNode.removeChild(node);
+ return;
+
}
- if (this.name) {
- input.name = this.name;
+ var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
+
+ // remove <a name=....> as rendering on yahoo mailer is borked with this.
+ // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
+
+ //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
+ // remove_keep_children = true;
+ //}
+
+ if (remove_keep_children) {
+ this.cleanUpChildren(node);
+ // inserts everything just before this node...
+ while (node.childNodes.length) {
+ var cn = node.childNodes[0];
+ node.removeChild(cn);
+ node.parentNode.insertBefore(cn, node);
+ }
+ node.parentNode.removeChild(node);
+ return;
}
- if (this.size) {
- input.cls += ' input-' + this.size;
+ if (!node.attributes || !node.attributes.length) {
+ this.cleanUpChildren(node);
+ return;
}
- var settings=this;
+ function cleanAttr(n,v)
+ {
+
+ if (v.match(/^\./) || v.match(/^\//)) {
+ return;
+ }
+ if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
+ return;
+ }
+ if (v.match(/^#/)) {
+ return;
+ }
+// Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
+ node.removeAttribute(n);
+
+ }
- ['xs','sm','md','lg'].map(function(size){
- if (settings[size]) {
- cfg.cls += ' col-' + size + '-' + settings[size];
+ var cwhite = this.cwhite;
+ var cblack = this.cblack;
+
+ function cleanStyle(n,v)
+ {
+ if (v.match(/expression/)) { //XSS?? should we even bother..
+ node.removeAttribute(n);
+ return;
}
- });
+
+ var parts = v.split(/;/);
+ var clean = [];
+
+ Roo.each(parts, function(p) {
+ p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
+ if (!p.length) {
+ return true;
+ }
+ var l = p.split(':').shift().replace(/\s+/g,'');
+ l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
+
+ if ( cwhite.length && cblack.indexOf(l) > -1) {
+// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
+ //node.removeAttribute(n);
+ return true;
+ }
+ //Roo.log()
+ // only allow 'c whitelisted system attributes'
+ if ( cwhite.length && cwhite.indexOf(l) < 0) {
+// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
+ //node.removeAttribute(n);
+ return true;
+ }
+
+
+
+
+ clean.push(p);
+ return true;
+ });
+ if (clean.length) {
+ node.setAttribute(n, clean.join(';'));
+ } else {
+ node.removeAttribute(n);
+ }
+
+ }
- var inputblock = input;
-
- if (this.before || this.after) {
+
+ for (var i = node.attributes.length-1; i > -1 ; i--) {
+ var a = node.attributes[i];
+ //console.log(a);
- inputblock = {
- cls : 'input-group',
- cn : []
- };
+ if (a.name.toLowerCase().substr(0,2)=='on') {
+ node.removeAttribute(a.name);
+ continue;
+ }
+ if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
+ node.removeAttribute(a.name);
+ continue;
+ }
+ if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
+ cleanAttr(a.name,a.value); // fixme..
+ continue;
+ }
+ if (a.name == 'style') {
+ cleanStyle(a.name,a.value);
+ continue;
+ }
+ /// clean up MS crap..
+ // tecnically this should be a list of valid class'es..
- if (this.before) {
- inputblock.cn.push({
- tag :'span',
- cls : 'input-group-addon',
- html : this.before
- });
+
+ if (a.name == 'class') {
+ if (a.value.match(/^Mso/)) {
+ node.className = '';
+ }
+
+ if (a.value.match(/body/)) {
+ node.className = '';
+ }
+ continue;
+ }
+
+ // style cleanup!?
+ // class cleanup?
+
+ }
+
+
+ this.cleanUpChildren(node);
+
+
+ },
+
+ /**
+ * Clean up MS wordisms...
+ */
+ cleanWord : function(node)
+ {
+
+
+ if (!node) {
+ this.cleanWord(this.doc.body);
+ return;
+ }
+ if (node.nodeName == "#text") {
+ // clean up silly Windows -- stuff?
+ return;
+ }
+ if (node.nodeName == "#comment") {
+ node.parentNode.removeChild(node);
+ // clean up silly Windows -- stuff?
+ return;
+ }
+
+ if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
+ node.parentNode.removeChild(node);
+ return;
+ }
+
+ // remove - but keep children..
+ if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+ while (node.childNodes.length) {
+ var cn = node.childNodes[0];
+ node.removeChild(cn);
+ node.parentNode.insertBefore(cn, node);
}
+ node.parentNode.removeChild(node);
+ this.iterateChildren(node, this.cleanWord);
+ return;
+ }
+ // clean styles
+ if (node.className.length) {
- inputblock.cn.push(input);
-
- if (this.after) {
- inputblock.cn.push({
- tag :'span',
- cls : 'input-group-addon',
- html : this.after
- });
+ var cn = node.className.split(/\W+/);
+ var cna = [];
+ Roo.each(cn, function(cls) {
+ if (cls.match(/Mso[a-zA-Z]+/)) {
+ return;
+ }
+ cna.push(cls);
+ });
+ node.className = cna.length ? cna.join(' ') : '';
+ if (!cna.length) {
+ node.removeAttribute("class");
}
-
}
- if (align ==='left' && this.fieldLabel.length) {
- Roo.log("left and has label");
- cfg.cn = [
-
- {
- tag: 'label',
- 'for' : id,
- cls : 'control-label col-md-' + this.labelWidth,
- html : this.fieldLabel
-
- },
- {
- cls : "col-md-" + (12 - this.labelWidth),
- cn: [
- inputblock
- ]
- }
-
- ];
- } else if ( this.fieldLabel.length) {
- Roo.log(" label");
- cfg.cn = [
-
- {
- tag: this.boxLabel ? 'span' : 'label',
- 'for': id,
- cls: 'control-label box-input-label',
- //cls : 'input-group-addon',
- html : this.fieldLabel
-
- },
-
- inputblock
-
- ];
-
- } else {
-
- Roo.log(" no label && no align");
- cfg.cn = [ inputblock ] ;
-
-
+ if (node.hasAttribute("lang")) {
+ node.removeAttribute("lang");
}
- if(this.boxLabel){
- var boxLabelCfg = {
- tag: 'label',
- //'for': id, // box label is handled by onclick - so no for...
- cls: 'box-label',
- html: this.boxLabel
- }
+
+ if (node.hasAttribute("style")) {
- if(this.tooltip){
- boxLabelCfg.tooltip = this.tooltip;
+ var styles = node.getAttribute("style").split(";");
+ var nstyle = [];
+ Roo.each(styles, function(s) {
+ if (!s.match(/:/)) {
+ return;
+ }
+ var kv = s.split(":");
+ if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
+ return;
+ }
+ // what ever is left... we allow.
+ nstyle.push(s);
+ });
+ node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+ if (!nstyle.length) {
+ node.removeAttribute('style');
}
-
- cfg.cn.push(boxLabelCfg);
}
+ this.iterateChildren(node, this.cleanWord);
-
- return cfg;
},
-
/**
- * return the real input element.
+ * iterateChildren of a Node, calling fn each time, using this as the scole..
+ * @param {DomNode} node node to iterate children of.
+ * @param {Function} fn method of this class to call on each item.
*/
- inputEl: function ()
- {
- return this.el.select('input.roo-' + this.inputType,true).first();
- },
-
- labelEl: function()
+ iterateChildren : function(node, fn)
{
- return this.el.select('label.control-label',true).first();
+ if (!node.childNodes.length) {
+ return;
+ }
+ for (var i = node.childNodes.length-1; i > -1 ; i--) {
+ fn.call(this, node.childNodes[i])
+ }
},
- /* depricated... */
- label: function()
- {
- return this.labelEl();
- },
- initEvents : function()
+ /**
+ * cleanTableWidths.
+ *
+ * Quite often pasting from word etc.. results in tables with column and widths.
+ * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
+ *
+ */
+ cleanTableWidths : function(node)
{
-// Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
+
+
+ if (!node) {
+ this.cleanTableWidths(this.doc.body);
+ return;
+ }
- this.inputEl().on('click', this.onClick, this);
+ // ignore list...
+ if (node.nodeName == "#text" || node.nodeName == "#comment") {
+ return;
+ }
+ Roo.log(node.tagName);
+ if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
+ this.iterateChildren(node, this.cleanTableWidths);
+ return;
+ }
+ if (node.hasAttribute('width')) {
+ node.removeAttribute('width');
+ }
- if (this.boxLabel) {
- this.el.select('label.box-label',true).first().on('click', this.onClick, this);
+
+ if (node.hasAttribute("style")) {
+ // pretty basic...
+
+ var styles = node.getAttribute("style").split(";");
+ var nstyle = [];
+ Roo.each(styles, function(s) {
+ if (!s.match(/:/)) {
+ return;
+ }
+ var kv = s.split(":");
+ if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
+ return;
+ }
+ // what ever is left... we allow.
+ nstyle.push(s);
+ });
+ node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+ if (!nstyle.length) {
+ node.removeAttribute('style');
+ }
}
- this.startValue = this.getValue();
+ this.iterateChildren(node, this.cleanTableWidths);
+
- if(this.groupId){
- Roo.bootstrap.CheckBox.register(this);
- }
},
- onClick : function()
- {
- this.setChecked(!this.checked);
- },
- setChecked : function(state,suppressEvent)
- {
- this.startValue = this.getValue();
+
+
+ domToHTML : function(currentElement, depth, nopadtext) {
- if(this.inputType == 'radio'){
-
- Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
- e.dom.checked = false;
- });
-
- this.inputEl().dom.checked = true;
-
- this.inputEl().dom.value = this.inputValue;
-
- if(suppressEvent !== true){
- this.fireEvent('check', this, true);
- }
-
- this.validate();
+ depth = depth || 0;
+ nopadtext = nopadtext || false;
+
+ if (!currentElement) {
+ return this.domToHTML(this.doc.body);
+ }
+
+ //Roo.log(currentElement);
+ var j;
+ var allText = false;
+ var nodeName = currentElement.nodeName;
+ var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
+
+ if (nodeName == '#text') {
- return;
+ return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
+ }
+
+
+ var ret = '';
+ if (nodeName != 'BODY') {
+
+ var i = 0;
+ // Prints the node tagName, such as <A>, <IMG>, etc
+ if (tagName) {
+ var attr = [];
+ for(i = 0; i < currentElement.attributes.length;i++) {
+ // quoting?
+ var aname = currentElement.attributes.item(i).name;
+ if (!currentElement.attributes.item(i).value.length) {
+ continue;
+ }
+ attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
+ }
+
+ ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
+ }
+ else {
+
+ // eack
+ }
+ } else {
+ tagName = false;
}
-
- this.checked = state;
-
- this.inputEl().dom.checked = state;
-
- this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
-
- if(suppressEvent !== true){
- this.fireEvent('check', this, state);
+ if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
+ return ret;
}
-
- this.validate();
- },
-
- getValue : function()
- {
- if(this.inputType == 'radio'){
- return this.getGroupValue();
+ if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
+ nopadtext = true;
}
- return this.inputEl().getValue();
-
- },
-
- getGroupValue : function()
- {
- if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
- return '';
- }
- return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
- },
-
- setValue : function(v,suppressEvent)
- {
- if(this.inputType == 'radio'){
- this.setGroupValue(v, suppressEvent);
- return;
+ // Traverse the tree
+ i = 0;
+ var currentElementChild = currentElement.childNodes.item(i);
+ var allText = true;
+ var innerHTML = '';
+ lastnode = '';
+ while (currentElementChild) {
+ // Formatting code (indent the tree so it looks nice on the screen)
+ var nopad = nopadtext;
+ if (lastnode == 'SPAN') {
+ nopad = true;
+ }
+ // text
+ if (currentElementChild.nodeName == '#text') {
+ var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
+ toadd = nopadtext ? toadd : toadd.trim();
+ if (!nopad && toadd.length > 80) {
+ innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
+ }
+ innerHTML += toadd;
+
+ i++;
+ currentElementChild = currentElement.childNodes.item(i);
+ lastNode = '';
+ continue;
+ }
+ allText = false;
+
+ innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
+
+ // Recursively traverse the tree structure of the child node
+ innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
+ lastnode = currentElementChild.nodeName;
+ i++;
+ currentElementChild=currentElement.childNodes.item(i);
}
- this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
+ ret += innerHTML;
- this.validate();
- },
-
- setGroupValue : function(v, suppressEvent)
- {
- this.startValue = this.getValue();
+ if (!allText) {
+ // The remaining code is mostly for formatting the tree
+ ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
+ }
- Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
- e.dom.checked = false;
-
- if(e.dom.value == v){
- e.dom.checked = true;
- }
- });
- if(suppressEvent !== true){
- this.fireEvent('check', this, true);
+ if (tagName) {
+ ret+= "</"+tagName+">";
}
-
- this.validate();
+ return ret;
- return;
},
-
- validate : function()
- {
- if(
- this.disabled ||
- (this.inputType == 'radio' && this.validateRadio()) ||
- (this.inputType == 'checkbox' && this.validateCheckbox())
- ){
- this.markValid();
- return true;
- }
- this.markInvalid();
- return false;
- },
-
- validateRadio : function()
+ applyBlacklists : function()
{
- var valid = false;
+ var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
+ var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
- Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
- if(!e.dom.checked){
+ this.white = [];
+ this.black = [];
+ Roo.each(Roo.HtmlEditorCore.white, function(tag) {
+ if (b.indexOf(tag) > -1) {
return;
}
+ this.white.push(tag);
- valid = true;
-
- return false;
- });
-
- return valid;
- },
-
- validateCheckbox : function()
- {
- if(!this.groupId){
- return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
- }
+ }, this);
- var group = Roo.bootstrap.CheckBox.get(this.groupId);
+ Roo.each(w, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.white.indexOf(tag) > -1) {
+ return;
+ }
+ this.white.push(tag);
+
+ }, this);
- if(!group){
- return false;
- }
- var r = false;
+ Roo.each(Roo.HtmlEditorCore.black, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ this.black.push(tag);
+
+ }, this);
- for(var i in group){
- if(r){
- break;
+ Roo.each(b, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.black.indexOf(tag) > -1) {
+ return;
}
+ this.black.push(tag);
- r = (group[i].getValue() == group[i].inputValue) ? true : false;
- }
+ }, this);
- return r;
- },
-
- /**
- * Mark this field as valid
- */
- markValid : function()
- {
- if(this.allowBlank){
- return;
- }
- var _this = this;
+ w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
+ b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
- this.fireEvent('valid', this);
+ this.cwhite = [];
+ this.cblack = [];
+ Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ this.cwhite.push(tag);
+
+ }, this);
- if(this.inputType == 'radio'){
- Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
- e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
- e.findParent('.form-group', false, true).addClass(_this.validClass);
- });
+ Roo.each(w, function(tag) {
+ if (b.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.cwhite.indexOf(tag) > -1) {
+ return;
+ }
+ this.cwhite.push(tag);
- return;
- }
+ }, this);
- if(!this.groupId){
- this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
- this.el.findParent('.form-group', false, true).addClass(this.validClass);
- return;
- }
- var group = Roo.bootstrap.CheckBox.get(this.groupId);
+ Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ this.cblack.push(tag);
- if(!group){
- return;
- }
+ }, this);
- for(var i in group){
- group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
- group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
- }
+ Roo.each(b, function(tag) {
+ if (w.indexOf(tag) > -1) {
+ return;
+ }
+ if (this.cblack.indexOf(tag) > -1) {
+ return;
+ }
+ this.cblack.push(tag);
+
+ }, this);
},
-
- /**
- * Mark this field as invalid
- * @param {String} msg The validation message
- */
- markInvalid : function(msg)
+
+ setStylesheets : function(stylesheets)
{
- if(this.allowBlank){
- return;
- }
-
- var _this = this;
-
- this.fireEvent('invalid', this, msg);
-
- if(this.inputType == 'radio'){
- Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
- e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
- e.findParent('.form-group', false, true).addClass(_this.invalidClass);
+ if(typeof(stylesheets) == 'string'){
+ Roo.get(this.iframe.contentDocument.head).createChild({
+ tag : 'link',
+ rel : 'stylesheet',
+ type : 'text/css',
+ href : stylesheets
});
return;
}
-
- if(!this.groupId){
- this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
- this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
- return;
- }
-
- var group = Roo.bootstrap.CheckBox.get(this.groupId);
+ var _this = this;
+
+ Roo.each(stylesheets, function(s) {
+ if(!s.length){
+ return;
+ }
- if(!group){
- return;
- }
+ Roo.get(_this.iframe.contentDocument.head).createChild({
+ tag : 'link',
+ rel : 'stylesheet',
+ type : 'text/css',
+ href : s
+ });
+ });
+
- for(var i in group){
- group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
- group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
- }
+ },
+
+ removeStylesheets : function()
+ {
+ var _this = this;
+ Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
+ s.remove();
+ });
}
+ // hide stuff that is not compatible
+ /**
+ * @event blur
+ * @hide
+ */
+ /**
+ * @event change
+ * @hide
+ */
+ /**
+ * @event focus
+ * @hide
+ */
+ /**
+ * @event specialkey
+ * @hide
+ */
+ /**
+ * @cfg {String} fieldClass @hide
+ */
+ /**
+ * @cfg {String} focusClass @hide
+ */
+ /**
+ * @cfg {String} autoCreate @hide
+ */
+ /**
+ * @cfg {String} inputType @hide
+ */
+ /**
+ * @cfg {String} invalidClass @hide
+ */
+ /**
+ * @cfg {String} invalidText @hide
+ */
+ /**
+ * @cfg {String} msgFx @hide
+ */
+ /**
+ * @cfg {String} validateOnBlur @hide
+ */
});
-Roo.apply(Roo.bootstrap.CheckBox, {
+Roo.HtmlEditorCore.white = [
+ 'area', 'br', 'img', 'input', 'hr', 'wbr',
+
+ 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
+ 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
+ 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
+ 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
+ 'table', 'ul', 'xmp',
+
+ 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
+ 'thead', 'tr',
+
+ 'dir', 'menu', 'ol', 'ul', 'dl',
+
+ 'embed', 'object'
+];
+
+
+Roo.HtmlEditorCore.black = [
+ // 'embed', 'object', // enable - backend responsiblity to clean thiese
+ 'applet', //
+ 'base', 'basefont', 'bgsound', 'blink', 'body',
+ 'frame', 'frameset', 'head', 'html', 'ilayer',
+ 'iframe', 'layer', 'link', 'meta', 'object',
+ 'script', 'style' ,'title', 'xml' // clean later..
+];
+Roo.HtmlEditorCore.clean = [
+ 'script', 'style', 'title', 'xml'
+];
+Roo.HtmlEditorCore.remove = [
+ 'font'
+];
+// attributes..
+
+Roo.HtmlEditorCore.ablack = [
+ 'on'
+];
+
+Roo.HtmlEditorCore.aclean = [
+ 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
+];
+
+// protocols..
+Roo.HtmlEditorCore.pwhite= [
+ 'http', 'https', 'mailto'
+];
+
+// white listed style attributes.
+Roo.HtmlEditorCore.cwhite= [
+ // 'text-align', /// default is to allow most things..
+
+
+// 'font-size'//??
+];
+
+// black listed style attributes.
+Roo.HtmlEditorCore.cblack= [
+ // 'font-size' -- this can be set by the project
+];
+
+
+Roo.HtmlEditorCore.swapCodes =[
+ [ 8211, "--" ],
+ [ 8212, "--" ],
+ [ 8216, "'" ],
+ [ 8217, "'" ],
+ [ 8220, '"' ],
+ [ 8221, '"' ],
+ [ 8226, "*" ],
+ [ 8230, "..." ]
+];
+
+ /*
+ * - LGPL
+ *
+ * HtmlEditor
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.HtmlEditor
+ * @extends Roo.bootstrap.TextArea
+ * Bootstrap HtmlEditor class
+
+ * @constructor
+ * Create a new HtmlEditor
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.HtmlEditor = function(config){
+ Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
+ if (!this.toolbars) {
+ this.toolbars = [];
+ }
+ this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
+ this.addEvents({
+ /**
+ * @event initialize
+ * Fires when the editor is fully initialized (including the iframe)
+ * @param {HtmlEditor} this
+ */
+ initialize: true,
+ /**
+ * @event activate
+ * Fires when the editor is first receives the focus. Any insertion must wait
+ * until after this event.
+ * @param {HtmlEditor} this
+ */
+ activate: true,
+ /**
+ * @event beforesync
+ * Fires before the textarea is updated with content from the editor iframe. Return false
+ * to cancel the sync.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ beforesync: true,
+ /**
+ * @event beforepush
+ * Fires before the iframe editor is updated with content from the textarea. Return false
+ * to cancel the push.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ beforepush: true,
+ /**
+ * @event sync
+ * Fires when the textarea is updated with content from the editor iframe.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ sync: true,
+ /**
+ * @event push
+ * Fires when the iframe editor is updated with content from the textarea.
+ * @param {HtmlEditor} this
+ * @param {String} html
+ */
+ push: true,
+ /**
+ * @event editmodechange
+ * Fires when the editor switches edit modes
+ * @param {HtmlEditor} this
+ * @param {Boolean} sourceEdit True if source edit, false if standard editing.
+ */
+ editmodechange: true,
+ /**
+ * @event editorevent
+ * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
+ * @param {HtmlEditor} this
+ */
+ editorevent: true,
+ /**
+ * @event firstfocus
+ * Fires when on first focus - needed by toolbars..
+ * @param {HtmlEditor} this
+ */
+ firstfocus: true,
+ /**
+ * @event autosave
+ * Auto save the htmlEditor value as a file into Events
+ * @param {HtmlEditor} this
+ */
+ autosave: true,
+ /**
+ * @event savedpreview
+ * preview the saved version of htmlEditor
+ * @param {HtmlEditor} this
+ */
+ savedpreview: true
+ });
+};
+
+
+Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
- groups: {},
+ /**
+ * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
+ */
+ toolbars : false,
+
/**
- * register a CheckBox Group
- * @param {Roo.bootstrap.CheckBox} the CheckBox to add
- */
- register : function(checkbox)
- {
- if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
- this.groups[checkbox.groupId] = {};
- }
-
- if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
- return;
- }
-
- this.groups[checkbox.groupId][checkbox.name] = checkbox;
-
- },
+ * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
+ * Roo.resizable.
+ */
+ resizable : false,
+ /**
+ * @cfg {Number} height (in pixels)
+ */
+ height: 300,
+ /**
+ * @cfg {Number} width (in pixels)
+ */
+ width: false,
+
/**
- * fetch a CheckBox Group based on the group ID
- * @param {string} the group ID
- * @returns {Roo.bootstrap.CheckBox} the CheckBox group
- */
- get: function(groupId) {
- if (typeof(this.groups[groupId]) == 'undefined') {
- return false;
- }
-
- return this.groups[groupId] ;
- }
+ * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
+ *
+ */
+ stylesheets: false,
+ // id of frame..
+ frameId: false,
-});
-/*
- * - LGPL
- *
- * Radio
- *
- *
- * not inline
- *<div class="radio">
- <label>
- <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
- Option one is this and that—be sure to include why it's great
- </label>
-</div>
- *
- *
- *inline
- *<span>
- *<label class="radio-inline">fieldLabel</label>
- *<label class="radio-inline">
- <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
-</label>
-<span>
- *
- *
- */
-
-/**
- * @class Roo.bootstrap.Radio
- * @extends Roo.bootstrap.CheckBox
- * Bootstrap Radio class
-
- * @constructor
- * Create a new Radio
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.Radio = function(config){
- Roo.bootstrap.Radio.superclass.constructor.call(this, config);
-
-};
-
-Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
+ // private properties
+ validationEvent : false,
+ deferHeight: true,
+ initialized : false,
+ activated : false,
- inputType: 'radio',
- inputValue: '',
- valueOff: '',
+ onFocus : Roo.emptyFn,
+ iframePad:3,
+ hideMode:'offsets',
- getAutoCreate : function()
- {
- var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
- align = align || 'left'; // default...
-
-
-
- var id = Roo.id();
-
- var cfg = {
- tag : this.inline ? 'span' : 'div',
- cls : '',
- cn : []
- };
-
- var inline = this.inline ? ' radio-inline' : '';
-
- var lbl = {
- tag: 'label' ,
- // does not need for, as we wrap the input with it..
- 'for' : id,
- cls : 'control-label box-label' + inline,
- cn : []
- };
- var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
-
- var fieldLabel = {
- tag: 'label' ,
- //cls : 'control-label' + inline,
- html : this.fieldLabel,
- style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
- };
-
-
-
-
- var input = {
- tag: 'input',
- id : id,
- type : this.inputType,
- //value : (!this.checked) ? this.valueOff : this.inputValue,
- value : this.inputValue,
- cls : 'roo-radio',
- placeholder : this.placeholder || '' // ?? needed????
-
- };
- if (this.weight) { // Validity check?
- input.cls += " radio-" + this.weight;
- }
- if (this.disabled) {
- input.disabled=true;
- }
-
- if(this.checked){
- input.checked = this.checked;
- }
-
- if (this.name) {
- input.name = this.name;
- }
-
- if (this.size) {
- input.cls += ' input-' + this.size;
- }
-
- //?? can span's inline have a width??
+
+ tbContainer : false,
+
+ toolbarContainer :function() {
+ return this.wrap.select('.x-html-editor-tb',true).first();
+ },
+
+ /**
+ * Protected method that will not generally be called directly. It
+ * is called when the editor creates its toolbar. Override this method if you need to
+ * add custom toolbar buttons.
+ * @param {HtmlEditor} editor
+ */
+ createToolbar : function(){
- var settings=this;
- ['xs','sm','md','lg'].map(function(size){
- if (settings[size]) {
- cfg.cls += ' col-' + size + '-' + settings[size];
- }
- });
+ Roo.log("create toolbars");
- var inputblock = input;
+ this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
+ this.toolbars[0].render(this.toolbarContainer());
- if (this.before || this.after) {
-
- inputblock = {
- cls : 'input-group',
- tag : 'span',
- cn : []
- };
- if (this.before) {
- inputblock.cn.push({
- tag :'span',
- cls : 'input-group-addon',
- html : this.before
- });
- }
- inputblock.cn.push(input);
- if (this.after) {
- inputblock.cn.push({
- tag :'span',
- cls : 'input-group-addon',
- html : this.after
- });
- }
-
- };
+ return;
+// if (!editor.toolbars || !editor.toolbars.length) {
+// editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
+// }
+//
+// for (var i =0 ; i < editor.toolbars.length;i++) {
+// editor.toolbars[i] = Roo.factory(
+// typeof(editor.toolbars[i]) == 'string' ?
+// { xtype: editor.toolbars[i]} : editor.toolbars[i],
+// Roo.bootstrap.HtmlEditor);
+// editor.toolbars[i].init(editor);
+// }
+ },
+
+
+ // private
+ onRender : function(ct, position)
+ {
+ // Roo.log("Call onRender: " + this.xtype);
+ var _t = this;
+ Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
+
+ this.wrap = this.inputEl().wrap({
+ cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
+ });
- if (this.fieldLabel && this.fieldLabel.length) {
- cfg.cn.push(fieldLabel);
+ this.editorcore.onRender(ct, position);
+
+ if (this.resizable) {
+ this.resizeEl = new Roo.Resizable(this.wrap, {
+ pinned : true,
+ wrap: true,
+ dynamic : true,
+ minHeight : this.height,
+ height: this.height,
+ handles : this.resizable,
+ width: this.width,
+ listeners : {
+ resize : function(r, w, h) {
+ _t.onResize(w,h); // -something
+ }
+ }
+ });
+
}
+ this.createToolbar(this);
- // normal bootstrap puts the input inside the label.
- // however with our styled version - it has to go after the input.
-
- //lbl.cn.push(inputblock);
- var lblwrap = {
- tag: 'span',
- cls: 'radio' + inline,
- cn: [
- inputblock,
- lbl
- ]
- };
+ if(!this.width && this.resizable){
+ this.setSize(this.wrap.getSize());
+ }
+ if (this.resizeEl) {
+ this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
+ // should trigger onReize..
+ }
- cfg.cn.push( lblwrap);
+ },
+
+ // private
+ onResize : function(w, h)
+ {
+ Roo.log('resize: ' +w + ',' + h );
+ Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
+ var ew = false;
+ var eh = false;
- if(this.boxLabel){
- lbl.cn.push({
- tag: 'span',
- html: this.boxLabel
- })
+ if(this.inputEl() ){
+ if(typeof w == 'number'){
+ var aw = w - this.wrap.getFrameWidth('lr');
+ this.inputEl().setWidth(this.adjustWidth('textarea', aw));
+ ew = aw;
+ }
+ if(typeof h == 'number'){
+ var tbh = -11; // fixme it needs to tool bar size!
+ for (var i =0; i < this.toolbars.length;i++) {
+ // fixme - ask toolbars for heights?
+ tbh += this.toolbars[i].el.getHeight();
+ //if (this.toolbars[i].footer) {
+ // tbh += this.toolbars[i].footer.el.getHeight();
+ //}
+ }
+
+
+
+
+
+ var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
+ ah -= 5; // knock a few pixes off for look..
+ this.inputEl().setHeight(this.adjustWidth('textarea', ah));
+ var eh = ah;
+ }
}
-
-
- return cfg;
+ Roo.log('onResize:' + [w,h,ew,eh].join(',') );
+ this.editorcore.onResize(ew,eh);
},
-
- initEvents : function()
+
+ /**
+ * Toggles the editor between standard and source edit mode.
+ * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+ */
+ toggleSourceEdit : function(sourceEditMode)
{
-// Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
+ this.editorcore.toggleSourceEdit(sourceEditMode);
- this.inputEl().on('click', this.onClick, this);
- if (this.boxLabel) {
- Roo.log('find label')
- this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
+ if(this.editorcore.sourceEditMode){
+ Roo.log('editor - showing textarea');
+
+// Roo.log('in');
+// Roo.log(this.syncValue());
+ this.syncValue();
+ this.inputEl().removeClass(['hide', 'x-hidden']);
+ this.inputEl().dom.removeAttribute('tabIndex');
+ this.inputEl().focus();
+ }else{
+ Roo.log('editor - hiding textarea');
+// Roo.log('out')
+// Roo.log(this.pushValue());
+ this.pushValue();
+
+ this.inputEl().addClass(['hide', 'x-hidden']);
+ this.inputEl().dom.setAttribute('tabIndex', -1);
+ //this.deferFocus();
+ }
+
+ if(this.resizable){
+ this.setSize(this.wrap.getSize());
}
+ this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
},
-
- inputEl: function ()
- {
- return this.el.select('input.roo-radio',true).first();
+
+ // private (for BoxComponent)
+ adjustSize : Roo.BoxComponent.prototype.adjustSize,
+
+ // private (for BoxComponent)
+ getResizeEl : function(){
+ return this.wrap;
},
- onClick : function()
- {
- Roo.log("click");
- this.setChecked(true);
+
+ // private (for BoxComponent)
+ getPositionEl : function(){
+ return this.wrap;
},
-
- setChecked : function(state,suppressEvent)
- {
- if(state){
- Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
- v.dom.checked = false;
- });
- }
- Roo.log(this.inputEl().dom);
- this.checked = state;
- this.inputEl().dom.checked = state;
+
+ // private
+ initEvents : function(){
+ this.originalValue = this.getValue();
+ },
+
+// /**
+// * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+// * @method
+// */
+// markInvalid : Roo.emptyFn,
+// /**
+// * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
+// * @method
+// */
+// clearInvalid : Roo.emptyFn,
+
+ setValue : function(v){
+ Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
+ this.editorcore.pushValue();
+ },
+
+
+ // private
+ deferFocus : function(){
+ this.focus.defer(10, this);
+ },
+
+ // doc'ed in Field
+ focus : function(){
+ this.editorcore.focus();
- if(suppressEvent !== true){
- this.fireEvent('check', this, state);
- }
+ },
+
+
+ // private
+ onDestroy : function(){
- //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
- },
-
- getGroupValue : function()
- {
- var value = '';
- Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
- if(v.dom.checked == true){
- value = v.dom.value;
+
+ if(this.rendered){
+
+ for (var i =0; i < this.toolbars.length;i++) {
+ // fixme - ask toolbars for heights?
+ this.toolbars[i].onDestroy();
}
- });
+
+ this.wrap.dom.innerHTML = '';
+ this.wrap.remove();
+ }
+ },
+
+ // private
+ onFirstFocus : function(){
+ //Roo.log("onFirstFocus");
+ this.editorcore.onFirstFocus();
+ for (var i =0; i < this.toolbars.length;i++) {
+ this.toolbars[i].onFirstFocus();
+ }
- return value;
},
+ // private
+ syncValue : function()
+ {
+ this.editorcore.syncValue();
+ },
+
+ pushValue : function()
+ {
+ this.editorcore.pushValue();
+ }
+
+
+ // hide stuff that is not compatible
+ /**
+ * @event blur
+ * @hide
+ */
+ /**
+ * @event change
+ * @hide
+ */
+ /**
+ * @event focus
+ * @hide
+ */
+ /**
+ * @event specialkey
+ * @hide
+ */
/**
- * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
- * @return {Mixed} value The field value
+ * @cfg {String} fieldClass @hide
+ */
+ /**
+ * @cfg {String} focusClass @hide
+ */
+ /**
+ * @cfg {String} autoCreate @hide
+ */
+ /**
+ * @cfg {String} inputType @hide
+ */
+ /**
+ * @cfg {String} invalidClass @hide
+ */
+ /**
+ * @cfg {String} invalidText @hide
+ */
+ /**
+ * @cfg {String} msgFx @hide
+ */
+ /**
+ * @cfg {String} validateOnBlur @hide
*/
- getValue : function(){
- return this.getGroupValue();
- }
-
});
-
-
-//<script type="text/javascript">
-
-/*
- * Based Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- * LGPL
- *
- */
+
+
+
+
+
+Roo.namespace('Roo.bootstrap.htmleditor');
/**
- * @class Roo.HtmlEditorCore
- * @extends Roo.Component
- * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
+ * @class Roo.bootstrap.HtmlEditorToolbar1
+ * Basic Toolbar
+ *
+ * Usage:
*
- * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
+ new Roo.bootstrap.HtmlEditor({
+ ....
+ toolbars : [
+ new Roo.bootstrap.HtmlEditorToolbar1({
+ disable : { fonts: 1 , format: 1, ..., ... , ...],
+ btns : [ .... ]
+ })
+ }
+
+ *
+ * @cfg {Object} disable List of elements to disable..
+ * @cfg {Array} btns List of additional buttons.
+ *
+ *
+ * NEEDS Extra CSS?
+ * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
*/
-
-Roo.HtmlEditorCore = function(config){
-
-
- Roo.HtmlEditorCore.superclass.constructor.call(this, config);
+
+Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
+{
+ Roo.apply(this, config);
- this.addEvents({
- /**
- * @event initialize
- * Fires when the editor is fully initialized (including the iframe)
- * @param {Roo.HtmlEditorCore} this
- */
- initialize: true,
- /**
- * @event activate
- * Fires when the editor is first receives the focus. Any insertion must wait
- * until after this event.
- * @param {Roo.HtmlEditorCore} this
- */
- activate: true,
- /**
- * @event beforesync
- * Fires before the textarea is updated with content from the editor iframe. Return false
- * to cancel the sync.
- * @param {Roo.HtmlEditorCore} this
- * @param {String} html
- */
- beforesync: true,
- /**
- * @event beforepush
- * Fires before the iframe editor is updated with content from the textarea. Return false
- * to cancel the push.
- * @param {Roo.HtmlEditorCore} this
- * @param {String} html
- */
- beforepush: true,
- /**
- * @event sync
- * Fires when the textarea is updated with content from the editor iframe.
- * @param {Roo.HtmlEditorCore} this
- * @param {String} html
- */
- sync: true,
- /**
- * @event push
- * Fires when the iframe editor is updated with content from the textarea.
- * @param {Roo.HtmlEditorCore} this
- * @param {String} html
- */
- push: true,
-
- /**
- * @event editorevent
- * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
- * @param {Roo.HtmlEditorCore} this
- */
- editorevent: true
-
+ // default disabled, based on 'good practice'..
+ this.disable = this.disable || {};
+ Roo.applyIf(this.disable, {
+ fontSize : true,
+ colors : true,
+ specialElements : true
});
+ Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
- // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
-
- // defaults : white / black...
- this.applyBlacklists();
-
-
-
-};
-
-
-Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
-
-
- /**
- * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
- */
-
- owner : false,
-
- /**
- * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
- * Roo.resizable.
- */
- resizable : false,
- /**
- * @cfg {Number} height (in pixels)
- */
- height: 300,
- /**
- * @cfg {Number} width (in pixels)
- */
- width: 500,
+ this.editor = config.editor;
+ this.editorcore = config.editor.editorcore;
- /**
- * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
- *
- */
- stylesheets: false,
+ this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
- // id of frame..
- frameId: false,
+ //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
+ // dont call parent... till later.
+}
+Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
+
+ bar : true,
- // private properties
- validationEvent : false,
- deferHeight: true,
- initialized : false,
- activated : false,
- sourceEditMode : false,
- onFocus : Roo.emptyFn,
- iframePad:3,
- hideMode:'offsets',
+ editor : false,
+ editorcore : false,
- clearUp: true,
- // blacklist + whitelisted elements..
- black: false,
- white: false,
-
+ formats : [
+ "p" ,
+ "h1","h2","h3","h4","h5","h6",
+ "pre", "code",
+ "abbr", "acronym", "address", "cite", "samp", "var",
+ 'div','span'
+ ],
-
- /**
- * Protected method that will not generally be called directly. It
- * is called when the editor initializes the iframe with HTML contents. Override this method if you
- * want to change the initialization markup of the iframe (e.g. to add stylesheets).
- */
- getDocMarkup : function(){
- // body styles..
- var st = '';
+ onRender : function(ct, position)
+ {
+ // Roo.log("Call onRender: " + this.xtype);
- // inherit styels from page...??
- if (this.stylesheets === false) {
-
- Roo.get(document.head).select('style').each(function(node) {
- st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
+ Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
+ Roo.log(this.el);
+ this.el.dom.style.marginBottom = '0';
+ var _this = this;
+ var editorcore = this.editorcore;
+ var editor= this.editor;
+
+ var children = [];
+ var btn = function(id,cmd , toggle, handler){
+
+ var event = toggle ? 'toggle' : 'click';
+
+ var a = {
+ size : 'sm',
+ xtype: 'Button',
+ xns: Roo.bootstrap,
+ glyphicon : id,
+ cmd : id || cmd,
+ enableToggle:toggle !== false,
+ //html : 'submit'
+ pressed : toggle ? false : null,
+ listeners : {}
+ };
+ a.listeners[toggle ? 'toggle' : 'click'] = function() {
+ handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
+ };
+ children.push(a);
+ return a;
+ }
+
+ var style = {
+ xtype: 'Button',
+ size : 'sm',
+ xns: Roo.bootstrap,
+ glyphicon : 'font',
+ //html : 'submit'
+ menu : {
+ xtype: 'Menu',
+ xns: Roo.bootstrap,
+ items: []
+ }
+ };
+ Roo.each(this.formats, function(f) {
+ style.menu.items.push({
+ xtype :'MenuItem',
+ xns: Roo.bootstrap,
+ html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
+ tagname : f,
+ listeners : {
+ click : function()
+ {
+ editorcore.insertTag(this.tagname);
+ editor.focus();
+ }
+ }
+
});
+ });
+ children.push(style);
- Roo.get(document.head).select('link').each(function(node) {
- st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
- });
- } else if (!this.stylesheets.length) {
- // simple..
- st = '<style type="text/css">' +
- 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
- '</style>';
- } else {
+ btn('bold',false,true);
+ btn('italic',false,true);
+ btn('align-left', 'justifyleft',true);
+ btn('align-center', 'justifycenter',true);
+ btn('align-right' , 'justifyright',true);
+ btn('link', false, false, function(btn) {
+ //Roo.log("create link?");
+ var url = prompt(this.createLinkText, this.defaultLinkValue);
+ if(url && url != 'http:/'+'/'){
+ this.editorcore.relayCmd('createlink', url);
+ }
+ }),
+ btn('list','insertunorderedlist',true);
+ btn('pencil', false,true, function(btn){
+ Roo.log(this);
+
+ this.toggleSourceEdit(btn.pressed);
+ });
+ /*
+ var cog = {
+ xtype: 'Button',
+ size : 'sm',
+ xns: Roo.bootstrap,
+ glyphicon : 'cog',
+ //html : 'submit'
+ menu : {
+ xtype: 'Menu',
+ xns: Roo.bootstrap,
+ items: []
+ }
+ };
+
+ cog.menu.items.push({
+ xtype :'MenuItem',
+ xns: Roo.bootstrap,
+ html : Clean styles,
+ tagname : f,
+ listeners : {
+ click : function()
+ {
+ editorcore.insertTag(this.tagname);
+ editor.focus();
+ }
+ }
- }
+ });
+ */
- st += '<style type="text/css">' +
- 'IMG { cursor: pointer } ' +
- '</style>';
-
+
+ this.xtype = 'NavSimplebar';
- return '<html><head>' + st +
- //<style type="text/css">' +
- //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
- //'</style>' +
- ' </head><body class="roo-htmleditor-body"></body></html>';
+ for(var i=0;i< children.length;i++) {
+
+ this.buttons.add(this.addxtypeChild(children[i]));
+
+ }
+
+ editor.on('editorevent', this.updateToolbar, this);
},
-
- // private
- onRender : function(ct, position)
+ onBtnClick : function(id)
{
- var _t = this;
- //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
- this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
-
-
- this.el.dom.style.border = '0 none';
- this.el.dom.setAttribute('tabIndex', -1);
- this.el.addClass('x-hidden hide');
+ this.editorcore.relayCmd(id);
+ this.editorcore.focus();
+ },
+
+ /**
+ * Protected method that will not generally be called directly. It triggers
+ * a toolbar update by reading the markup state of the current selection in the editor.
+ */
+ updateToolbar: function(){
+
+ if(!this.editorcore.activated){
+ this.editor.onFirstFocus(); // is this neeed?
+ return;
+ }
+
+ var btns = this.buttons;
+ var doc = this.editorcore.doc;
+ btns.get('bold').setActive(doc.queryCommandState('bold'));
+ btns.get('italic').setActive(doc.queryCommandState('italic'));
+ //btns.get('underline').setActive(doc.queryCommandState('underline'));
+ btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
+ btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
+ btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
+ //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
+ btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
+ /*
- if(Roo.isIE){ // fix IE 1px bogus margin
- this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
+ var ans = this.editorcore.getAllAncestors();
+ if (this.formatCombo) {
+
+
+ var store = this.formatCombo.store;
+ this.formatCombo.setValue("");
+ for (var i =0; i < ans.length;i++) {
+ if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
+ // select it..
+ this.formatCombo.setValue(ans[i].tagName.toLowerCase());
+ break;
+ }
+ }
}
-
-
- this.frameId = Roo.id();
-
-
- var iframe = this.owner.wrap.createChild({
- tag: 'iframe',
- cls: 'form-control', // bootstrap..
- id: this.frameId,
- name: this.frameId,
- frameBorder : 'no',
- 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
- }, this.el
- );
- this.iframe = iframe.dom;
-
- this.assignDocWin();
+ // hides menus... - so this cant be on a menu...
+ Roo.bootstrap.MenuMgr.hideAll();
+ */
+ Roo.bootstrap.MenuMgr.hideAll();
+ //this.editorsyncValue();
+ },
+ onFirstFocus: function() {
+ this.buttons.each(function(item){
+ item.enable();
+ });
+ },
+ toggleSourceEdit : function(sourceEditMode){
- this.doc.designMode = 'on';
+
+ if(sourceEditMode){
+ Roo.log("disabling buttons");
+ this.buttons.each( function(item){
+ if(item.cmd != 'pencil'){
+ item.disable();
+ }
+ });
+
+ }else{
+ Roo.log("enabling buttons");
+ if(this.editorcore.initialized){
+ this.buttons.each( function(item){
+ item.enable();
+ });
+ }
+
+ }
+ Roo.log("calling toggole on editor");
+ // tell the editor that it's been pressed..
+ this.editor.toggleSourceEdit(sourceEditMode);
- this.doc.open();
- this.doc.write(this.getDocMarkup());
- this.doc.close();
+ }
+});
-
- var task = { // must defer to wait for browser to be ready
- run : function(){
- //console.log("run task?" + this.doc.readyState);
- this.assignDocWin();
- if(this.doc.body || this.doc.readyState == 'complete'){
- try {
- this.doc.designMode="on";
- } catch (e) {
- return;
- }
- Roo.TaskMgr.stop(task);
- this.initEditor.defer(10, this);
- }
- },
- interval : 10,
- duration: 10000,
- scope: this
- };
- Roo.TaskMgr.start(task);
- },
- // private
- onResize : function(w, h)
- {
- Roo.log('resize: ' +w + ',' + h );
- //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
- if(!this.iframe){
- return;
- }
- if(typeof w == 'number'){
-
- this.iframe.style.width = w + 'px';
- }
- if(typeof h == 'number'){
-
- this.iframe.style.height = h + 'px';
- if(this.doc){
- (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
- }
- }
-
+
+
+/**
+ * @class Roo.bootstrap.Table.AbstractSelectionModel
+ * @extends Roo.util.Observable
+ * Abstract base class for grid SelectionModels. It provides the interface that should be
+ * implemented by descendant classes. This class should not be directly instantiated.
+ * @constructor
+ */
+Roo.bootstrap.Table.AbstractSelectionModel = function(){
+ this.locked = false;
+ Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
+};
+
+
+Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
+ /** @ignore Called by the grid automatically. Do not call directly. */
+ init : function(grid){
+ this.grid = grid;
+ this.initEvents();
},
/**
- * Toggles the editor between standard and source edit mode.
- * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
+ * Locks the selections.
*/
- toggleSourceEdit : function(sourceEditMode){
-
- this.sourceEditMode = sourceEditMode === true;
-
- if(this.sourceEditMode){
-
- Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
-
- }else{
- Roo.get(this.iframe).removeClass(['x-hidden','hide']);
- //this.iframe.className = '';
- this.deferFocus();
- }
- //this.setSize(this.owner.wrap.getSize());
- //this.fireEvent('editmodechange', this, this.sourceEditMode);
+ lock : function(){
+ this.locked = true;
},
-
-
-
/**
- * Protected method that will not generally be called directly. If you need/want
- * custom HTML cleanup, this is the method you should override.
- * @param {String} html The HTML to be cleaned
- * return {String} The cleaned HTML
+ * Unlocks the selections.
*/
- cleanHtml : function(html){
- html = String(html);
- if(html.length > 5){
- if(Roo.isSafari){ // strip safari nonsense
- html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
- }
- }
- if(html == ' '){
- html = '';
- }
- return html;
+ unlock : function(){
+ this.locked = false;
},
/**
- * HTML Editor -> Textarea
- * Protected method that will not generally be called directly. Syncs the contents
- * of the editor iframe with the textarea.
+ * Returns true if the selections are locked.
+ * @return {Boolean}
*/
- syncValue : function(){
- if(this.initialized){
- var bd = (this.doc.body || this.doc.documentElement);
- //this.cleanUpPaste(); -- this is done else where and causes havoc..
- var html = bd.innerHTML;
- if(Roo.isSafari){
- var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
- var m = bs ? bs.match(/text-align:(.*?);/i) : false;
- if(m && m[1]){
- html = '<div style="'+m[0]+'">' + html + '</div>';
- }
- }
- html = this.cleanHtml(html);
- // fix up the special chars.. normaly like back quotes in word...
- // however we do not want to do this with chinese..
- html = html.replace(/([\x80-\uffff])/g, function (a, b) {
- var cc = b.charCodeAt();
- if (
- (cc >= 0x4E00 && cc < 0xA000 ) ||
- (cc >= 0x3400 && cc < 0x4E00 ) ||
- (cc >= 0xf900 && cc < 0xfb00 )
- ) {
- return b;
- }
- return "&#"+cc+";"
- });
- if(this.owner.fireEvent('beforesync', this, html) !== false){
- this.el.dom.value = html;
- this.owner.fireEvent('sync', this, html);
- }
- }
- },
+ isLocked : function(){
+ return this.locked;
+ }
+});
+/**
+ * @extends Roo.bootstrap.Table.AbstractSelectionModel
+ * @class Roo.bootstrap.Table.RowSelectionModel
+ * The default SelectionModel used by {@link Roo.bootstrap.Table}.
+ * It supports multiple selections and keyboard selection/navigation.
+ * @constructor
+ * @param {Object} config
+ */
+
+Roo.bootstrap.Table.RowSelectionModel = function(config){
+ Roo.apply(this, config);
+ this.selections = new Roo.util.MixedCollection(false, function(o){
+ return o.id;
+ });
+
+ this.last = false;
+ this.lastActive = false;
+
+ this.addEvents({
+ /**
+ * @event selectionchange
+ * Fires when the selection changes
+ * @param {SelectionModel} this
+ */
+ "selectionchange" : true,
+ /**
+ * @event afterselectionchange
+ * Fires after the selection changes (eg. by key press or clicking)
+ * @param {SelectionModel} this
+ */
+ "afterselectionchange" : true,
+ /**
+ * @event beforerowselect
+ * Fires when a row is selected being selected, return false to cancel.
+ * @param {SelectionModel} this
+ * @param {Number} rowIndex The selected index
+ * @param {Boolean} keepExisting False if other selections will be cleared
+ */
+ "beforerowselect" : true,
+ /**
+ * @event rowselect
+ * Fires when a row is selected.
+ * @param {SelectionModel} this
+ * @param {Number} rowIndex The selected index
+ * @param {Roo.data.Record} r The record
+ */
+ "rowselect" : true,
+ /**
+ * @event rowdeselect
+ * Fires when a row is deselected.
+ * @param {SelectionModel} this
+ * @param {Number} rowIndex The selected index
+ */
+ "rowdeselect" : true
+ });
+ Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
+ this.locked = false;
+};
+Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
/**
- * Protected method that will not generally be called directly. Pushes the value of the textarea
- * into the iframe editor.
+ * @cfg {Boolean} singleSelect
+ * True to allow selection of only one row at a time (defaults to false)
*/
- pushValue : function(){
- if(this.initialized){
- var v = this.el.dom.value.trim();
-
-// if(v.length < 1){
-// v = ' ';
-// }
-
- if(this.owner.fireEvent('beforepush', this, v) !== false){
- var d = (this.doc.body || this.doc.documentElement);
- d.innerHTML = v;
- this.cleanUpPaste();
- this.el.dom.value = d.innerHTML;
- this.owner.fireEvent('push', this, v);
- }
- }
- },
+ singleSelect : false,
// private
- deferFocus : function(){
- this.focus.defer(10, this);
- },
+ initEvents : function(){
- // doc'ed in Field
- focus : function(){
- if(this.win && !this.sourceEditMode){
- this.win.focus();
- }else{
- this.el.focus();
+ if(!this.grid.enableDragDrop && !this.grid.enableDrag){
+ this.grid.on("mousedown", this.handleMouseDown, this);
+ }else{ // allow click to work like normal
+ this.grid.on("rowclick", this.handleDragableRowClick, this);
}
+
+ this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
+ "up" : function(e){
+ if(!e.shiftKey){
+ this.selectPrevious(e.shiftKey);
+ }else if(this.last !== false && this.lastActive !== false){
+ var last = this.last;
+ this.selectRange(this.last, this.lastActive-1);
+ this.grid.getView().focusRow(this.lastActive);
+ if(last !== false){
+ this.last = last;
+ }
+ }else{
+ this.selectFirstRow();
+ }
+ this.fireEvent("afterselectionchange", this);
+ },
+ "down" : function(e){
+ if(!e.shiftKey){
+ this.selectNext(e.shiftKey);
+ }else if(this.last !== false && this.lastActive !== false){
+ var last = this.last;
+ this.selectRange(this.last, this.lastActive+1);
+ this.grid.getView().focusRow(this.lastActive);
+ if(last !== false){
+ this.last = last;
+ }
+ }else{
+ this.selectFirstRow();
+ }
+ this.fireEvent("afterselectionchange", this);
+ },
+ scope: this
+ });
+
+ var view = this.grid.view;
+ view.on("refresh", this.onRefresh, this);
+ view.on("rowupdated", this.onRowUpdated, this);
+ view.on("rowremoved", this.onRemove, this);
},
-
- assignDocWin: function()
- {
- var iframe = this.iframe;
-
- if(Roo.isIE){
- this.doc = iframe.contentWindow.document;
- this.win = iframe.contentWindow;
- } else {
-// if (!Roo.get(this.frameId)) {
-// return;
-// }
-// this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
-// this.win = Roo.get(this.frameId).dom.contentWindow;
-
- if (!Roo.get(this.frameId) && !iframe.contentDocument) {
- return;
+
+ // private
+ onRefresh : function(){
+ var ds = this.grid.dataSource, i, v = this.grid.view;
+ var s = this.selections;
+ s.each(function(r){
+ if((i = ds.indexOfId(r.id)) != -1){
+ v.onRowSelect(i);
+ }else{
+ s.remove(r);
}
-
- this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
- this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
- }
+ });
},
-
+
// private
- initEditor : function(){
- //console.log("INIT EDITOR");
- this.assignDocWin();
-
-
-
- this.doc.designMode="on";
- this.doc.open();
- this.doc.write(this.getDocMarkup());
- this.doc.close();
-
- var dbody = (this.doc.body || this.doc.documentElement);
- //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
- // this copies styles from the containing element into thsi one..
- // not sure why we need all of this..
- //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
-
- //var ss = this.el.getStyles( 'background-image', 'background-repeat');
- //ss['background-attachment'] = 'fixed'; // w3c
- dbody.bgProperties = 'fixed'; // ie
- //Roo.DomHelper.applyStyles(dbody, ss);
- Roo.EventManager.on(this.doc, {
- //'mousedown': this.onEditorEvent,
- 'mouseup': this.onEditorEvent,
- 'dblclick': this.onEditorEvent,
- 'click': this.onEditorEvent,
- 'keyup': this.onEditorEvent,
- buffer:100,
- scope: this
- });
- if(Roo.isGecko){
- Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
+ onRemove : function(v, index, r){
+ this.selections.remove(r);
+ },
+
+ // private
+ onRowUpdated : function(v, index, r){
+ if(this.isSelected(r)){
+ v.onRowSelect(index);
}
- if(Roo.isIE || Roo.isSafari || Roo.isOpera){
- Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
+ },
+
+ /**
+ * Select records.
+ * @param {Array} records The records to select
+ * @param {Boolean} keepExisting (optional) True to keep existing selections
+ */
+ selectRecords : function(records, keepExisting){
+ if(!keepExisting){
+ this.clearSelections();
}
- this.initialized = true;
+ var ds = this.grid.dataSource;
+ for(var i = 0, len = records.length; i < len; i++){
+ this.selectRow(ds.indexOf(records[i]), true);
+ }
+ },
- this.owner.fireEvent('initialize', this);
- this.pushValue();
+ /**
+ * Gets the number of selected rows.
+ * @return {Number}
+ */
+ getCount : function(){
+ return this.selections.length;
},
- // private
- onDestroy : function(){
-
-
-
- if(this.rendered){
-
- //for (var i =0; i < this.toolbars.length;i++) {
- // // fixme - ask toolbars for heights?
- // this.toolbars[i].onDestroy();
- // }
-
- //this.wrap.dom.innerHTML = '';
- //this.wrap.remove();
- }
+ /**
+ * Selects the first row in the grid.
+ */
+ selectFirstRow : function(){
+ this.selectRow(0);
},
- // private
- onFirstFocus : function(){
-
- this.assignDocWin();
-
-
- this.activated = true;
-
-
- if(Roo.isGecko){ // prevent silly gecko errors
- this.win.focus();
- var s = this.win.getSelection();
- if(!s.focusNode || s.focusNode.nodeType != 3){
- var r = s.getRangeAt(0);
- r.selectNodeContents((this.doc.body || this.doc.documentElement));
- r.collapse(true);
- this.deferFocus();
- }
- try{
- this.execCmd('useCSS', true);
- this.execCmd('styleWithCSS', false);
- }catch(e){}
+ /**
+ * Select the last row.
+ * @param {Boolean} keepExisting (optional) True to keep existing selections
+ */
+ selectLastRow : function(keepExisting){
+ this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
+ },
+
+ /**
+ * Selects the row immediately following the last selected row.
+ * @param {Boolean} keepExisting (optional) True to keep existing selections
+ */
+ selectNext : function(keepExisting){
+ if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
+ this.selectRow(this.last+1, keepExisting);
+ this.grid.getView().focusRow(this.last);
}
- this.owner.fireEvent('activate', this);
},
- // private
- adjustFont: function(btn){
- var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
- //if(Roo.isSafari){ // safari
- // adjust *= 2;
- // }
- var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
- if(Roo.isSafari){ // safari
- var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
- v = (v < 10) ? 10 : v;
- v = (v > 48) ? 48 : v;
- v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
-
+ /**
+ * Selects the row that precedes the last selected row.
+ * @param {Boolean} keepExisting (optional) True to keep existing selections
+ */
+ selectPrevious : function(keepExisting){
+ if(this.last){
+ this.selectRow(this.last-1, keepExisting);
+ this.grid.getView().focusRow(this.last);
}
-
-
- v = Math.max(1, v+adjust);
-
- this.execCmd('FontSize', v );
},
- onEditorEvent : function(e)
- {
- this.owner.fireEvent('editorevent', this, e);
- // this.updateToolbar();
- this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
+ /**
+ * Returns the selected records
+ * @return {Array} Array of selected records
+ */
+ getSelections : function(){
+ return [].concat(this.selections.items);
},
- insertTag : function(tg)
- {
- // could be a bit smarter... -> wrap the current selected tRoo..
- if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
-
- range = this.createRange(this.getSelection());
- var wrappingNode = this.doc.createElement(tg.toLowerCase());
- wrappingNode.appendChild(range.extractContents());
- range.insertNode(wrappingNode);
+ /**
+ * Returns the first selected record.
+ * @return {Record}
+ */
+ getSelected : function(){
+ return this.selections.itemAt(0);
+ },
- return;
-
-
-
+
+ /**
+ * Clears all selections.
+ */
+ clearSelections : function(fast){
+ if(this.locked) return;
+ if(fast !== true){
+ var ds = this.grid.dataSource;
+ var s = this.selections;
+ s.each(function(r){
+ this.deselectRow(ds.indexOfId(r.id));
+ }, this);
+ s.clear();
+ }else{
+ this.selections.clear();
}
- this.execCmd("formatblock", tg);
-
+ this.last = false;
},
-
- insertText : function(txt)
- {
-
-
- var range = this.createRange();
- range.deleteContents();
- //alert(Sender.getAttribute('label'));
-
- range.insertNode(this.doc.createTextNode(txt));
- } ,
-
-
+
/**
- * Executes a Midas editor command on the editor document and performs necessary focus and
- * toolbar updates. <b>This should only be called after the editor is initialized.</b>
- * @param {String} cmd The Midas command
- * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+ * Selects all rows.
*/
- relayCmd : function(cmd, value){
- this.win.focus();
- this.execCmd(cmd, value);
- this.owner.fireEvent('editorevent', this);
- //this.updateToolbar();
- this.owner.deferFocus();
+ selectAll : function(){
+ if(this.locked) return;
+ this.selections.clear();
+ for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
+ this.selectRow(i, true);
+ }
},
/**
- * Executes a Midas editor command directly on the editor document.
- * For visual commands, you should use {@link #relayCmd} instead.
- * <b>This should only be called after the editor is initialized.</b>
- * @param {String} cmd The Midas command
- * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
+ * Returns True if there is a selection.
+ * @return {Boolean}
+ */
+ hasSelection : function(){
+ return this.selections.length > 0;
+ },
+
+ /**
+ * Returns True if the specified row is selected.
+ * @param {Number/Record} record The record or index of the record to check
+ * @return {Boolean}
*/
- execCmd : function(cmd, value){
- this.doc.execCommand(cmd, false, value === undefined ? null : value);
- this.syncValue();
+ isSelected : function(index){
+ var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
+ return (r && this.selections.key(r.id) ? true : false);
},
-
-
-
+
/**
- * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
- * to insert tRoo.
- * @param {String} text | dom node..
+ * Returns True if the specified record id is selected.
+ * @param {String} id The id of record to check
+ * @return {Boolean}
*/
- insertAtCursor : function(text)
- {
-
-
-
- if(!this.activated){
- return;
- }
- /*
- if(Roo.isIE){
- this.win.focus();
- var r = this.doc.selection.createRange();
- if(r){
- r.collapse(true);
- r.pasteHTML(text);
- this.syncValue();
- this.deferFocus();
-
- }
- return;
- }
- */
- if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
- this.win.focus();
-
-
- // from jquery ui (MIT licenced)
- var range, node;
- var win = this.win;
-
- if (win.getSelection && win.getSelection().getRangeAt) {
- range = win.getSelection().getRangeAt(0);
- node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
- range.insertNode(node);
- } else if (win.document.selection && win.document.selection.createRange) {
- // no firefox support
- var txt = typeof(text) == 'string' ? text : text.outerHTML;
- win.document.selection.createRange().pasteHTML(txt);
- } else {
- // no firefox support
- var txt = typeof(text) == 'string' ? text : text.outerHTML;
- this.execCmd('InsertHTML', txt);
- }
-
- this.syncValue();
-
- this.deferFocus();
- }
+ isIdSelected : function(id){
+ return (this.selections.key(id) ? true : false);
},
- // private
- mozKeyPress : function(e){
- if(e.ctrlKey){
- var c = e.getCharCode(), cmd;
-
- if(c > 0){
- c = String.fromCharCode(c).toLowerCase();
- switch(c){
- case 'b':
- cmd = 'bold';
- break;
- case 'i':
- cmd = 'italic';
- break;
-
- case 'u':
- cmd = 'underline';
- break;
-
- case 'v':
- this.cleanUpPaste.defer(100, this);
- return;
-
- }
- if(cmd){
- this.win.focus();
- this.execCmd(cmd);
- this.deferFocus();
- e.preventDefault();
- }
-
+
+ // private
+ handleMouseDown : function(e, t){
+ var view = this.grid.getView(), rowIndex;
+ if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
+ return;
+ };
+ if(e.shiftKey && this.last !== false){
+ var last = this.last;
+ this.selectRange(last, rowIndex, e.ctrlKey);
+ this.last = last; // reset the last
+ view.focusRow(rowIndex);
+ }else{
+ var isSelected = this.isSelected(rowIndex);
+ if(e.button !== 0 && isSelected){
+ view.focusRow(rowIndex);
+ }else if(e.ctrlKey && isSelected){
+ this.deselectRow(rowIndex);
+ }else if(!isSelected){
+ this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
+ view.focusRow(rowIndex);
}
}
+ this.fireEvent("afterselectionchange", this);
},
-
// private
- fixKeys : function(){ // load time branching for fastest keydown performance
- if(Roo.isIE){
- return function(e){
- var k = e.getKey(), r;
- if(k == e.TAB){
- e.stopEvent();
- r = this.doc.selection.createRange();
- if(r){
- r.collapse(true);
- r.pasteHTML('    ');
- this.deferFocus();
- }
- return;
- }
-
- if(k == e.ENTER){
- r = this.doc.selection.createRange();
- if(r){
- var target = r.parentElement();
- if(!target || target.tagName.toLowerCase() != 'li'){
- e.stopEvent();
- r.pasteHTML('<br />');
- r.collapse(false);
- r.select();
- }
- }
- }
- if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
- this.cleanUpPaste.defer(100, this);
- return;
- }
-
-
- };
- }else if(Roo.isOpera){
- return function(e){
- var k = e.getKey();
- if(k == e.TAB){
- e.stopEvent();
- this.win.focus();
- this.execCmd('InsertHTML','    ');
- this.deferFocus();
- }
- if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
- this.cleanUpPaste.defer(100, this);
- return;
- }
-
- };
- }else if(Roo.isSafari){
- return function(e){
- var k = e.getKey();
-
- if(k == e.TAB){
- e.stopEvent();
- this.execCmd('InsertText','\t');
- this.deferFocus();
- return;
- }
- if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
- this.cleanUpPaste.defer(100, this);
- return;
- }
-
- };
- }
- }(),
-
- getAllAncestors: function()
+ handleDragableRowClick : function(grid, rowIndex, e)
{
- var p = this.getSelectedNode();
- var a = [];
- if (!p) {
- a.push(p); // push blank onto stack..
- p = this.getParentElement();
- }
-
-
- while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
- a.push(p);
- p = p.parentNode;
+ if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
+ this.selectRow(rowIndex, false);
+ grid.view.focusRow(rowIndex);
+ this.fireEvent("afterselectionchange", this);
}
- a.push(this.doc.body);
- return a;
},
- lastSel : false,
- lastSelNode : false,
-
- getSelection : function()
- {
- this.assignDocWin();
- return Roo.isIE ? this.doc.selection : this.win.getSelection();
+ /**
+ * Selects multiple rows.
+ * @param {Array} rows Array of the indexes of the row to select
+ * @param {Boolean} keepExisting (optional) True to keep existing selections
+ */
+ selectRows : function(rows, keepExisting){
+ if(!keepExisting){
+ this.clearSelections();
+ }
+ for(var i = 0, len = rows.length; i < len; i++){
+ this.selectRow(rows[i], true);
+ }
},
-
- getSelectedNode: function()
- {
- // this may only work on Gecko!!!
-
- // should we cache this!!!!
-
-
-
-
- var range = this.createRange(this.getSelection()).cloneRange();
-
- if (Roo.isIE) {
- var parent = range.parentElement();
- while (true) {
- var testRange = range.duplicate();
- testRange.moveToElementText(parent);
- if (testRange.inRange(range)) {
- break;
- }
- if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
- break;
- }
- parent = parent.parentElement;
+
+ /**
+ * Selects a range of rows. All rows in between startRow and endRow are also selected.
+ * @param {Number} startRow The index of the first row in the range
+ * @param {Number} endRow The index of the last row in the range
+ * @param {Boolean} keepExisting (optional) True to retain existing selections
+ */
+ selectRange : function(startRow, endRow, keepExisting){
+ if(this.locked) return;
+ if(!keepExisting){
+ this.clearSelections();
+ }
+ if(startRow <= endRow){
+ for(var i = startRow; i <= endRow; i++){
+ this.selectRow(i, true);
+ }
+ }else{
+ for(var i = startRow; i >= endRow; i--){
+ this.selectRow(i, true);
}
- return parent;
}
-
- // is ancestor a text element.
- var ac = range.commonAncestorContainer;
- if (ac.nodeType == 3) {
- ac = ac.parentNode;
+ },
+
+ /**
+ * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
+ * @param {Number} startRow The index of the first row in the range
+ * @param {Number} endRow The index of the last row in the range
+ */
+ deselectRange : function(startRow, endRow, preventViewNotify){
+ if(this.locked) return;
+ for(var i = startRow; i <= endRow; i++){
+ this.deselectRow(i, preventViewNotify);
}
-
- var ar = ac.childNodes;
-
- var nodes = [];
- var other_nodes = [];
- var has_other_nodes = false;
- for (var i=0;i<ar.length;i++) {
- if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
- continue;
+ },
+
+ /**
+ * Selects a row.
+ * @param {Number} row The index of the row to select
+ * @param {Boolean} keepExisting (optional) True to keep existing selections
+ */
+ selectRow : function(index, keepExisting, preventViewNotify){
+ if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
+ if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
+ if(!keepExisting || this.singleSelect){
+ this.clearSelections();
}
- // fullly contained node.
-
- if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
- nodes.push(ar[i]);
- continue;
+ var r = this.grid.dataSource.getAt(index);
+ this.selections.add(r);
+ this.last = this.lastActive = index;
+ if(!preventViewNotify){
+ this.grid.getView().onRowSelect(index);
}
-
- // probably selected..
- if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
- other_nodes.push(ar[i]);
- continue;
+ this.fireEvent("rowselect", this, index, r);
+ this.fireEvent("selectionchange", this);
+ }
+ },
+
+ /**
+ * Deselects a row.
+ * @param {Number} row The index of the row to deselect
+ */
+ deselectRow : function(index, preventViewNotify){
+ if(this.locked) return;
+ if(this.last == index){
+ this.last = false;
+ }
+ if(this.lastActive == index){
+ this.lastActive = false;
+ }
+ var r = this.grid.dataSource.getAt(index);
+ this.selections.remove(r);
+ if(!preventViewNotify){
+ this.grid.getView().onRowDeselect(index);
+ }
+ this.fireEvent("rowdeselect", this, index);
+ this.fireEvent("selectionchange", this);
+ },
+
+ // private
+ restoreLast : function(){
+ if(this._last){
+ this.last = this._last;
+ }
+ },
+
+ // private
+ acceptsNav : function(row, col, cm){
+ return !cm.isHidden(col) && cm.isCellEditable(col, row);
+ },
+
+ // private
+ onEditorKey : function(field, e){
+ var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
+ if(k == e.TAB){
+ e.stopEvent();
+ ed.completeEdit();
+ if(e.shiftKey){
+ newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
+ }else{
+ newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
}
- // outer..
- if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
- continue;
+ }else if(k == e.ENTER && !e.ctrlKey){
+ e.stopEvent();
+ ed.completeEdit();
+ if(e.shiftKey){
+ newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
+ }else{
+ newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
}
-
-
- has_other_nodes = true;
+ }else if(k == e.ESC){
+ ed.cancelEdit();
}
- if (!nodes.length && other_nodes.length) {
- nodes= other_nodes;
+ if(newCell){
+ g.startEditing(newCell[0], newCell[1]);
}
- if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
- return false;
+ }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.bootstrap.PagingToolbar
+ * @extends Roo.bootstrap.NavSimplebar
+ * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
+ * @constructor
+ * Create a new PagingToolbar
+ * @param {Object} config The config object
+ * @param {Roo.data.Store} store
+ */
+Roo.bootstrap.PagingToolbar = function(config)
+{
+ // old args format still supported... - xtype is prefered..
+ // created from xtype...
+
+ this.ds = config.dataSource;
+
+ if (config.store && !this.ds) {
+ this.store= Roo.factory(config.store, Roo.data);
+ this.ds = this.store;
+ this.ds.xmodule = this.xmodule || false;
+ }
+
+ this.toolbarItems = [];
+ if (config.items) {
+ this.toolbarItems = config.items;
+ }
+
+ Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
+
+ this.cursor = 0;
+
+ if (this.ds) {
+ this.bind(this.ds);
+ }
+
+ this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
+
+};
+
+Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
+ /**
+ * @cfg {Roo.data.Store} dataSource
+ * The underlying data store providing the paged data
+ */
+ /**
+ * @cfg {String/HTMLElement/Element} container
+ * container The id or element that will contain the toolbar
+ */
+ /**
+ * @cfg {Boolean} displayInfo
+ * True to display the displayMsg (defaults to false)
+ */
+ /**
+ * @cfg {Number} pageSize
+ * The number of records to display per page (defaults to 20)
+ */
+ pageSize: 20,
+ /**
+ * @cfg {String} displayMsg
+ * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
+ */
+ displayMsg : 'Displaying {0} - {1} of {2}',
+ /**
+ * @cfg {String} emptyMsg
+ * The message to display when no records are found (defaults to "No data to display")
+ */
+ emptyMsg : 'No data to display',
+ /**
+ * Customizable piece of the default paging text (defaults to "Page")
+ * @type String
+ */
+ beforePageText : "Page",
+ /**
+ * Customizable piece of the default paging text (defaults to "of %0")
+ * @type String
+ */
+ afterPageText : "of {0}",
+ /**
+ * Customizable piece of the default paging text (defaults to "First Page")
+ * @type String
+ */
+ firstText : "First Page",
+ /**
+ * Customizable piece of the default paging text (defaults to "Previous Page")
+ * @type String
+ */
+ prevText : "Previous Page",
+ /**
+ * Customizable piece of the default paging text (defaults to "Next Page")
+ * @type String
+ */
+ nextText : "Next Page",
+ /**
+ * Customizable piece of the default paging text (defaults to "Last Page")
+ * @type String
+ */
+ lastText : "Last Page",
+ /**
+ * Customizable piece of the default paging text (defaults to "Refresh")
+ * @type String
+ */
+ refreshText : "Refresh",
+
+ buttons : false,
+ // private
+ onRender : function(ct, position)
+ {
+ Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
+ this.navgroup.parentId = this.id;
+ this.navgroup.onRender(this.el, null);
+ // add the buttons to the navgroup
+
+ if(this.displayInfo){
+ Roo.log(this.el.select('ul.navbar-nav',true).first());
+ this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
+ this.displayEl = this.el.select('.x-paging-info', true).first();
+// var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
+// this.displayEl = navel.el.select('span',true).first();
}
- return nodes[0];
- },
- createRange: function(sel)
- {
- // this has strange effects when using with
- // top toolbar - not sure if it's a great idea.
- //this.editor.contentWindow.focus();
- if (typeof sel != "undefined") {
- try {
- return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
- } catch(e) {
- return this.doc.createRange();
- }
- } else {
- return this.doc.createRange();
+ var _this = this;
+
+ if(this.buttons){
+ Roo.each(_this.buttons, function(e){ // this might need to use render????
+ Roo.factory(e).onRender(_this.el, null);
+ });
}
- },
- getParentElement: function()
- {
+
+ Roo.each(_this.toolbarItems, function(e) {
+ _this.navgroup.addItem(e);
+ });
- this.assignDocWin();
- var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
- var range = this.createRange(sel);
-
- try {
- var p = range.commonAncestorContainer;
- while (p.nodeType == 3) { // text node
- p = p.parentNode;
- }
- return p;
- } catch (e) {
- return null;
- }
-
- },
- /***
- *
- * Range intersection.. the hard stuff...
- * '-1' = before
- * '0' = hits..
- * '1' = after.
- * [ -- selected range --- ]
- * [fail] [fail]
- *
- * basically..
- * if end is before start or hits it. fail.
- * if start is after end or hits it fail.
- *
- * if either hits (but other is outside. - then it's not
- *
- *
- **/
-
-
- // @see http://www.thismuchiknow.co.uk/?p=64.
- rangeIntersectsNode : function(range, node)
- {
- var nodeRange = node.ownerDocument.createRange();
- try {
- nodeRange.selectNode(node);
- } catch (e) {
- nodeRange.selectNodeContents(node);
- }
-
- var rangeStartRange = range.cloneRange();
- rangeStartRange.collapse(true);
-
- var rangeEndRange = range.cloneRange();
- rangeEndRange.collapse(false);
-
- var nodeStartRange = nodeRange.cloneRange();
- nodeStartRange.collapse(true);
-
- var nodeEndRange = nodeRange.cloneRange();
- nodeEndRange.collapse(false);
-
- return rangeStartRange.compareBoundaryPoints(
- Range.START_TO_START, nodeEndRange) == -1 &&
- rangeEndRange.compareBoundaryPoints(
- Range.START_TO_START, nodeStartRange) == 1;
+ this.first = this.navgroup.addItem({
+ tooltip: this.firstText,
+ cls: "prev",
+ icon : 'fa fa-backward',
+ disabled: true,
+ preventDefault: true,
+ listeners : { click : this.onClick.createDelegate(this, ["first"]) }
+ });
-
- },
- rangeCompareNode : function(range, node)
- {
- var nodeRange = node.ownerDocument.createRange();
- try {
- nodeRange.selectNode(node);
- } catch (e) {
- nodeRange.selectNodeContents(node);
- }
+ this.prev = this.navgroup.addItem({
+ tooltip: this.prevText,
+ cls: "prev",
+ icon : 'fa fa-step-backward',
+ disabled: true,
+ preventDefault: true,
+ listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
+ });
+ //this.addSeparator();
- range.collapse(true);
-
- nodeRange.collapse(true);
-
- var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
- var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
-
- //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
+ var field = this.navgroup.addItem( {
+ tagtype : 'span',
+ cls : 'x-paging-position',
+
+ html : this.beforePageText +
+ '<input type="text" size="3" value="1" class="x-grid-page-number">' +
+ '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
+ } ); //?? escaped?
- var nodeIsBefore = ss == 1;
- var nodeIsAfter = ee == -1;
+ this.field = field.el.select('input', true).first();
+ this.field.on("keydown", this.onPagingKeydown, this);
+ this.field.on("focus", function(){this.dom.select();});
+
+
+ this.afterTextEl = field.el.select('.x-paging-after',true).first();
+ //this.field.setHeight(18);
+ //this.addSeparator();
+ this.next = this.navgroup.addItem({
+ tooltip: this.nextText,
+ cls: "next",
+ html : ' <i class="fa fa-step-forward">',
+ disabled: true,
+ preventDefault: true,
+ listeners : { click : this.onClick.createDelegate(this, ["next"]) }
+ });
+ this.last = this.navgroup.addItem({
+ tooltip: this.lastText,
+ icon : 'fa fa-forward',
+ cls: "next",
+ disabled: true,
+ preventDefault: true,
+ listeners : { click : this.onClick.createDelegate(this, ["last"]) }
+ });
+ //this.addSeparator();
+ this.loading = this.navgroup.addItem({
+ tooltip: this.refreshText,
+ icon: 'fa fa-refresh',
+ preventDefault: true,
+ listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
+ });
- if (nodeIsBefore && nodeIsAfter)
- return 0; // outer
- if (!nodeIsBefore && nodeIsAfter)
- return 1; //right trailed.
+ },
+
+ // private
+ updateInfo : function(){
+ if(this.displayEl){
+ var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
+ var msg = count == 0 ?
+ this.emptyMsg :
+ String.format(
+ this.displayMsg,
+ this.cursor+1, this.cursor+count, this.ds.getTotalCount()
+ );
+ this.displayEl.update(msg);
+ }
+ },
+
+ // private
+ onLoad : function(ds, r, o){
+ this.cursor = o.params ? o.params.start : 0;
+ var d = this.getPageData(),
+ ap = d.activePage,
+ ps = d.pages;
- if (nodeIsBefore && !nodeIsAfter)
- return 2; // left trailed.
- // fully contined.
- return 3;
+ this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
+ this.field.dom.value = ap;
+ this.first.setDisabled(ap == 1);
+ this.prev.setDisabled(ap == 1);
+ this.next.setDisabled(ap == ps);
+ this.last.setDisabled(ap == ps);
+ this.loading.enable();
+ this.updateInfo();
+ },
+
+ // private
+ getPageData : function(){
+ var total = this.ds.getTotalCount();
+ return {
+ total : total,
+ activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
+ pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
+ };
+ },
+
+ // private
+ onLoadError : function(){
+ this.loading.enable();
+ },
+
+ // private
+ onPagingKeydown : function(e){
+ var k = e.getKey();
+ var d = this.getPageData();
+ if(k == e.RETURN){
+ var v = this.field.dom.value, pageNum;
+ if(!v || isNaN(pageNum = parseInt(v, 10))){
+ this.field.dom.value = d.activePage;
+ return;
+ }
+ pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
+ this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
+ e.stopEvent();
+ }
+ else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
+ {
+ var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
+ this.field.dom.value = pageNum;
+ this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
+ e.stopEvent();
+ }
+ else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
+ {
+ var v = this.field.dom.value, pageNum;
+ var increment = (e.shiftKey) ? 10 : 1;
+ if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
+ increment *= -1;
+ if(!v || isNaN(pageNum = parseInt(v, 10))) {
+ this.field.dom.value = d.activePage;
+ return;
+ }
+ else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
+ {
+ this.field.dom.value = parseInt(v, 10) + increment;
+ pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
+ this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
+ }
+ e.stopEvent();
+ }
},
- // private? - in a new class?
- cleanUpPaste : function()
- {
- // cleans up the whole document..
- Roo.log('cleanuppaste');
-
- this.cleanUpChildren(this.doc.body);
- var clean = this.cleanWordChars(this.doc.body.innerHTML);
- if (clean != this.doc.body.innerHTML) {
- this.doc.body.innerHTML = clean;
+ // private
+ beforeLoad : function(){
+ if(this.loading){
+ this.loading.disable();
}
-
},
-
- cleanWordChars : function(input) {// change the chars to hex code
- var he = Roo.HtmlEditorCore;
-
- var output = input;
- Roo.each(he.swapCodes, function(sw) {
- var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
-
- output = output.replace(swapper, sw[1]);
- });
+
+ // private
+ onClick : function(which){
- return output;
- },
-
-
- cleanUpChildren : function (n)
- {
- if (!n.childNodes.length) {
+ var ds = this.ds;
+ if (!ds) {
return;
}
- for (var i = n.childNodes.length-1; i > -1 ; i--) {
- this.cleanUpChild(n.childNodes[i]);
+
+ switch(which){
+ case "first":
+ ds.load({params:{start: 0, limit: this.pageSize}});
+ break;
+ case "prev":
+ ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
+ break;
+ case "next":
+ ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
+ break;
+ case "last":
+ var total = ds.getTotalCount();
+ var extra = total % this.pageSize;
+ var lastStart = extra ? (total - extra) : total-this.pageSize;
+ ds.load({params:{start: lastStart, limit: this.pageSize}});
+ break;
+ case "refresh":
+ ds.load({params:{start: this.cursor, limit: this.pageSize}});
+ break;
}
},
+
+ /**
+ * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
+ * @param {Roo.data.Store} store The data store to unbind
+ */
+ unbind : function(ds){
+ ds.un("beforeload", this.beforeLoad, this);
+ ds.un("load", this.onLoad, this);
+ ds.un("loadexception", this.onLoadError, this);
+ ds.un("remove", this.updateInfo, this);
+ ds.un("add", this.updateInfo, this);
+ this.ds = undefined;
+ },
+
+ /**
+ * Binds the paging toolbar to the specified {@link Roo.data.Store}
+ * @param {Roo.data.Store} store The data store to bind
+ */
+ bind : function(ds){
+ ds.on("beforeload", this.beforeLoad, this);
+ ds.on("load", this.onLoad, this);
+ ds.on("loadexception", this.onLoadError, this);
+ ds.on("remove", this.updateInfo, this);
+ ds.on("add", this.updateInfo, this);
+ this.ds = ds;
+ }
+});/*
+ * - LGPL
+ *
+ * element
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.MessageBar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap MessageBar class
+ * @cfg {String} html contents of the MessageBar
+ * @cfg {String} weight (info | success | warning | danger) default info
+ * @cfg {String} beforeClass insert the bar before the given class
+ * @cfg {Boolean} closable (true | false) default false
+ * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
+ *
+ * @constructor
+ * Create a new Element
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.MessageBar = function(config){
+ Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
+ html: '',
+ weight: 'info',
+ closable: false,
+ fixed: false,
+ beforeClass: 'bootstrap-sticky-wrap',
+ getAutoCreate : function(){
-
- cleanUpChild : function (node)
- {
- var ed = this;
- //console.log(node);
- if (node.nodeName == "#text") {
- // clean up silly Windows -- stuff?
- return;
- }
- if (node.nodeName == "#comment") {
- node.parentNode.removeChild(node);
- // clean up silly Windows -- stuff?
- return;
- }
- var lcname = node.tagName.toLowerCase();
- // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
- // whitelist of tags..
-
- if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
- // remove node.
- node.parentNode.removeChild(node);
- return;
-
+ var cfg = {
+ tag: 'div',
+ cls: 'alert alert-dismissable alert-' + this.weight,
+ cn: [
+ {
+ tag: 'span',
+ cls: 'message',
+ html: this.html || ''
+ }
+ ]
}
- var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
-
- // remove <a name=....> as rendering on yahoo mailer is borked with this.
- // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
-
- //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
- // remove_keep_children = true;
- //}
-
- if (remove_keep_children) {
- this.cleanUpChildren(node);
- // inserts everything just before this node...
- while (node.childNodes.length) {
- var cn = node.childNodes[0];
- node.removeChild(cn);
- node.parentNode.insertBefore(cn, node);
- }
- node.parentNode.removeChild(node);
- return;
+ if(this.fixed){
+ cfg.cls += ' alert-messages-fixed';
}
- if (!node.attributes || !node.attributes.length) {
- this.cleanUpChildren(node);
- return;
+ if(this.closable){
+ cfg.cn.push({
+ tag: 'button',
+ cls: 'close',
+ html: 'x'
+ });
}
- function cleanAttr(n,v)
- {
-
- if (v.match(/^\./) || v.match(/^\//)) {
- return;
- }
- if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
- return;
- }
- if (v.match(/^#/)) {
- return;
- }
-// Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
- node.removeAttribute(n);
-
- }
+ return cfg;
+ },
+
+ onRender : function(ct, position)
+ {
+ Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
- var cwhite = this.cwhite;
- var cblack = this.cblack;
+ if(!this.el){
+ var cfg = Roo.apply({}, this.getAutoCreate());
+ cfg.id = Roo.id();
- function cleanStyle(n,v)
- {
- if (v.match(/expression/)) { //XSS?? should we even bother..
- node.removeAttribute(n);
- return;
+ if (this.cls) {
+ cfg.cls += ' ' + this.cls;
}
-
- var parts = v.split(/;/);
- var clean = [];
-
- Roo.each(parts, function(p) {
- p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
- if (!p.length) {
- return true;
- }
- var l = p.split(':').shift().replace(/\s+/g,'');
- l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
-
- if ( cwhite.length && cblack.indexOf(l) > -1) {
-// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
- //node.removeAttribute(n);
- return true;
- }
- //Roo.log()
- // only allow 'c whitelisted system attributes'
- if ( cwhite.length && cwhite.indexOf(l) < 0) {
-// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
- //node.removeAttribute(n);
- return true;
- }
-
-
-
-
- clean.push(p);
- return true;
- });
- if (clean.length) {
- node.setAttribute(n, clean.join(';'));
- } else {
- node.removeAttribute(n);
+ if (this.style) {
+ cfg.style = this.style;
}
+ this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
+ this.el.setVisibilityMode(Roo.Element.DISPLAY);
}
+ this.el.select('>button.close').on('click', this.hide, this);
- for (var i = node.attributes.length-1; i > -1 ; i--) {
- var a = node.attributes[i];
- //console.log(a);
-
- if (a.name.toLowerCase().substr(0,2)=='on') {
- node.removeAttribute(a.name);
- continue;
- }
- if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
- node.removeAttribute(a.name);
- continue;
- }
- if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
- cleanAttr(a.name,a.value); // fixme..
- continue;
- }
- if (a.name == 'style') {
- cleanStyle(a.name,a.value);
- continue;
- }
- /// clean up MS crap..
- // tecnically this should be a list of valid class'es..
-
-
- if (a.name == 'class') {
- if (a.value.match(/^Mso/)) {
- node.className = '';
- }
-
- if (a.value.match(/body/)) {
- node.className = '';
- }
- continue;
- }
-
- // style cleanup!?
- // class cleanup?
-
+ },
+
+ show : function()
+ {
+ if (!this.rendered) {
+ this.render();
}
+ this.el.show();
+
+ this.fireEvent('show', this);
- this.cleanUpChildren(node);
+ },
+
+ hide : function()
+ {
+ if (!this.rendered) {
+ this.render();
+ }
+ this.el.hide();
+ this.fireEvent('hide', this);
},
- /**
- * Clean up MS wordisms...
- */
- cleanWord : function(node)
+ update : function()
{
+// var e = this.el.dom.firstChild;
+//
+// if(this.closable){
+// e = e.nextSibling;
+// }
+//
+// e.data = this.html || '';
+
+ this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
+ }
+
+});
+
+
+
+ /*
+ * - LGPL
+ *
+ * Graph
+ *
+ */
+
+
+/**
+ * @class Roo.bootstrap.Graph
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Graph class
+> Prameters
+ -sm {number} sm 4
+ -md {number} md 5
+ @cfg {String} graphtype bar | vbar | pie
+ @cfg {number} g_x coodinator | centre x (pie)
+ @cfg {number} g_y coodinator | centre y (pie)
+ @cfg {number} g_r radius (pie)
+ @cfg {number} g_height height of the chart (respected by all elements in the set)
+ @cfg {number} g_width width of the chart (respected by all elements in the set)
+ @cfg {Object} title The title of the chart
+
+ -{Array} values
+ -opts (object) options for the chart
+ o {
+ o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
+ o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
+ o vgutter (number)
+ o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
+ o stacked (boolean) whether or not to tread values as in a stacked bar chart
+ o to
+ o stretch (boolean)
+ o }
+ -opts (object) options for the pie
+ o{
+ o cut
+ o startAngle (number)
+ o endAngle (number)
+ }
+ *
+ * @constructor
+ * Create a new Input
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Graph = function(config){
+ Roo.bootstrap.Graph.superclass.constructor.call(this, config);
+
+ this.addEvents({
+ // img events
+ /**
+ * @event click
+ * The img click event for the img.
+ * @param {Roo.EventObject} e
+ */
+ "click" : true
+ });
+};
+
+Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
+
+ sm: 4,
+ md: 5,
+ graphtype: 'bar',
+ g_height: 250,
+ g_width: 400,
+ g_x: 50,
+ g_y: 50,
+ g_r: 30,
+ opts:{
+ //g_colors: this.colors,
+ g_type: 'soft',
+ g_gutter: '20%'
+
+ },
+ title : false,
+
+ getAutoCreate : function(){
+
+ var cfg = {
+ tag: 'div',
+ html : null
+ }
- if (!node) {
- this.cleanWord(this.doc.body);
- return;
+ return cfg;
+ },
+
+ onRender : function(ct,position){
+ Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
+ this.raphael = Raphael(this.el.dom);
+
+ // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
+ // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
+ // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
+ // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
+ /*
+ r.text(160, 10, "Single Series Chart").attr(txtattr);
+ r.text(480, 10, "Multiline Series Chart").attr(txtattr);
+ r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
+ r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
+
+ r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
+ r.barchart(330, 10, 300, 220, data1);
+ r.barchart(10, 250, 300, 220, data2, {stacked: true});
+ r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
+ */
+
+ // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
+ // r.barchart(30, 30, 560, 250, xdata, {
+ // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
+ // axis : "0 0 1 1",
+ // axisxlabels : xdata
+ // //yvalues : cols,
+
+ // });
+// var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
+//
+// this.load(null,xdata,{
+// axis : "0 0 1 1",
+// axisxlabels : xdata
+// });
+
+ },
+
+ load : function(graphtype,xdata,opts){
+ this.raphael.clear();
+ if(!graphtype) {
+ graphtype = this.graphtype;
}
- if (node.nodeName == "#text") {
- // clean up silly Windows -- stuff?
- return;
+ if(!opts){
+ opts = this.opts;
}
- if (node.nodeName == "#comment") {
- node.parentNode.removeChild(node);
- // clean up silly Windows -- stuff?
- return;
+ var r = this.raphael,
+ fin = function () {
+ this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
+ },
+ fout = function () {
+ this.flag.animate({opacity: 0}, 300, function () {this.remove();});
+ },
+ pfin = function() {
+ this.sector.stop();
+ this.sector.scale(1.1, 1.1, this.cx, this.cy);
+
+ if (this.label) {
+ this.label[0].stop();
+ this.label[0].attr({ r: 7.5 });
+ this.label[1].attr({ "font-weight": 800 });
+ }
+ },
+ pfout = function() {
+ this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
+
+ if (this.label) {
+ this.label[0].animate({ r: 5 }, 500, "bounce");
+ this.label[1].attr({ "font-weight": 400 });
+ }
+ };
+
+ switch(graphtype){
+ case 'bar':
+ this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
+ break;
+ case 'hbar':
+ this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
+ break;
+ case 'pie':
+// opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
+// href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
+//
+ this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
+
+ break;
+
}
- if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
- node.parentNode.removeChild(node);
- return;
+ if(this.title){
+ this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
}
- // remove - but keep children..
- if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
- while (node.childNodes.length) {
- var cn = node.childNodes[0];
- node.removeChild(cn);
- node.parentNode.insertBefore(cn, node);
- }
- node.parentNode.removeChild(node);
- this.iterateChildren(node, this.cleanWord);
- return;
+ },
+
+ setTitle: function(o)
+ {
+ this.title = o;
+ },
+
+ initEvents: function() {
+
+ if(!this.href){
+ this.el.on('click', this.onClick, this);
}
- // clean styles
- if (node.className.length) {
-
- var cn = node.className.split(/\W+/);
- var cna = [];
- Roo.each(cn, function(cls) {
- if (cls.match(/Mso[a-zA-Z]+/)) {
- return;
+ },
+
+ onClick : function(e)
+ {
+ Roo.log('img onclick');
+ this.fireEvent('click', this, e);
+ }
+
+});
+
+
+/*
+ * - LGPL
+ *
+ * numberBox
+ *
+ */
+Roo.bootstrap.dash = Roo.bootstrap.dash || {};
+
+/**
+ * @class Roo.bootstrap.dash.NumberBox
+ * @extends Roo.bootstrap.Component
+ * Bootstrap NumberBox class
+ * @cfg {String} headline Box headline
+ * @cfg {String} content Box content
+ * @cfg {String} icon Box icon
+ * @cfg {String} footer Footer text
+ * @cfg {String} fhref Footer href
+ *
+ * @constructor
+ * Create a new NumberBox
+ * @param {Object} config The config object
+ */
+
+
+Roo.bootstrap.dash.NumberBox = function(config){
+ Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
+
+};
+
+Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
+
+ headline : '',
+ content : '',
+ icon : '',
+ footer : '',
+ fhref : '',
+ ficon : '',
+
+ getAutoCreate : function(){
+
+ var cfg = {
+ tag : 'div',
+ cls : 'small-box ',
+ cn : [
+ {
+ tag : 'div',
+ cls : 'inner',
+ cn :[
+ {
+ tag : 'h3',
+ cls : 'roo-headline',
+ html : this.headline
+ },
+ {
+ tag : 'p',
+ cls : 'roo-content',
+ html : this.content
+ }
+ ]
}
- cna.push(cls);
- });
- node.className = cna.length ? cna.join(' ') : '';
- if (!cna.length) {
- node.removeAttribute("class");
- }
+ ]
}
- if (node.hasAttribute("lang")) {
- node.removeAttribute("lang");
+ if(this.icon){
+ cfg.cn.push({
+ tag : 'div',
+ cls : 'icon',
+ cn :[
+ {
+ tag : 'i',
+ cls : 'ion ' + this.icon
+ }
+ ]
+ });
}
- if (node.hasAttribute("style")) {
+ if(this.footer){
+ var footer = {
+ tag : 'a',
+ cls : 'small-box-footer',
+ href : this.fhref || '#',
+ html : this.footer
+ };
+
+ cfg.cn.push(footer);
- var styles = node.getAttribute("style").split(";");
- var nstyle = [];
- Roo.each(styles, function(s) {
- if (!s.match(/:/)) {
- return;
- }
- var kv = s.split(":");
- if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
- return;
- }
- // what ever is left... we allow.
- nstyle.push(s);
- });
- node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
- if (!nstyle.length) {
- node.removeAttribute('style');
- }
}
- this.iterateChildren(node, this.cleanWord);
-
-
+ return cfg;
},
- /**
- * iterateChildren of a Node, calling fn each time, using this as the scole..
- * @param {DomNode} node node to iterate children of.
- * @param {Function} fn method of this class to call on each item.
- */
- iterateChildren : function(node, fn)
+
+ onRender : function(ct,position){
+ Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
+
+
+
+
+ },
+
+ setHeadline: function (value)
{
- if (!node.childNodes.length) {
- return;
- }
- for (var i = node.childNodes.length-1; i > -1 ; i--) {
- fn.call(this, node.childNodes[i])
- }
+ this.el.select('.roo-headline',true).first().dom.innerHTML = value;
},
-
- /**
- * cleanTableWidths.
- *
- * Quite often pasting from word etc.. results in tables with column and widths.
- * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
- *
- */
- cleanTableWidths : function(node)
+ setFooter: function (value, href)
{
-
-
- if (!node) {
- this.cleanTableWidths(this.doc.body);
- return;
- }
+ this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
- // ignore list...
- if (node.nodeName == "#text" || node.nodeName == "#comment") {
- return;
- }
- Roo.log(node.tagName);
- if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
- this.iterateChildren(node, this.cleanTableWidths);
- return;
- }
- if (node.hasAttribute('width')) {
- node.removeAttribute('width');
+ if(href){
+ this.el.select('a.small-box-footer',true).first().attr('href', href);
}
+ },
+
+ setContent: function (value)
+ {
+ this.el.select('.roo-content',true).first().dom.innerHTML = value;
+ },
+
+ initEvents: function()
+ {
+
+ }
+
+});
+
+
+/*
+ * - LGPL
+ *
+ * TabBox
+ *
+ */
+Roo.bootstrap.dash = Roo.bootstrap.dash || {};
+
+/**
+ * @class Roo.bootstrap.dash.TabBox
+ * @extends Roo.bootstrap.Component
+ * Bootstrap TabBox class
+ * @cfg {String} title Title of the TabBox
+ * @cfg {String} icon Icon of the TabBox
+ * @cfg {Boolean} showtabs (true|false) show the tabs default true
+ * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
+ *
+ * @constructor
+ * Create a new TabBox
+ * @param {Object} config The config object
+ */
+
+
+Roo.bootstrap.dash.TabBox = function(config){
+ Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
+ this.addEvents({
+ // raw events
+ /**
+ * @event addpane
+ * When a pane is added
+ * @param {Roo.bootstrap.dash.TabPane} pane
+ */
+ "addpane" : true,
+ /**
+ * @event activatepane
+ * When a pane is activated
+ * @param {Roo.bootstrap.dash.TabPane} pane
+ */
+ "activatepane" : true
+
- if (node.hasAttribute("style")) {
- // pretty basic...
-
- var styles = node.getAttribute("style").split(";");
- var nstyle = [];
- Roo.each(styles, function(s) {
- if (!s.match(/:/)) {
- return;
- }
- var kv = s.split(":");
- if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
- return;
- }
- // what ever is left... we allow.
- nstyle.push(s);
- });
- node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
- if (!nstyle.length) {
- node.removeAttribute('style');
- }
- }
-
- this.iterateChildren(node, this.cleanTableWidths);
-
-
- },
-
-
+ });
+ this.panes = [];
+};
+
+Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
+
+ title : '',
+ icon : false,
+ showtabs : true,
+ tabScrollable : false,
- domToHTML : function(currentElement, depth, nopadtext) {
-
- depth = depth || 0;
- nopadtext = nopadtext || false;
+ getChildContainer : function()
+ {
+ return this.el.select('.tab-content', true).first();
+ },
- if (!currentElement) {
- return this.domToHTML(this.doc.body);
- }
+ getAutoCreate : function(){
- //Roo.log(currentElement);
- var j;
- var allText = false;
- var nodeName = currentElement.nodeName;
- var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
+ var header = {
+ tag: 'li',
+ cls: 'pull-left header',
+ html: this.title,
+ cn : []
+ };
- if (nodeName == '#text') {
-
- return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
+ if(this.icon){
+ header.cn.push({
+ tag: 'i',
+ cls: 'fa ' + this.icon
+ });
}
+ var h = {
+ tag: 'ul',
+ cls: 'nav nav-tabs pull-right',
+ cn: [
+ header
+ ]
+ };
- var ret = '';
- if (nodeName != 'BODY') {
-
- var i = 0;
- // Prints the node tagName, such as <A>, <IMG>, etc
- if (tagName) {
- var attr = [];
- for(i = 0; i < currentElement.attributes.length;i++) {
- // quoting?
- var aname = currentElement.attributes.item(i).name;
- if (!currentElement.attributes.item(i).value.length) {
- continue;
+ if(this.tabScrollable){
+ h = {
+ tag: 'div',
+ cls: 'tab-header',
+ cn: [
+ {
+ tag: 'ul',
+ cls: 'nav nav-tabs pull-right',
+ cn: [
+ header
+ ]
}
- attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
- }
-
- ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
- }
- else {
-
- // eack
+ ]
}
- } else {
- tagName = false;
- }
- if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
- return ret;
- }
- if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
- nopadtext = true;
}
-
- // Traverse the tree
- i = 0;
- var currentElementChild = currentElement.childNodes.item(i);
- var allText = true;
- var innerHTML = '';
- lastnode = '';
- while (currentElementChild) {
- // Formatting code (indent the tree so it looks nice on the screen)
- var nopad = nopadtext;
- if (lastnode == 'SPAN') {
- nopad = true;
- }
- // text
- if (currentElementChild.nodeName == '#text') {
- var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
- toadd = nopadtext ? toadd : toadd.trim();
- if (!nopad && toadd.length > 80) {
- innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
+ var cfg = {
+ tag: 'div',
+ cls: 'nav-tabs-custom',
+ cn: [
+ h,
+ {
+ tag: 'div',
+ cls: 'tab-content no-padding',
+ cn: []
}
- innerHTML += toadd;
-
- i++;
- currentElementChild = currentElement.childNodes.item(i);
- lastNode = '';
- continue;
- }
- allText = false;
-
- innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
-
- // Recursively traverse the tree structure of the child node
- innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
- lastnode = currentElementChild.nodeName;
- i++;
- currentElementChild=currentElement.childNodes.item(i);
- }
-
- ret += innerHTML;
-
- if (!allText) {
- // The remaining code is mostly for formatting the tree
- ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
- }
-
-
- if (tagName) {
- ret+= "</"+tagName+">";
+ ]
}
- return ret;
-
+
+ return cfg;
},
-
- applyBlacklists : function()
+ initEvents : function()
{
- var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
- var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
-
- this.white = [];
- this.black = [];
- Roo.each(Roo.HtmlEditorCore.white, function(tag) {
- if (b.indexOf(tag) > -1) {
- return;
- }
- this.white.push(tag);
-
- }, this);
-
- Roo.each(w, function(tag) {
- if (b.indexOf(tag) > -1) {
- return;
- }
- if (this.white.indexOf(tag) > -1) {
- return;
- }
- this.white.push(tag);
-
- }, this);
-
-
- Roo.each(Roo.HtmlEditorCore.black, function(tag) {
- if (w.indexOf(tag) > -1) {
- return;
- }
- this.black.push(tag);
-
- }, this);
+ //Roo.log('add add pane handler');
+ this.on('addpane', this.onAddPane, this);
+ },
+ /**
+ * Updates the box title
+ * @param {String} html to set the title to.
+ */
+ setTitle : function(value)
+ {
+ this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
+ },
+ onAddPane : function(pane)
+ {
+ this.panes.push(pane);
+ //Roo.log('addpane');
+ //Roo.log(pane);
+ // tabs are rendere left to right..
+ if(!this.showtabs){
+ return;
+ }
- Roo.each(b, function(tag) {
- if (w.indexOf(tag) > -1) {
- return;
- }
- if (this.black.indexOf(tag) > -1) {
- return;
- }
- this.black.push(tag);
-
- }, this);
+ var ctr = this.el.select('.nav-tabs', true).first();
+
+
+ var existing = ctr.select('.nav-tab',true);
+ var qty = existing.getCount();;
- w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
- b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
+ var tab = ctr.createChild({
+ tag : 'li',
+ cls : 'nav-tab' + (qty ? '' : ' active'),
+ cn : [
+ {
+ tag : 'a',
+ href:'#',
+ html : pane.title
+ }
+ ]
+ }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
+ pane.tab = tab;
- this.cwhite = [];
- this.cblack = [];
- Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
- if (b.indexOf(tag) > -1) {
- return;
- }
- this.cwhite.push(tag);
-
- }, this);
+ tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
+ if (!qty) {
+ pane.el.addClass('active');
+ }
- Roo.each(w, function(tag) {
- if (b.indexOf(tag) > -1) {
- return;
- }
- if (this.cwhite.indexOf(tag) > -1) {
- return;
- }
- this.cwhite.push(tag);
-
- }, this);
+
+ },
+ onTabClick : function(ev,un,ob,pane)
+ {
+ //Roo.log('tab - prev default');
+ ev.preventDefault();
- Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
- if (w.indexOf(tag) > -1) {
- return;
- }
- this.cblack.push(tag);
-
- }, this);
+ this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
+ pane.tab.addClass('active');
+ //Roo.log(pane.title);
+ this.getChildContainer().select('.tab-pane',true).removeClass('active');
+ // technically we should have a deactivate event.. but maybe add later.
+ // and it should not de-activate the selected tab...
+ this.fireEvent('activatepane', pane);
+ pane.el.addClass('active');
+ pane.fireEvent('activate');
+
- Roo.each(b, function(tag) {
- if (w.indexOf(tag) > -1) {
- return;
- }
- if (this.cblack.indexOf(tag) > -1) {
- return;
- }
- this.cblack.push(tag);
-
- }, this);
},
- setStylesheets : function(stylesheets)
+ getActivePane : function()
{
- if(typeof(stylesheets) == 'string'){
- Roo.get(this.iframe.contentDocument.head).createChild({
- tag : 'link',
- rel : 'stylesheet',
- type : 'text/css',
- href : stylesheets
- });
-
- return;
- }
- var _this = this;
-
- Roo.each(stylesheets, function(s) {
- if(!s.length){
- return;
+ var r = false;
+ Roo.each(this.panes, function(p) {
+ if(p.el.hasClass('active')){
+ r = p;
+ return false;
}
- Roo.get(_this.iframe.contentDocument.head).createChild({
- tag : 'link',
- rel : 'stylesheet',
- type : 'text/css',
- href : s
- });
+ return;
});
-
-
- },
-
- removeStylesheets : function()
- {
- var _this = this;
- Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
- s.remove();
- });
+ return r;
}
- // hide stuff that is not compatible
- /**
- * @event blur
- * @hide
- */
- /**
- * @event change
- * @hide
- */
- /**
- * @event focus
- * @hide
- */
- /**
- * @event specialkey
- * @hide
- */
- /**
- * @cfg {String} fieldClass @hide
- */
- /**
- * @cfg {String} focusClass @hide
- */
- /**
- * @cfg {String} autoCreate @hide
- */
- /**
- * @cfg {String} inputType @hide
- */
- /**
- * @cfg {String} invalidClass @hide
- */
- /**
- * @cfg {String} invalidText @hide
- */
- /**
- * @cfg {String} msgFx @hide
- */
- /**
- * @cfg {String} validateOnBlur @hide
- */
+
});
-Roo.HtmlEditorCore.white = [
- 'area', 'br', 'img', 'input', 'hr', 'wbr',
-
- 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
- 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
- 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
- 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
- 'table', 'ul', 'xmp',
-
- 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
- 'thead', 'tr',
-
- 'dir', 'menu', 'ol', 'ul', 'dl',
-
- 'embed', 'object'
-];
+
+/*
+ * - LGPL
+ *
+ * Tab pane
+ *
+ */
+Roo.bootstrap.dash = Roo.bootstrap.dash || {};
+/**
+ * @class Roo.bootstrap.TabPane
+ * @extends Roo.bootstrap.Component
+ * Bootstrap TabPane class
+ * @cfg {Boolean} active (false | true) Default false
+ * @cfg {String} title title of panel
+ *
+ * @constructor
+ * Create a new TabPane
+ * @param {Object} config The config object
+ */
-Roo.HtmlEditorCore.black = [
- // 'embed', 'object', // enable - backend responsiblity to clean thiese
- 'applet', //
- 'base', 'basefont', 'bgsound', 'blink', 'body',
- 'frame', 'frameset', 'head', 'html', 'ilayer',
- 'iframe', 'layer', 'link', 'meta', 'object',
- 'script', 'style' ,'title', 'xml' // clean later..
-];
-Roo.HtmlEditorCore.clean = [
- 'script', 'style', 'title', 'xml'
-];
-Roo.HtmlEditorCore.remove = [
- 'font'
-];
-// attributes..
+Roo.bootstrap.dash.TabPane = function(config){
+ Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
+
+ this.addEvents({
+ // raw events
+ /**
+ * @event activate
+ * When a pane is activated
+ * @param {Roo.bootstrap.dash.TabPane} pane
+ */
+ "activate" : true
+
+ });
+};
-Roo.HtmlEditorCore.ablack = [
- 'on'
-];
+Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
+
+ active : false,
+ title : '',
+
+ // the tabBox that this is attached to.
+ tab : false,
+
+ getAutoCreate : function()
+ {
+ var cfg = {
+ tag: 'div',
+ cls: 'tab-pane'
+ }
+
+ if(this.active){
+ cfg.cls += ' active';
+ }
+
+ return cfg;
+ },
+ initEvents : function()
+ {
+ //Roo.log('trigger add pane handler');
+ this.parent().fireEvent('addpane', this)
+ },
+
+ /**
+ * Updates the tab title
+ * @param {String} html to set the title to.
+ */
+ setTitle: function(str)
+ {
+ if (!this.tab) {
+ return;
+ }
+ this.title = str;
+ this.tab.select('a', true).first().dom.innerHTML = str;
+
+ }
-Roo.HtmlEditorCore.aclean = [
- 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
-];
-
-// protocols..
-Roo.HtmlEditorCore.pwhite= [
- 'http', 'https', 'mailto'
-];
-
-// white listed style attributes.
-Roo.HtmlEditorCore.cwhite= [
- // 'text-align', /// default is to allow most things..
-
-
-// 'font-size'//??
-];
-
-// black listed style attributes.
-Roo.HtmlEditorCore.cblack= [
- // 'font-size' -- this can be set by the project
-];
+
+
+});
+
-Roo.HtmlEditorCore.swapCodes =[
- [ 8211, "--" ],
- [ 8212, "--" ],
- [ 8216, "'" ],
- [ 8217, "'" ],
- [ 8220, '"' ],
- [ 8221, '"' ],
- [ 8226, "*" ],
- [ 8230, "..." ]
-];
- /*
+ /*
* - LGPL
*
- * HtmlEditor
+ * menu
*
*/
+Roo.bootstrap.menu = Roo.bootstrap.menu || {};
/**
- * @class Roo.bootstrap.HtmlEditor
- * @extends Roo.bootstrap.TextArea
- * Bootstrap HtmlEditor class
-
+ * @class Roo.bootstrap.menu.Menu
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Menu class - container for Menu
+ * @cfg {String} html Text of the menu
+ * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
+ * @cfg {String} icon Font awesome icon
+ * @cfg {String} pos Menu align to (top | bottom) default bottom
+ *
+ *
* @constructor
- * Create a new HtmlEditor
+ * Create a new Menu
* @param {Object} config The config object
*/
-Roo.bootstrap.HtmlEditor = function(config){
- Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
- if (!this.toolbars) {
- this.toolbars = [];
- }
- this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
- this.addEvents({
- /**
- * @event initialize
- * Fires when the editor is fully initialized (including the iframe)
- * @param {HtmlEditor} this
- */
- initialize: true,
- /**
- * @event activate
- * Fires when the editor is first receives the focus. Any insertion must wait
- * until after this event.
- * @param {HtmlEditor} this
- */
- activate: true,
- /**
- * @event beforesync
- * Fires before the textarea is updated with content from the editor iframe. Return false
- * to cancel the sync.
- * @param {HtmlEditor} this
- * @param {String} html
- */
- beforesync: true,
- /**
- * @event beforepush
- * Fires before the iframe editor is updated with content from the textarea. Return false
- * to cancel the push.
- * @param {HtmlEditor} this
- * @param {String} html
- */
- beforepush: true,
- /**
- * @event sync
- * Fires when the textarea is updated with content from the editor iframe.
- * @param {HtmlEditor} this
- * @param {String} html
- */
- sync: true,
- /**
- * @event push
- * Fires when the iframe editor is updated with content from the textarea.
- * @param {HtmlEditor} this
- * @param {String} html
- */
- push: true,
- /**
- * @event editmodechange
- * Fires when the editor switches edit modes
- * @param {HtmlEditor} this
- * @param {Boolean} sourceEdit True if source edit, false if standard editing.
- */
- editmodechange: true,
- /**
- * @event editorevent
- * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
- * @param {HtmlEditor} this
- */
- editorevent: true,
- /**
- * @event firstfocus
- * Fires when on first focus - needed by toolbars..
- * @param {HtmlEditor} this
- */
- firstfocus: true,
- /**
- * @event autosave
- * Auto save the htmlEditor value as a file into Events
- * @param {HtmlEditor} this
- */
- autosave: true,
- /**
- * @event savedpreview
- * preview the saved version of htmlEditor
- * @param {HtmlEditor} this
- */
- savedpreview: true
- });
-};
-
-Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
-
-
- /**
- * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
- */
- toolbars : false,
-
- /**
- * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
- * Roo.resizable.
- */
- resizable : false,
- /**
- * @cfg {Number} height (in pixels)
- */
- height: 300,
- /**
- * @cfg {Number} width (in pixels)
- */
- width: false,
-
- /**
- * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
- *
- */
- stylesheets: false,
-
- // id of frame..
- frameId: false,
+Roo.bootstrap.menu.Menu = function(config){
+ Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
- // private properties
- validationEvent : false,
- deferHeight: true,
- initialized : false,
- activated : false,
+ this.addEvents({
+ /**
+ * @event beforeshow
+ * Fires before this menu is displayed
+ * @param {Roo.bootstrap.menu.Menu} this
+ */
+ beforeshow : true,
+ /**
+ * @event beforehide
+ * Fires before this menu is hidden
+ * @param {Roo.bootstrap.menu.Menu} this
+ */
+ beforehide : true,
+ /**
+ * @event show
+ * Fires after this menu is displayed
+ * @param {Roo.bootstrap.menu.Menu} this
+ */
+ show : true,
+ /**
+ * @event hide
+ * Fires after this menu is hidden
+ * @param {Roo.bootstrap.menu.Menu} this
+ */
+ hide : true,
+ /**
+ * @event click
+ * Fires when this menu is clicked (or when the enter key is pressed while it is active)
+ * @param {Roo.bootstrap.menu.Menu} this
+ * @param {Roo.EventObject} e
+ */
+ click : true
+ });
- onFocus : Roo.emptyFn,
- iframePad:3,
- hideMode:'offsets',
+};
+
+Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
+ submenu : false,
+ html : '',
+ weight : 'default',
+ icon : false,
+ pos : 'bottom',
- tbContainer : false,
- toolbarContainer :function() {
- return this.wrap.select('.x-html-editor-tb',true).first();
+ getChildContainer : function() {
+ if(this.isSubMenu){
+ return this.el;
+ }
+
+ return this.el.select('ul.dropdown-menu', true).first();
},
-
- /**
- * Protected method that will not generally be called directly. It
- * is called when the editor creates its toolbar. Override this method if you need to
- * add custom toolbar buttons.
- * @param {HtmlEditor} editor
- */
- createToolbar : function(){
+
+ getAutoCreate : function()
+ {
+ var text = [
+ {
+ tag : 'span',
+ cls : 'roo-menu-text',
+ html : this.html
+ }
+ ];
+
+ if(this.icon){
+ text.unshift({
+ tag : 'i',
+ cls : 'fa ' + this.icon
+ })
+ }
- Roo.log("create toolbars");
- this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
- this.toolbars[0].render(this.toolbarContainer());
+ var cfg = {
+ tag : 'div',
+ cls : 'btn-group',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'dropdown-button btn btn-' + this.weight,
+ cn : text
+ },
+ {
+ tag : 'button',
+ cls : 'dropdown-toggle btn btn-' + this.weight,
+ cn : [
+ {
+ tag : 'span',
+ cls : 'caret'
+ }
+ ]
+ },
+ {
+ tag : 'ul',
+ cls : 'dropdown-menu'
+ }
+ ]
+
+ };
- return;
+ if(this.pos == 'top'){
+ cfg.cls += ' dropup';
+ }
-// if (!editor.toolbars || !editor.toolbars.length) {
-// editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
-// }
-//
-// for (var i =0 ; i < editor.toolbars.length;i++) {
-// editor.toolbars[i] = Roo.factory(
-// typeof(editor.toolbars[i]) == 'string' ?
-// { xtype: editor.toolbars[i]} : editor.toolbars[i],
-// Roo.bootstrap.HtmlEditor);
-// editor.toolbars[i].init(editor);
-// }
+ if(this.isSubMenu){
+ cfg = {
+ tag : 'ul',
+ cls : 'dropdown-menu'
+ }
+ }
+
+ return cfg;
},
-
-
- // private
+
onRender : function(ct, position)
{
- // Roo.log("Call onRender: " + this.xtype);
- var _t = this;
- Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
-
- this.wrap = this.inputEl().wrap({
- cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
- });
+ this.isSubMenu = ct.hasClass('dropdown-submenu');
- this.editorcore.onRender(ct, position);
-
- if (this.resizable) {
- this.resizeEl = new Roo.Resizable(this.wrap, {
- pinned : true,
- wrap: true,
- dynamic : true,
- minHeight : this.height,
- height: this.height,
- handles : this.resizable,
- width: this.width,
- listeners : {
- resize : function(r, w, h) {
- _t.onResize(w,h); // -something
- }
- }
- });
-
+ Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
+ },
+
+ initEvents : function()
+ {
+ if(this.isSubMenu){
+ return;
}
- this.createToolbar(this);
-
- if(!this.width && this.resizable){
- this.setSize(this.wrap.getSize());
- }
- if (this.resizeEl) {
- this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
- // should trigger onReize..
- }
+ this.hidden = true;
+
+ this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
+ this.triggerEl.on('click', this.onTriggerPress, this);
+
+ this.buttonEl = this.el.select('button.dropdown-button', true).first();
+ this.buttonEl.on('click', this.onClick, this);
},
-
- // private
- onResize : function(w, h)
+
+ list : function()
{
- Roo.log('resize: ' +w + ',' + h );
- Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
- var ew = false;
- var eh = false;
-
- if(this.inputEl() ){
- if(typeof w == 'number'){
- var aw = w - this.wrap.getFrameWidth('lr');
- this.inputEl().setWidth(this.adjustWidth('textarea', aw));
- ew = aw;
- }
- if(typeof h == 'number'){
- var tbh = -11; // fixme it needs to tool bar size!
- for (var i =0; i < this.toolbars.length;i++) {
- // fixme - ask toolbars for heights?
- tbh += this.toolbars[i].el.getHeight();
- //if (this.toolbars[i].footer) {
- // tbh += this.toolbars[i].footer.el.getHeight();
- //}
- }
-
-
-
-
-
- var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
- ah -= 5; // knock a few pixes off for look..
- this.inputEl().setHeight(this.adjustWidth('textarea', ah));
- var eh = ah;
- }
+ if(this.isSubMenu){
+ return this.el;
}
- Roo.log('onResize:' + [w,h,ew,eh].join(',') );
- this.editorcore.onResize(ew,eh);
+ return this.el.select('ul.dropdown-menu', true).first();
},
-
- /**
- * Toggles the editor between standard and source edit mode.
- * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
- */
- toggleSourceEdit : function(sourceEditMode)
+
+ onClick : function(e)
{
- this.editorcore.toggleSourceEdit(sourceEditMode);
-
- if(this.editorcore.sourceEditMode){
- Roo.log('editor - showing textarea');
-
-// Roo.log('in');
-// Roo.log(this.syncValue());
- this.syncValue();
- this.inputEl().removeClass(['hide', 'x-hidden']);
- this.inputEl().dom.removeAttribute('tabIndex');
- this.inputEl().focus();
- }else{
- Roo.log('editor - hiding textarea');
-// Roo.log('out')
-// Roo.log(this.pushValue());
- this.pushValue();
-
- this.inputEl().addClass(['hide', 'x-hidden']);
- this.inputEl().dom.setAttribute('tabIndex', -1);
- //this.deferFocus();
- }
-
- if(this.resizable){
- this.setSize(this.wrap.getSize());
+ this.fireEvent("click", this, e);
+ },
+
+ onTriggerPress : function(e)
+ {
+ if (this.isVisible()) {
+ this.hide();
+ } else {
+ this.show();
}
-
- this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
},
-
- // private (for BoxComponent)
- adjustSize : Roo.BoxComponent.prototype.adjustSize,
-
- // private (for BoxComponent)
- getResizeEl : function(){
- return this.wrap;
+
+ isVisible : function(){
+ return !this.hidden;
},
-
- // private (for BoxComponent)
- getPositionEl : function(){
- return this.wrap;
+
+ show : function()
+ {
+ this.fireEvent("beforeshow", this);
+
+ this.hidden = false;
+ this.el.addClass('open');
+
+ Roo.get(document).on("mouseup", this.onMouseUp, this);
+
+ this.fireEvent("show", this);
+
+
},
-
- // private
- initEvents : function(){
- this.originalValue = this.getValue();
+
+ hide : function()
+ {
+ this.fireEvent("beforehide", this);
+
+ this.hidden = true;
+ this.el.removeClass('open');
+
+ Roo.get(document).un("mouseup", this.onMouseUp);
+
+ this.fireEvent("hide", this);
},
+
+ onMouseUp : function()
+ {
+ this.hide();
+ }
+
+});
-// /**
-// * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
-// * @method
-// */
-// markInvalid : Roo.emptyFn,
-// /**
-// * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
-// * @method
-// */
-// clearInvalid : Roo.emptyFn,
+
+ /*
+ * - LGPL
+ *
+ * menu item
+ *
+ */
+Roo.bootstrap.menu = Roo.bootstrap.menu || {};
- setValue : function(v){
- Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
- this.editorcore.pushValue();
- },
+/**
+ * @class Roo.bootstrap.menu.Item
+ * @extends Roo.bootstrap.Component
+ * Bootstrap MenuItem class
+ * @cfg {Boolean} submenu (true | false) default false
+ * @cfg {String} html text of the item
+ * @cfg {String} href the link
+ * @cfg {Boolean} disable (true | false) default false
+ * @cfg {Boolean} preventDefault (true | false) default true
+ * @cfg {String} icon Font awesome icon
+ * @cfg {String} pos Submenu align to (left | right) default right
+ *
+ *
+ * @constructor
+ * Create a new Item
+ * @param {Object} config The config object
+ */
-
- // private
- deferFocus : function(){
- this.focus.defer(10, this);
- },
- // doc'ed in Field
- focus : function(){
- this.editorcore.focus();
-
- },
-
+Roo.bootstrap.menu.Item = function(config){
+ Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
+ this.addEvents({
+ /**
+ * @event mouseover
+ * Fires when the mouse is hovering over this menu
+ * @param {Roo.bootstrap.menu.Item} this
+ * @param {Roo.EventObject} e
+ */
+ mouseover : true,
+ /**
+ * @event mouseout
+ * Fires when the mouse exits this menu
+ * @param {Roo.bootstrap.menu.Item} this
+ * @param {Roo.EventObject} e
+ */
+ mouseout : true,
+ // raw events
+ /**
+ * @event click
+ * The raw click event for the entire grid.
+ * @param {Roo.EventObject} e
+ */
+ click : true
+ });
+};
- // private
- onDestroy : function(){
+Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
+
+ submenu : false,
+ href : '',
+ html : '',
+ preventDefault: true,
+ disable : false,
+ icon : false,
+ pos : 'right',
+
+ getAutoCreate : function()
+ {
+ var text = [
+ {
+ tag : 'span',
+ cls : 'roo-menu-item-text',
+ html : this.html
+ }
+ ];
+
+ if(this.icon){
+ text.unshift({
+ tag : 'i',
+ cls : 'fa ' + this.icon
+ })
+ }
+ var cfg = {
+ tag : 'li',
+ cn : [
+ {
+ tag : 'a',
+ href : this.href || '#',
+ cn : text
+ }
+ ]
+ };
+ if(this.disable){
+ cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
+ }
- if(this.rendered){
+ if(this.submenu){
+ cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
- for (var i =0; i < this.toolbars.length;i++) {
- // fixme - ask toolbars for heights?
- this.toolbars[i].onDestroy();
+ if(this.pos == 'left'){
+ cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
}
-
- this.wrap.dom.innerHTML = '';
- this.wrap.remove();
}
+
+ return cfg;
},
-
- // private
- onFirstFocus : function(){
- //Roo.log("onFirstFocus");
- this.editorcore.onFirstFocus();
- for (var i =0; i < this.toolbars.length;i++) {
- this.toolbars[i].onFirstFocus();
+
+ initEvents : function()
+ {
+ this.el.on('mouseover', this.onMouseOver, this);
+ this.el.on('mouseout', this.onMouseOut, this);
+
+ this.el.select('a', true).first().on('click', this.onClick, this);
+
+ },
+
+ onClick : function(e)
+ {
+ if(this.preventDefault){
+ e.preventDefault();
}
+ this.fireEvent("click", this, e);
},
- // private
- syncValue : function()
- {
- this.editorcore.syncValue();
+ onMouseOver : function(e)
+ {
+ if(this.submenu && this.pos == 'left'){
+ this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
+ }
+
+ this.fireEvent("mouseover", this, e);
},
- pushValue : function()
- {
- this.editorcore.pushValue();
+ onMouseOut : function(e)
+ {
+ this.fireEvent("mouseout", this, e);
}
-
-
- // hide stuff that is not compatible
- /**
- * @event blur
- * @hide
- */
- /**
- * @event change
- * @hide
- */
- /**
- * @event focus
- * @hide
- */
- /**
- * @event specialkey
- * @hide
- */
- /**
- * @cfg {String} fieldClass @hide
- */
- /**
- * @cfg {String} focusClass @hide
- */
- /**
- * @cfg {String} autoCreate @hide
- */
- /**
- * @cfg {String} inputType @hide
- */
- /**
- * @cfg {String} invalidClass @hide
- */
- /**
- * @cfg {String} invalidText @hide
- */
- /**
- * @cfg {String} msgFx @hide
- */
- /**
- * @cfg {String} validateOnBlur @hide
- */
});
+
-
-
-
-
-
-Roo.namespace('Roo.bootstrap.htmleditor');
+
+ /*
+ * - LGPL
+ *
+ * menu separator
+ *
+ */
+Roo.bootstrap.menu = Roo.bootstrap.menu || {};
+
/**
- * @class Roo.bootstrap.HtmlEditorToolbar1
- * Basic Toolbar
+ * @class Roo.bootstrap.menu.Separator
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Separator class
*
- * Usage:
- *
- new Roo.bootstrap.HtmlEditor({
- ....
- toolbars : [
- new Roo.bootstrap.HtmlEditorToolbar1({
- disable : { fonts: 1 , format: 1, ..., ... , ...],
- btns : [ .... ]
- })
+ * @constructor
+ * Create a new Separator
+ * @param {Object} config The config object
+ */
+
+
+Roo.bootstrap.menu.Separator = function(config){
+ Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
+
+ getAutoCreate : function(){
+ var cfg = {
+ tag : 'li',
+ cls: 'divider'
+ };
+
+ return cfg;
}
-
+
+});
+
+
+
+ /*
+ * - LGPL
+ *
+ * Tooltip
*
- * @cfg {Object} disable List of elements to disable..
- * @cfg {Array} btns List of additional buttons.
+ */
+
+/**
+ * @class Roo.bootstrap.Tooltip
+ * Bootstrap Tooltip class
+ * This is basic at present - all componets support it by default, however they should add tooltipEl() method
+ * to determine which dom element triggers the tooltip.
*
+ * It needs to add support for additional attributes like tooltip-position
*
- * NEEDS Extra CSS?
- * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
+ * @constructor
+ * Create a new Toolti
+ * @param {Object} config The config object
*/
-
-Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
-{
-
- Roo.apply(this, config);
-
- // default disabled, based on 'good practice'..
- this.disable = this.disable || {};
- Roo.applyIf(this.disable, {
- fontSize : true,
- colors : true,
- specialElements : true
- });
- Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
-
- this.editor = config.editor;
- this.editorcore = config.editor.editorcore;
-
- this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
-
- //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
- // dont call parent... till later.
-}
-Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
-
- bar : true,
-
- editor : false,
- editorcore : false,
+
+Roo.bootstrap.Tooltip = function(config){
+ Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
+};
+
+Roo.apply(Roo.bootstrap.Tooltip, {
+ /**
+ * @function init initialize tooltip monitoring.
+ * @static
+ */
+ currentEl : false,
+ currentTip : false,
+ currentRegion : false,
+ // init : delay?
- formats : [
- "p" ,
- "h1","h2","h3","h4","h5","h6",
- "pre", "code",
- "abbr", "acronym", "address", "cite", "samp", "var",
- 'div','span'
- ],
+ init : function()
+ {
+ Roo.get(document).on('mouseover', this.enter ,this);
+ Roo.get(document).on('mouseout', this.leave, this);
+
+
+ this.currentTip = new Roo.bootstrap.Tooltip();
+ },
- onRender : function(ct, position)
+ enter : function(ev)
{
- // Roo.log("Call onRender: " + this.xtype);
+ var dom = ev.getTarget();
- Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
- Roo.log(this.el);
- this.el.dom.style.marginBottom = '0';
- var _this = this;
- var editorcore = this.editorcore;
- var editor= this.editor;
-
- var children = [];
- var btn = function(id,cmd , toggle, handler){
-
- var event = toggle ? 'toggle' : 'click';
-
- var a = {
- size : 'sm',
- xtype: 'Button',
- xns: Roo.bootstrap,
- glyphicon : id,
- cmd : id || cmd,
- enableToggle:toggle !== false,
- //html : 'submit'
- pressed : toggle ? false : null,
- listeners : {}
+ //Roo.log(['enter',dom]);
+ var el = Roo.fly(dom);
+ if (this.currentEl) {
+ //Roo.log(dom);
+ //Roo.log(this.currentEl);
+ //Roo.log(this.currentEl.contains(dom));
+ if (this.currentEl == el) {
+ return;
}
- a.listeners[toggle ? 'toggle' : 'click'] = function() {
- handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
+ if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
+ return;
}
- children.push(a);
- return a;
- }
+
+ }
- var style = {
- xtype: 'Button',
- size : 'sm',
- xns: Roo.bootstrap,
- glyphicon : 'font',
- //html : 'submit'
- menu : {
- xtype: 'Menu',
- xns: Roo.bootstrap,
- items: []
- }
- };
- Roo.each(this.formats, function(f) {
- style.menu.items.push({
- xtype :'MenuItem',
- xns: Roo.bootstrap,
- html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
- tagname : f,
- listeners : {
- click : function()
- {
- editorcore.insertTag(this.tagname);
- editor.focus();
- }
- }
-
- });
- });
- children.push(style);
-
-
- btn('bold',false,true);
- btn('italic',false,true);
- btn('align-left', 'justifyleft',true);
- btn('align-center', 'justifycenter',true);
- btn('align-right' , 'justifyright',true);
- btn('link', false, false, function(btn) {
- //Roo.log("create link?");
- var url = prompt(this.createLinkText, this.defaultLinkValue);
- if(url && url != 'http:/'+'/'){
- this.editorcore.relayCmd('createlink', url);
+ if (this.currentTip.el) {
+ this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
+ }
+ //Roo.log(ev);
+ var bindEl = el;
+
+ // you can not look for children, as if el is the body.. then everythign is the child..
+ if (!el.attr('tooltip')) { //
+ if (!el.select("[tooltip]").elements.length) {
+ return;
}
- }),
- btn('list','insertunorderedlist',true);
- btn('pencil', false,true, function(btn){
- Roo.log(this);
-
- this.toggleSourceEdit(btn.pressed);
- });
- /*
- var cog = {
- xtype: 'Button',
- size : 'sm',
- xns: Roo.bootstrap,
- glyphicon : 'cog',
- //html : 'submit'
- menu : {
- xtype: 'Menu',
- xns: Roo.bootstrap,
- items: []
- }
- };
+ // is the mouse over this child...?
+ bindEl = el.select("[tooltip]").first();
+ var xy = ev.getXY();
+ if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
+ //Roo.log("not in region.");
+ return;
+ }
+ //Roo.log("child element over..");
+
+ }
+ this.currentEl = bindEl;
+ this.currentTip.bind(bindEl);
+ this.currentRegion = Roo.lib.Region.getRegion(dom);
+ this.currentTip.enter();
- cog.menu.items.push({
- xtype :'MenuItem',
- xns: Roo.bootstrap,
- html : Clean styles,
- tagname : f,
- listeners : {
- click : function()
+ },
+ leave : function(ev)
+ {
+ var dom = ev.getTarget();
+ //Roo.log(['leave',dom]);
+ if (!this.currentEl) {
+ return;
+ }
+
+
+ if (dom != this.currentEl.dom) {
+ return;
+ }
+ var xy = ev.getXY();
+ if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
+ return;
+ }
+ // only activate leave if mouse cursor is outside... bounding box..
+
+
+
+
+ if (this.currentTip) {
+ this.currentTip.leave();
+ }
+ //Roo.log('clear currentEl');
+ this.currentEl = false;
+
+
+ },
+ alignment : {
+ 'left' : ['r-l', [-2,0], 'right'],
+ 'right' : ['l-r', [2,0], 'left'],
+ 'bottom' : ['t-b', [0,2], 'top'],
+ 'top' : [ 'b-t', [0,-2], 'bottom']
+ }
+
+});
+
+
+Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
+
+
+ bindEl : false,
+
+ delay : null, // can be { show : 300 , hide: 500}
+
+ timeout : null,
+
+ hoverState : null, //???
+
+ placement : 'bottom',
+
+ getAutoCreate : function(){
+
+ var cfg = {
+ cls : 'tooltip',
+ role : 'tooltip',
+ cn : [
{
- editorcore.insertTag(this.tagname);
- editor.focus();
+ cls : 'tooltip-arrow'
+ },
+ {
+ cls : 'tooltip-inner'
}
- }
-
- });
- */
-
-
- this.xtype = 'NavSimplebar';
+ ]
+ };
- for(var i=0;i< children.length;i++) {
-
- this.buttons.add(this.addxtypeChild(children[i]));
-
+ return cfg;
+ },
+ bind : function(el)
+ {
+ this.bindEl = el;
+ },
+
+
+ enter : function () {
+
+ if (this.timeout != null) {
+ clearTimeout(this.timeout);
}
- editor.on('editorevent', this.updateToolbar, this);
+ this.hoverState = 'in';
+ //Roo.log("enter - show");
+ if (!this.delay || !this.delay.show) {
+ this.show();
+ return;
+ }
+ var _t = this;
+ this.timeout = setTimeout(function () {
+ if (_t.hoverState == 'in') {
+ _t.show();
+ }
+ }, this.delay.show);
},
- onBtnClick : function(id)
+ leave : function()
{
- this.editorcore.relayCmd(id);
- this.editorcore.focus();
- },
+ clearTimeout(this.timeout);
- /**
- * Protected method that will not generally be called directly. It triggers
- * a toolbar update by reading the markup state of the current selection in the editor.
- */
- updateToolbar: function(){
-
- if(!this.editorcore.activated){
- this.editor.onFirstFocus(); // is this neeed?
+ this.hoverState = 'out';
+ if (!this.delay || !this.delay.hide) {
+ this.hide();
return;
}
-
- var btns = this.buttons;
- var doc = this.editorcore.doc;
- btns.get('bold').setActive(doc.queryCommandState('bold'));
- btns.get('italic').setActive(doc.queryCommandState('italic'));
- //btns.get('underline').setActive(doc.queryCommandState('underline'));
+
+ var _t = this;
+ this.timeout = setTimeout(function () {
+ //Roo.log("leave - timeout");
+
+ if (_t.hoverState == 'out') {
+ _t.hide();
+ Roo.bootstrap.Tooltip.currentEl = false;
+ }
+ }, delay);
+ },
+
+ show : function ()
+ {
+ if (!this.el) {
+ this.render(document.body);
+ }
+ // set content.
+ //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
- btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
- btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
- btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
+ var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
- //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
- btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
- /*
+ this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
- var ans = this.editorcore.getAllAncestors();
- if (this.formatCombo) {
-
+ this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
+
+ var placement = typeof this.placement == 'function' ?
+ this.placement.call(this, this.el, on_el) :
+ this.placement;
- var store = this.formatCombo.store;
- this.formatCombo.setValue("");
- for (var i =0; i < ans.length;i++) {
- if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
- // select it..
- this.formatCombo.setValue(ans[i].tagName.toLowerCase());
- break;
- }
- }
+ var autoToken = /\s?auto?\s?/i;
+ var autoPlace = autoToken.test(placement);
+ if (autoPlace) {
+ placement = placement.replace(autoToken, '') || 'top';
}
+ //this.el.detach()
+ //this.el.setXY([0,0]);
+ this.el.show();
+ //this.el.dom.style.display='block';
+
+ //this.el.appendTo(on_el);
+ var p = this.getPosition();
+ var box = this.el.getBox();
- // hides menus... - so this cant be on a menu...
- Roo.bootstrap.MenuMgr.hideAll();
- */
- Roo.bootstrap.MenuMgr.hideAll();
- //this.editorsyncValue();
- },
- onFirstFocus: function() {
- this.buttons.each(function(item){
- item.enable();
- });
- },
- toggleSourceEdit : function(sourceEditMode){
+ if (autoPlace) {
+ // fixme..
+ }
-
- if(sourceEditMode){
- Roo.log("disabling buttons");
- this.buttons.each( function(item){
- if(item.cmd != 'pencil'){
- item.disable();
- }
- });
-
- }else{
- Roo.log("enabling buttons");
- if(this.editorcore.initialized){
- this.buttons.each( function(item){
- item.enable();
- });
+ var align = Roo.bootstrap.Tooltip.alignment[placement];
+
+ var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
+
+ if(placement == 'top' || placement == 'bottom'){
+ if(xy[0] < 0){
+ placement = 'right';
}
+ if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
+ placement = 'left';
+ }
}
- Roo.log("calling toggole on editor");
- // tell the editor that it's been pressed..
- this.editor.toggleSourceEdit(sourceEditMode);
-
+
+ align = Roo.bootstrap.Tooltip.alignment[placement];
+
+ this.el.alignTo(this.bindEl, align[0],align[1]);
+ //var arrow = this.el.select('.arrow',true).first();
+ //arrow.set(align[2],
+
+ this.el.addClass(placement);
+
+ this.el.addClass('in fade');
+
+ this.hoverState = null;
+
+ if (this.el.hasClass('fade')) {
+ // fade it?
+ }
+
+ },
+ hide : function()
+ {
+
+ if (!this.el) {
+ return;
+ }
+ //this.el.setXY([0,0]);
+ this.el.removeClass('in');
+ //this.el.hide();
+
}
+
});
+
-
-
-
-
-/**
- * @class Roo.bootstrap.Table.AbstractSelectionModel
- * @extends Roo.util.Observable
- * Abstract base class for grid SelectionModels. It provides the interface that should be
- * implemented by descendant classes. This class should not be directly instantiated.
- * @constructor
+ /*
+ * - LGPL
+ *
+ * Location Picker
+ *
*/
-Roo.bootstrap.Table.AbstractSelectionModel = function(){
- this.locked = false;
- Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
-};
-
-
-Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
- /** @ignore Called by the grid automatically. Do not call directly. */
- init : function(grid){
- this.grid = grid;
- this.initEvents();
- },
-
- /**
- * Locks the selections.
- */
- lock : function(){
- this.locked = true;
- },
-
- /**
- * Unlocks the selections.
- */
- unlock : function(){
- this.locked = false;
- },
- /**
- * Returns true if the selections are locked.
- * @return {Boolean}
- */
- isLocked : function(){
- return this.locked;
- }
-});
/**
- * @extends Roo.bootstrap.Table.AbstractSelectionModel
- * @class Roo.bootstrap.Table.RowSelectionModel
- * The default SelectionModel used by {@link Roo.bootstrap.Table}.
- * It supports multiple selections and keyboard selection/navigation.
+ * @class Roo.bootstrap.LocationPicker
+ * @extends Roo.bootstrap.Component
+ * Bootstrap LocationPicker class
+ * @cfg {Number} latitude Position when init default 0
+ * @cfg {Number} longitude Position when init default 0
+ * @cfg {Number} zoom default 15
+ * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
+ * @cfg {Boolean} mapTypeControl default false
+ * @cfg {Boolean} disableDoubleClickZoom default false
+ * @cfg {Boolean} scrollwheel default true
+ * @cfg {Boolean} streetViewControl default false
+ * @cfg {Number} radius default 0
+ * @cfg {String} locationName
+ * @cfg {Boolean} draggable default true
+ * @cfg {Boolean} enableAutocomplete default false
+ * @cfg {Boolean} enableReverseGeocode default true
+ * @cfg {String} markerTitle
+ *
* @constructor
- * @param {Object} config
+ * Create a new LocationPicker
+ * @param {Object} config The config object
*/
-Roo.bootstrap.Table.RowSelectionModel = function(config){
- Roo.apply(this, config);
- this.selections = new Roo.util.MixedCollection(false, function(o){
- return o.id;
- });
-
- this.last = false;
- this.lastActive = false;
+Roo.bootstrap.LocationPicker = function(config){
+
+ Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
+
this.addEvents({
/**
- * @event selectionchange
- * Fires when the selection changes
- * @param {SelectionModel} this
- */
- "selectionchange" : true,
+ * @event initial
+ * Fires when the picker initialized.
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Google Location} location
+ */
+ initial : true,
/**
- * @event afterselectionchange
- * Fires after the selection changes (eg. by key press or clicking)
- * @param {SelectionModel} this
- */
- "afterselectionchange" : true,
+ * @event positionchanged
+ * Fires when the picker position changed.
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Google Location} location
+ */
+ positionchanged : true,
/**
- * @event beforerowselect
- * Fires when a row is selected being selected, return false to cancel.
- * @param {SelectionModel} this
- * @param {Number} rowIndex The selected index
- * @param {Boolean} keepExisting False if other selections will be cleared
- */
- "beforerowselect" : true,
+ * @event resize
+ * Fires when the map resize.
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ resize : true,
/**
- * @event rowselect
- * Fires when a row is selected.
- * @param {SelectionModel} this
- * @param {Number} rowIndex The selected index
- * @param {Roo.data.Record} r The record
- */
- "rowselect" : true,
+ * @event show
+ * Fires when the map show.
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ show : true,
/**
- * @event rowdeselect
- * Fires when a row is deselected.
- * @param {SelectionModel} this
- * @param {Number} rowIndex The selected index
- */
- "rowdeselect" : true
+ * @event hide
+ * Fires when the map hide.
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ hide : true,
+ /**
+ * @event mapClick
+ * Fires when click the map.
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Map event} e
+ */
+ mapClick : true,
+ /**
+ * @event mapRightClick
+ * Fires when right click the map.
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Map event} e
+ */
+ mapRightClick : true,
+ /**
+ * @event markerClick
+ * Fires when click the marker.
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Map event} e
+ */
+ markerClick : true,
+ /**
+ * @event markerRightClick
+ * Fires when right click the marker.
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Map event} e
+ */
+ markerRightClick : true,
+ /**
+ * @event OverlayViewDraw
+ * Fires when OverlayView Draw
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ OverlayViewDraw : true,
+ /**
+ * @event OverlayViewOnAdd
+ * Fires when OverlayView Draw
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ OverlayViewOnAdd : true,
+ /**
+ * @event OverlayViewOnRemove
+ * Fires when OverlayView Draw
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ OverlayViewOnRemove : true,
+ /**
+ * @event OverlayViewShow
+ * Fires when OverlayView Draw
+ * @param {Roo.bootstrap.LocationPicker} this
+ * @param {Pixel} cpx
+ */
+ OverlayViewShow : true,
+ /**
+ * @event OverlayViewHide
+ * Fires when OverlayView Draw
+ * @param {Roo.bootstrap.LocationPicker} this
+ */
+ OverlayViewHide : true
});
- Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
- this.locked = false;
+
};
-Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
- /**
- * @cfg {Boolean} singleSelect
- * True to allow selection of only one row at a time (defaults to false)
- */
- singleSelect : false,
-
- // private
- initEvents : function(){
+Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
+
+ gMapContext: false,
+
+ latitude: 0,
+ longitude: 0,
+ zoom: 15,
+ mapTypeId: false,
+ mapTypeControl: false,
+ disableDoubleClickZoom: false,
+ scrollwheel: true,
+ streetViewControl: false,
+ radius: 0,
+ locationName: '',
+ draggable: true,
+ enableAutocomplete: false,
+ enableReverseGeocode: true,
+ markerTitle: '',
+
+ getAutoCreate: function()
+ {
- if(!this.grid.enableDragDrop && !this.grid.enableDrag){
- this.grid.on("mousedown", this.handleMouseDown, this);
- }else{ // allow click to work like normal
- this.grid.on("rowclick", this.handleDragableRowClick, this);
+ var cfg = {
+ tag: 'div',
+ cls: 'roo-location-picker'
+ };
+
+ return cfg
+ },
+
+ initEvents: function(ct, position)
+ {
+ if(!this.el.getWidth() || this.isApplied()){
+ return;
}
-
- this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
- "up" : function(e){
- if(!e.shiftKey){
- this.selectPrevious(e.shiftKey);
- }else if(this.last !== false && this.lastActive !== false){
- var last = this.last;
- this.selectRange(this.last, this.lastActive-1);
- this.grid.getView().focusRow(this.lastActive);
- if(last !== false){
- this.last = last;
- }
- }else{
- this.selectFirstRow();
- }
- this.fireEvent("afterselectionchange", this);
- },
- "down" : function(e){
- if(!e.shiftKey){
- this.selectNext(e.shiftKey);
- }else if(this.last !== false && this.lastActive !== false){
- var last = this.last;
- this.selectRange(this.last, this.lastActive+1);
- this.grid.getView().focusRow(this.lastActive);
- if(last !== false){
- this.last = last;
- }
- }else{
- this.selectFirstRow();
- }
- this.fireEvent("afterselectionchange", this);
- },
- scope: this
+
+ this.el.setVisibilityMode(Roo.Element.DISPLAY);
+
+ this.initial();
+ },
+
+ initial: function()
+ {
+ if(!this.mapTypeId){
+ this.mapTypeId = google.maps.MapTypeId.ROADMAP;
+ }
+
+ this.gMapContext = this.GMapContext();
+
+ this.initOverlayView();
+
+ this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
+
+ var _this = this;
+
+ google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
+ _this.setPosition(_this.gMapContext.marker.position);
+ });
+
+ google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
+ _this.fireEvent('mapClick', this, event);
+
+ });
+
+ google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
+ _this.fireEvent('mapRightClick', this, event);
+
+ });
+
+ google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
+ _this.fireEvent('markerClick', this, event);
+
});
- var view = this.grid.view;
- view.on("refresh", this.onRefresh, this);
- view.on("rowupdated", this.onRowUpdated, this);
- view.on("rowremoved", this.onRemove, this);
+ google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
+ _this.fireEvent('markerRightClick', this, event);
+
+ });
+
+ this.setPosition(this.gMapContext.location);
+
+ this.fireEvent('initial', this, this.gMapContext.location);
},
-
- // private
- onRefresh : function(){
- var ds = this.grid.dataSource, i, v = this.grid.view;
- var s = this.selections;
- s.each(function(r){
- if((i = ds.indexOfId(r.id)) != -1){
- v.onRowSelect(i);
- }else{
- s.remove(r);
+
+ initOverlayView: function()
+ {
+ var _this = this;
+
+ Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
+
+ draw: function()
+ {
+ _this.fireEvent('OverlayViewDraw', _this);
+ },
+
+ onAdd: function()
+ {
+ _this.fireEvent('OverlayViewOnAdd', _this);
+ },
+
+ onRemove: function()
+ {
+ _this.fireEvent('OverlayViewOnRemove', _this);
+ },
+
+ show: function(cpx)
+ {
+ _this.fireEvent('OverlayViewShow', _this, cpx);
+ },
+
+ hide: function()
+ {
+ _this.fireEvent('OverlayViewHide', _this);
}
+
});
},
-
- // private
- onRemove : function(v, index, r){
- this.selections.remove(r);
- },
-
- // private
- onRowUpdated : function(v, index, r){
- if(this.isSelected(r)){
- v.onRowSelect(index);
- }
- },
-
- /**
- * Select records.
- * @param {Array} records The records to select
- * @param {Boolean} keepExisting (optional) True to keep existing selections
- */
- selectRecords : function(records, keepExisting){
- if(!keepExisting){
- this.clearSelections();
- }
- var ds = this.grid.dataSource;
- for(var i = 0, len = records.length; i < len; i++){
- this.selectRow(ds.indexOf(records[i]), true);
- }
+
+ fromLatLngToContainerPixel: function(event)
+ {
+ return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
},
-
- /**
- * Gets the number of selected rows.
- * @return {Number}
- */
- getCount : function(){
- return this.selections.length;
+
+ isApplied: function()
+ {
+ return this.getGmapContext() == false ? false : true;
},
-
- /**
- * Selects the first row in the grid.
- */
- selectFirstRow : function(){
- this.selectRow(0);
+
+ getGmapContext: function()
+ {
+ return this.gMapContext
},
-
- /**
- * Select the last row.
- * @param {Boolean} keepExisting (optional) True to keep existing selections
- */
- selectLastRow : function(keepExisting){
- this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
+
+ GMapContext: function()
+ {
+ var position = new google.maps.LatLng(this.latitude, this.longitude);
+
+ var _map = new google.maps.Map(this.el.dom, {
+ center: position,
+ zoom: this.zoom,
+ mapTypeId: this.mapTypeId,
+ mapTypeControl: this.mapTypeControl,
+ disableDoubleClickZoom: this.disableDoubleClickZoom,
+ scrollwheel: this.scrollwheel,
+ streetViewControl: this.streetViewControl,
+ locationName: this.locationName,
+ draggable: this.draggable,
+ enableAutocomplete: this.enableAutocomplete,
+ enableReverseGeocode: this.enableReverseGeocode
+ });
+
+ var _marker = new google.maps.Marker({
+ position: position,
+ map: _map,
+ title: this.markerTitle,
+ draggable: this.draggable
+ });
+
+ return {
+ map: _map,
+ marker: _marker,
+ circle: null,
+ location: position,
+ radius: this.radius,
+ locationName: this.locationName,
+ addressComponents: {
+ formatted_address: null,
+ addressLine1: null,
+ addressLine2: null,
+ streetName: null,
+ streetNumber: null,
+ city: null,
+ district: null,
+ state: null,
+ stateOrProvince: null
+ },
+ settings: this,
+ domContainer: this.el.dom,
+ geodecoder: new google.maps.Geocoder()
+ };
},
-
- /**
- * Selects the row immediately following the last selected row.
- * @param {Boolean} keepExisting (optional) True to keep existing selections
- */
- selectNext : function(keepExisting){
- if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
- this.selectRow(this.last+1, keepExisting);
- this.grid.getView().focusRow(this.last);
+
+ drawCircle: function(center, radius, options)
+ {
+ if (this.gMapContext.circle != null) {
+ this.gMapContext.circle.setMap(null);
}
- },
-
- /**
- * Selects the row that precedes the last selected row.
- * @param {Boolean} keepExisting (optional) True to keep existing selections
- */
- selectPrevious : function(keepExisting){
- if(this.last){
- this.selectRow(this.last-1, keepExisting);
- this.grid.getView().focusRow(this.last);
+ if (radius > 0) {
+ radius *= 1;
+ options = Roo.apply({}, options, {
+ strokeColor: "#0000FF",
+ strokeOpacity: .35,
+ strokeWeight: 2,
+ fillColor: "#0000FF",
+ fillOpacity: .2
+ });
+
+ options.map = this.gMapContext.map;
+ options.radius = radius;
+ options.center = center;
+ this.gMapContext.circle = new google.maps.Circle(options);
+ return this.gMapContext.circle;
}
+
+ return null;
},
-
- /**
- * Returns the selected records
- * @return {Array} Array of selected records
- */
- getSelections : function(){
- return [].concat(this.selections.items);
- },
-
- /**
- * Returns the first selected record.
- * @return {Record}
- */
- getSelected : function(){
- return this.selections.itemAt(0);
- },
-
-
- /**
- * Clears all selections.
- */
- clearSelections : function(fast){
- if(this.locked) return;
- if(fast !== true){
- var ds = this.grid.dataSource;
- var s = this.selections;
- s.each(function(r){
- this.deselectRow(ds.indexOfId(r.id));
- }, this);
- s.clear();
- }else{
- this.selections.clear();
+
+ setPosition: function(location)
+ {
+ this.gMapContext.location = location;
+ this.gMapContext.marker.setPosition(location);
+ this.gMapContext.map.panTo(location);
+ this.drawCircle(location, this.gMapContext.radius, {});
+
+ var _this = this;
+
+ if (this.gMapContext.settings.enableReverseGeocode) {
+ this.gMapContext.geodecoder.geocode({
+ latLng: this.gMapContext.location
+ }, function(results, status) {
+
+ if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
+ _this.gMapContext.locationName = results[0].formatted_address;
+ _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
+
+ _this.fireEvent('positionchanged', this, location);
+ }
+ });
+
+ return;
}
- this.last = false;
+
+ this.fireEvent('positionchanged', this, location);
},
-
-
- /**
- * Selects all rows.
- */
- selectAll : function(){
- if(this.locked) return;
- this.selections.clear();
- for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
- this.selectRow(i, true);
- }
+
+ resize: function()
+ {
+ google.maps.event.trigger(this.gMapContext.map, "resize");
+
+ this.gMapContext.map.setCenter(this.gMapContext.marker.position);
+
+ this.fireEvent('resize', this);
},
-
- /**
- * Returns True if there is a selection.
- * @return {Boolean}
- */
- hasSelection : function(){
- return this.selections.length > 0;
+
+ setPositionByLatLng: function(latitude, longitude)
+ {
+ this.setPosition(new google.maps.LatLng(latitude, longitude));
},
-
- /**
- * Returns True if the specified row is selected.
- * @param {Number/Record} record The record or index of the record to check
- * @return {Boolean}
- */
- isSelected : function(index){
- var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
- return (r && this.selections.key(r.id) ? true : false);
+
+ getCurrentPosition: function()
+ {
+ return {
+ latitude: this.gMapContext.location.lat(),
+ longitude: this.gMapContext.location.lng()
+ };
},
-
- /**
- * Returns True if the specified record id is selected.
- * @param {String} id The id of record to check
- * @return {Boolean}
- */
- isIdSelected : function(id){
- return (this.selections.key(id) ? true : false);
+
+ getAddressName: function()
+ {
+ return this.gMapContext.locationName;
},
-
- // private
- handleMouseDown : function(e, t){
- var view = this.grid.getView(), rowIndex;
- if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
- return;
- };
- if(e.shiftKey && this.last !== false){
- var last = this.last;
- this.selectRange(last, rowIndex, e.ctrlKey);
- this.last = last; // reset the last
- view.focusRow(rowIndex);
- }else{
- var isSelected = this.isSelected(rowIndex);
- if(e.button !== 0 && isSelected){
- view.focusRow(rowIndex);
- }else if(e.ctrlKey && isSelected){
- this.deselectRow(rowIndex);
- }else if(!isSelected){
- this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
- view.focusRow(rowIndex);
+
+ getAddressComponents: function()
+ {
+ return this.gMapContext.addressComponents;
+ },
+
+ address_component_from_google_geocode: function(address_components)
+ {
+ var result = {};
+
+ for (var i = 0; i < address_components.length; i++) {
+ var component = address_components[i];
+ if (component.types.indexOf("postal_code") >= 0) {
+ result.postalCode = component.short_name;
+ } else if (component.types.indexOf("street_number") >= 0) {
+ result.streetNumber = component.short_name;
+ } else if (component.types.indexOf("route") >= 0) {
+ result.streetName = component.short_name;
+ } else if (component.types.indexOf("neighborhood") >= 0) {
+ result.city = component.short_name;
+ } else if (component.types.indexOf("locality") >= 0) {
+ result.city = component.short_name;
+ } else if (component.types.indexOf("sublocality") >= 0) {
+ result.district = component.short_name;
+ } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
+ result.stateOrProvince = component.short_name;
+ } else if (component.types.indexOf("country") >= 0) {
+ result.country = component.short_name;
}
}
- this.fireEvent("afterselectionchange", this);
+
+ result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
+ result.addressLine2 = "";
+ return result;
},
- // private
- handleDragableRowClick : function(grid, rowIndex, e)
+
+ setZoomLevel: function(zoom)
{
- if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
- this.selectRow(rowIndex, false);
- grid.view.focusRow(rowIndex);
- this.fireEvent("afterselectionchange", this);
- }
+ this.gMapContext.map.setZoom(zoom);
},
- /**
- * Selects multiple rows.
- * @param {Array} rows Array of the indexes of the row to select
- * @param {Boolean} keepExisting (optional) True to keep existing selections
- */
- selectRows : function(rows, keepExisting){
- if(!keepExisting){
- this.clearSelections();
- }
- for(var i = 0, len = rows.length; i < len; i++){
- this.selectRow(rows[i], true);
+ show: function()
+ {
+ if(!this.el){
+ return;
}
+
+ this.el.show();
+
+ this.resize();
+
+ this.fireEvent('show', this);
},
-
- /**
- * Selects a range of rows. All rows in between startRow and endRow are also selected.
- * @param {Number} startRow The index of the first row in the range
- * @param {Number} endRow The index of the last row in the range
- * @param {Boolean} keepExisting (optional) True to retain existing selections
- */
- selectRange : function(startRow, endRow, keepExisting){
- if(this.locked) return;
- if(!keepExisting){
- this.clearSelections();
+
+ hide: function()
+ {
+ if(!this.el){
+ return;
}
- if(startRow <= endRow){
- for(var i = startRow; i <= endRow; i++){
- this.selectRow(i, true);
- }
- }else{
- for(var i = startRow; i >= endRow; i--){
- this.selectRow(i, true);
- }
+
+ this.el.hide();
+
+ this.fireEvent('hide', this);
+ }
+
+});
+
+Roo.apply(Roo.bootstrap.LocationPicker, {
+
+ OverlayView : function(map, options)
+ {
+ options = options || {};
+
+ this.setMap(map);
+ }
+
+
+});/*
+ * - LGPL
+ *
+ * Alert
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.Alert
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Alert class
+ * @cfg {String} title The title of alert
+ * @cfg {String} html The content of alert
+ * @cfg {String} weight ( success | info | warning | danger )
+ * @cfg {String} faicon font-awesomeicon
+ *
+ * @constructor
+ * Create a new alert
+ * @param {Object} config The config object
+ */
+
+
+Roo.bootstrap.Alert = function(config){
+ Roo.bootstrap.Alert.superclass.constructor.call(this, config);
+
+};
+
+Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
+
+ title: '',
+ html: '',
+ weight: false,
+ faicon: false,
+
+ getAutoCreate : function()
+ {
+
+ var cfg = {
+ tag : 'div',
+ cls : 'alert',
+ cn : [
+ {
+ tag : 'i',
+ cls : 'roo-alert-icon'
+
+ },
+ {
+ tag : 'b',
+ cls : 'roo-alert-title',
+ html : this.title
+ },
+ {
+ tag : 'span',
+ cls : 'roo-alert-text',
+ html : this.html
+ }
+ ]
+ };
+
+ if(this.faicon){
+ cfg.cn[0].cls += ' fa ' + this.faicon;
}
- },
-
- /**
- * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
- * @param {Number} startRow The index of the first row in the range
- * @param {Number} endRow The index of the last row in the range
- */
- deselectRange : function(startRow, endRow, preventViewNotify){
- if(this.locked) return;
- for(var i = startRow; i <= endRow; i++){
- this.deselectRow(i, preventViewNotify);
+
+ if(this.weight){
+ cfg.cls += ' alert-' + this.weight;
}
+
+ return cfg;
},
-
- /**
- * Selects a row.
- * @param {Number} row The index of the row to select
- * @param {Boolean} keepExisting (optional) True to keep existing selections
- */
- selectRow : function(index, keepExisting, preventViewNotify){
- if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
- if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
- if(!keepExisting || this.singleSelect){
- this.clearSelections();
- }
- var r = this.grid.dataSource.getAt(index);
- this.selections.add(r);
- this.last = this.lastActive = index;
- if(!preventViewNotify){
- this.grid.getView().onRowSelect(index);
- }
- this.fireEvent("rowselect", this, index, r);
- this.fireEvent("selectionchange", this);
- }
+
+ initEvents: function()
+ {
+ this.el.setVisibilityMode(Roo.Element.DISPLAY);
},
-
- /**
- * Deselects a row.
- * @param {Number} row The index of the row to deselect
- */
- deselectRow : function(index, preventViewNotify){
- if(this.locked) return;
- if(this.last == index){
- this.last = false;
- }
- if(this.lastActive == index){
- this.lastActive = false;
- }
- var r = this.grid.dataSource.getAt(index);
- this.selections.remove(r);
- if(!preventViewNotify){
- this.grid.getView().onRowDeselect(index);
+
+ setTitle : function(str)
+ {
+ this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
+ },
+
+ setText : function(str)
+ {
+ this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
+ },
+
+ setWeight : function(weight)
+ {
+ if(this.weight){
+ this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
}
- this.fireEvent("rowdeselect", this, index);
- this.fireEvent("selectionchange", this);
+
+ this.weight = weight;
+
+ this.el.select('.alert',true).first().addClass('alert-' + this.weight);
},
-
- // private
- restoreLast : function(){
- if(this._last){
- this.last = this._last;
+
+ setIcon : function(icon)
+ {
+ if(this.faicon){
+ this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
}
+
+ this.faicon = icon
+
+ this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
},
-
- // private
- acceptsNav : function(row, col, cm){
- return !cm.isHidden(col) && cm.isCellEditable(col, row);
+
+ hide: function()
+ {
+ this.el.hide();
},
-
- // private
- onEditorKey : function(field, e){
- var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
- if(k == e.TAB){
- e.stopEvent();
- ed.completeEdit();
- if(e.shiftKey){
- newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
- }else{
- newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
- }
- }else if(k == e.ENTER && !e.ctrlKey){
- e.stopEvent();
- ed.completeEdit();
- if(e.shiftKey){
- newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
- }else{
- newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
- }
- }else if(k == e.ESC){
- ed.cancelEdit();
- }
- if(newCell){
- g.startEditing(newCell[0], newCell[1]);
- }
+
+ show: function()
+ {
+ this.el.show();
}
-});/*
- * Based on:
- * Ext JS Library 1.1.1
- * Copyright(c) 2006-2007, Ext JS, LLC.
- *
- * Originally Released Under LGPL - original licence link has changed is not relivant.
- *
- * Fork - LGPL
- * <script type="text/javascript">
- */
+
+});
+
+/*
+* Licence: LGPL
+*/
+
/**
- * @class Roo.bootstrap.PagingToolbar
- * @extends Roo.Row
- * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
+ * @class Roo.bootstrap.UploadCropbox
+ * @extends Roo.bootstrap.Component
+ * Bootstrap UploadCropbox class
+ * @cfg {String} emptyText show when image has been loaded
+ * @cfg {String} rotateNotify show when image too small to rotate
+ * @cfg {Number} errorTimeout default 3000
+ * @cfg {Number} minWidth default 300
+ * @cfg {Number} minHeight default 300
+ * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
+ * @cfg {Boolean} isDocument (true|false) default false
+ * @cfg {String} url action url
+ * @cfg {String} paramName default 'imageUpload'
+ * @cfg {String} method default POST
+ *
* @constructor
- * Create a new PagingToolbar
+ * Create a new UploadCropbox
* @param {Object} config The config object
*/
-Roo.bootstrap.PagingToolbar = function(config)
-{
- // old args format still supported... - xtype is prefered..
- // created from xtype...
- var ds = config.dataSource;
- this.toolbarItems = [];
- if (config.items) {
- this.toolbarItems = config.items;
-// config.items = [];
- }
-
- Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
- this.ds = ds;
- this.cursor = 0;
- if (ds) {
- this.bind(ds);
- }
-
- this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
-
-};
-Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
- /**
- * @cfg {Roo.data.Store} dataSource
- * The underlying data store providing the paged data
- */
- /**
- * @cfg {String/HTMLElement/Element} container
- * container The id or element that will contain the toolbar
- */
- /**
- * @cfg {Boolean} displayInfo
- * True to display the displayMsg (defaults to false)
- */
- /**
- * @cfg {Number} pageSize
- * The number of records to display per page (defaults to 20)
- */
- pageSize: 20,
- /**
- * @cfg {String} displayMsg
- * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
- */
- displayMsg : 'Displaying {0} - {1} of {2}',
- /**
- * @cfg {String} emptyMsg
- * The message to display when no records are found (defaults to "No data to display")
- */
- emptyMsg : 'No data to display',
- /**
- * Customizable piece of the default paging text (defaults to "Page")
- * @type String
- */
- beforePageText : "Page",
- /**
- * Customizable piece of the default paging text (defaults to "of %0")
- * @type String
- */
- afterPageText : "of {0}",
- /**
- * Customizable piece of the default paging text (defaults to "First Page")
- * @type String
- */
- firstText : "First Page",
- /**
- * Customizable piece of the default paging text (defaults to "Previous Page")
- * @type String
- */
- prevText : "Previous Page",
- /**
- * Customizable piece of the default paging text (defaults to "Next Page")
- * @type String
- */
- nextText : "Next Page",
- /**
- * Customizable piece of the default paging text (defaults to "Last Page")
- * @type String
- */
- lastText : "Last Page",
- /**
- * Customizable piece of the default paging text (defaults to "Refresh")
- * @type String
- */
- refreshText : "Refresh",
+Roo.bootstrap.UploadCropbox = function(config){
+ Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
+
+ this.addEvents({
+ /**
+ * @event beforeselectfile
+ * Fire before select file
+ * @param {Roo.bootstrap.UploadCropbox} this
+ */
+ "beforeselectfile" : true,
+ /**
+ * @event initial
+ * Fire after initEvent
+ * @param {Roo.bootstrap.UploadCropbox} this
+ */
+ "initial" : true,
+ /**
+ * @event crop
+ * Fire after initEvent
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {String} data
+ */
+ "crop" : true,
+ /**
+ * @event prepare
+ * Fire when preparing the file data
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {Object} file
+ */
+ "prepare" : true,
+ /**
+ * @event exception
+ * Fire when get exception
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {XMLHttpRequest} xhr
+ */
+ "exception" : true,
+ /**
+ * @event beforeloadcanvas
+ * Fire before load the canvas
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {String} src
+ */
+ "beforeloadcanvas" : true,
+ /**
+ * @event trash
+ * Fire when trash image
+ * @param {Roo.bootstrap.UploadCropbox} this
+ */
+ "trash" : true,
+ /**
+ * @event download
+ * Fire when download the image
+ * @param {Roo.bootstrap.UploadCropbox} this
+ */
+ "download" : true,
+ /**
+ * @event footerbuttonclick
+ * Fire when footerbuttonclick
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {String} type
+ */
+ "footerbuttonclick" : true,
+ /**
+ * @event resize
+ * Fire when resize
+ * @param {Roo.bootstrap.UploadCropbox} this
+ */
+ "resize" : true,
+ /**
+ * @event rotate
+ * Fire when rotate the image
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {String} pos
+ */
+ "rotate" : true,
+ /**
+ * @event inspect
+ * Fire when inspect the file
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {Object} file
+ */
+ "inspect" : true,
+ /**
+ * @event upload
+ * Fire when xhr upload the file
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {Object} data
+ */
+ "upload" : true,
+ /**
+ * @event arrange
+ * Fire when arrange the file data
+ * @param {Roo.bootstrap.UploadCropbox} this
+ * @param {Object} formData
+ */
+ "arrange" : true
+ });
+
+ this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
+};
+Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
+
+ emptyText : 'Click to upload image',
+ rotateNotify : 'Image is too small to rotate',
+ errorTimeout : 3000,
+ scale : 0,
+ baseScale : 1,
+ rotate : 0,
+ dragable : false,
+ pinching : false,
+ mouseX : 0,
+ mouseY : 0,
+ cropData : false,
+ minWidth : 300,
+ minHeight : 300,
+ file : false,
+ exif : {},
+ baseRotate : 1,
+ cropType : 'image/jpeg',
buttons : false,
- // private
- onRender : function(ct, position)
+ canvasLoaded : false,
+ isDocument : false,
+ method : 'POST',
+ paramName : 'imageUpload',
+
+ getAutoCreate : function()
{
- Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
- this.navgroup.parentId = this.id;
- this.navgroup.onRender(this.el, null);
- // add the buttons to the navgroup
+ var cfg = {
+ tag : 'div',
+ cls : 'roo-upload-cropbox',
+ cn : [
+ {
+ tag : 'input',
+ cls : 'roo-upload-cropbox-selector',
+ type : 'file'
+ },
+ {
+ tag : 'div',
+ cls : 'roo-upload-cropbox-body',
+ style : 'cursor:pointer',
+ cn : [
+ {
+ tag : 'div',
+ cls : 'roo-upload-cropbox-preview'
+ },
+ {
+ tag : 'div',
+ cls : 'roo-upload-cropbox-thumb'
+ },
+ {
+ tag : 'div',
+ cls : 'roo-upload-cropbox-empty-notify',
+ html : this.emptyText
+ },
+ {
+ tag : 'div',
+ cls : 'roo-upload-cropbox-error-notify alert alert-danger',
+ html : this.rotateNotify
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'roo-upload-cropbox-footer',
+ cn : {
+ tag : 'div',
+ cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
+ cn : []
+ }
+ }
+ ]
+ };
- if(this.displayInfo){
- Roo.log(this.el.select('ul.navbar-nav',true).first());
- this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
- this.displayEl = this.el.select('.x-paging-info', true).first();
-// var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
-// this.displayEl = navel.el.select('span',true).first();
+ return cfg;
+ },
+
+ onRender : function(ct, position)
+ {
+ Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
+
+ if (this.buttons.length) {
+
+ Roo.each(this.buttons, function(bb) {
+
+ var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
+
+ btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
+
+ }, this);
}
+ },
+
+ initEvents : function()
+ {
+ this.urlAPI = (window.createObjectURL && window) ||
+ (window.URL && URL.revokeObjectURL && URL) ||
+ (window.webkitURL && webkitURL);
+
+ this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
+ this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
+ this.selectorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ this.selectorEl.hide();
+
+ this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
+ this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
+ this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ this.thumbEl.hide();
+
+ this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
+ this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
+ this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ this.errorEl.hide();
+
+ this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
+ this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ this.footerEl.hide();
+
+ this.setThumbBoxSize();
+
+ this.bind();
+
+ this.resize();
+ this.fireEvent('initial', this);
+ },
+
+ bind : function()
+ {
var _this = this;
- if(this.buttons){
- Roo.each(_this.buttons, function(e){
- Roo.factory(e).onRender(_this.el, null);
- });
- }
-
- Roo.each(_this.toolbarItems, function(e) {
- _this.navgroup.addItem(e);
- });
+ window.addEventListener("resize", function() { _this.resize(); } );
+ this.bodyEl.on('click', this.beforeSelectFile, this);
- this.first = this.navgroup.addItem({
- tooltip: this.firstText,
- cls: "prev",
- icon : 'fa fa-backward',
- disabled: true,
- preventDefault: true,
- listeners : { click : this.onClick.createDelegate(this, ["first"]) }
- });
+ if(Roo.isTouch){
+ this.bodyEl.on('touchstart', this.onTouchStart, this);
+ this.bodyEl.on('touchmove', this.onTouchMove, this);
+ this.bodyEl.on('touchend', this.onTouchEnd, this);
+ }
- this.prev = this.navgroup.addItem({
- tooltip: this.prevText,
- cls: "prev",
- icon : 'fa fa-step-backward',
- disabled: true,
- preventDefault: true,
- listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
- });
- //this.addSeparator();
+ if(!Roo.isTouch){
+ this.bodyEl.on('mousedown', this.onMouseDown, this);
+ this.bodyEl.on('mousemove', this.onMouseMove, this);
+ var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
+ this.bodyEl.on(mousewheel, this.onMouseWheel, this);
+ Roo.get(document).on('mouseup', this.onMouseUp, this);
+ }
+ this.selectorEl.on('change', this.onFileSelected, this);
+ },
+
+ reset : function()
+ {
+ this.scale = 0;
+ this.baseScale = 1;
+ this.rotate = 0;
+ this.baseRotate = 1;
+ this.dragable = false;
+ this.pinching = false;
+ this.mouseX = 0;
+ this.mouseY = 0;
+ this.cropData = false;
+ this.notifyEl.dom.innerHTML = this.emptyText;
- var field = this.navgroup.addItem( {
- tagtype : 'span',
- cls : 'x-paging-position',
-
- html : this.beforePageText +
- '<input type="text" size="3" value="1" class="x-grid-page-number">' +
- '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
- } ); //?? escaped?
+ this.selectorEl.dom.value = '';
- this.field = field.el.select('input', true).first();
- this.field.on("keydown", this.onPagingKeydown, this);
- this.field.on("focus", function(){this.dom.select();});
+ },
+ resize : function()
+ {
+ if(this.fireEvent('resize', this) != false){
+ this.setThumbBoxPosition();
+ this.setCanvasPosition();
+ }
+ },
- this.afterTextEl = field.el.select('.x-paging-after',true).first();
- //this.field.setHeight(18);
- //this.addSeparator();
- this.next = this.navgroup.addItem({
- tooltip: this.nextText,
- cls: "next",
- html : ' <i class="fa fa-step-forward">',
- disabled: true,
- preventDefault: true,
- listeners : { click : this.onClick.createDelegate(this, ["next"]) }
- });
- this.last = this.navgroup.addItem({
- tooltip: this.lastText,
- icon : 'fa fa-forward',
- cls: "next",
- disabled: true,
- preventDefault: true,
- listeners : { click : this.onClick.createDelegate(this, ["last"]) }
- });
- //this.addSeparator();
- this.loading = this.navgroup.addItem({
- tooltip: this.refreshText,
- icon: 'fa fa-refresh',
- preventDefault: true,
- listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
- });
-
+ onFooterButtonClick : function(e, el, o, type)
+ {
+ switch (type) {
+ case 'rotate-left' :
+ this.onRotateLeft(e);
+ break;
+ case 'rotate-right' :
+ this.onRotateRight(e);
+ break;
+ case 'picture' :
+ this.beforeSelectFile(e);
+ break;
+ case 'trash' :
+ this.trash(e);
+ break;
+ case 'crop' :
+ this.crop(e);
+ break;
+ case 'download' :
+ this.download(e);
+ break;
+ default :
+ break;
+ }
+
+ this.fireEvent('footerbuttonclick', this, type);
},
-
- // private
- updateInfo : function(){
- if(this.displayEl){
- var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
- var msg = count == 0 ?
- this.emptyMsg :
- String.format(
- this.displayMsg,
- this.cursor+1, this.cursor+count, this.ds.getTotalCount()
- );
- this.displayEl.update(msg);
+
+ beforeSelectFile : function(e)
+ {
+ e.preventDefault();
+
+ if(this.fireEvent('beforeselectfile', this) != false){
+ this.selectorEl.dom.click();
}
},
-
- // private
- onLoad : function(ds, r, o){
- this.cursor = o.params ? o.params.start : 0;
- var d = this.getPageData(),
- ap = d.activePage,
- ps = d.pages;
+
+ onFileSelected : function(e)
+ {
+ e.preventDefault();
+
+ if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+ return;
+ }
+
+ var file = this.selectorEl.dom.files[0];
+
+ if(this.fireEvent('inspect', this, file) != false){
+ this.prepare(file);
+ }
- this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
- this.field.dom.value = ap;
- this.first.setDisabled(ap == 1);
- this.prev.setDisabled(ap == 1);
- this.next.setDisabled(ap == ps);
- this.last.setDisabled(ap == ps);
- this.loading.enable();
- this.updateInfo();
},
-
- // private
- getPageData : function(){
- var total = this.ds.getTotalCount();
- return {
- total : total,
- activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
- pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
- };
+
+ trash : function(e)
+ {
+ this.fireEvent('trash', this);
},
-
- // private
- onLoadError : function(){
- this.loading.enable();
+
+ download : function(e)
+ {
+ this.fireEvent('download', this);
},
-
- // private
- onPagingKeydown : function(e){
- var k = e.getKey();
- var d = this.getPageData();
- if(k == e.RETURN){
- var v = this.field.dom.value, pageNum;
- if(!v || isNaN(pageNum = parseInt(v, 10))){
- this.field.dom.value = d.activePage;
- return;
- }
- pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
- this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
- e.stopEvent();
+
+ loadCanvas : function(src)
+ {
+ if(this.fireEvent('beforeloadcanvas', this, src) != false){
+
+ this.reset();
+
+ this.imageEl = document.createElement('img');
+
+ var _this = this;
+
+ this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
+
+ this.imageEl.src = src;
}
- else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
- {
- var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
- this.field.dom.value = pageNum;
- this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
- e.stopEvent();
+ },
+
+ onLoadCanvas : function()
+ {
+ this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
+ this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
+
+ this.bodyEl.un('click', this.beforeSelectFile, this);
+
+ this.notifyEl.hide();
+ this.thumbEl.show();
+ this.footerEl.show();
+
+ this.baseRotateLevel();
+
+ if(this.isDocument){
+ this.setThumbBoxSize();
}
- else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
- {
- var v = this.field.dom.value, pageNum;
- var increment = (e.shiftKey) ? 10 : 1;
- if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
- increment *= -1;
- if(!v || isNaN(pageNum = parseInt(v, 10))) {
- this.field.dom.value = d.activePage;
+
+ this.setThumbBoxPosition();
+
+ this.baseScaleLevel();
+
+ this.draw();
+
+ this.resize();
+
+ this.canvasLoaded = true;
+
+ },
+
+ setCanvasPosition : function()
+ {
+ if(!this.canvasEl){
return;
- }
- else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
- {
- this.field.dom.value = parseInt(v, 10) + increment;
- pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
- this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
- }
- e.stopEvent();
}
+
+ var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
+ var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
+
+ this.previewEl.setLeft(pw);
+ this.previewEl.setTop(ph);
+
},
-
- // private
- beforeLoad : function(){
- if(this.loading){
- this.loading.disable();
+
+ onMouseDown : function(e)
+ {
+ e.stopEvent();
+
+ this.dragable = true;
+ this.pinching = false;
+
+ if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
+ this.dragable = false;
+ return;
}
+
+ this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
+ this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
+
},
-
- // private
- onClick : function(which){
+
+ onMouseMove : function(e)
+ {
+ e.stopEvent();
- var ds = this.ds;
- if (!ds) {
+ if(!this.canvasLoaded){
return;
}
- switch(which){
- case "first":
- ds.load({params:{start: 0, limit: this.pageSize}});
- break;
- case "prev":
- ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
- break;
- case "next":
- ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
- break;
- case "last":
- var total = ds.getTotalCount();
- var extra = total % this.pageSize;
- var lastStart = extra ? (total - extra) : total-this.pageSize;
- ds.load({params:{start: lastStart, limit: this.pageSize}});
- break;
- case "refresh":
- ds.load({params:{start: this.cursor, limit: this.pageSize}});
- break;
+ if (!this.dragable){
+ return;
}
+
+ var minX = Math.ceil(this.thumbEl.getLeft(true));
+ var minY = Math.ceil(this.thumbEl.getTop(true));
+
+ var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
+ var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
+
+ var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
+ var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
+
+ x = x - this.mouseX;
+ y = y - this.mouseY;
+
+ var bgX = Math.ceil(x + this.previewEl.getLeft(true));
+ var bgY = Math.ceil(y + this.previewEl.getTop(true));
+
+ bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
+ bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
+
+ this.previewEl.setLeft(bgX);
+ this.previewEl.setTop(bgY);
+
+ this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
+ this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
},
-
- /**
- * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
- * @param {Roo.data.Store} store The data store to unbind
- */
- unbind : function(ds){
- ds.un("beforeload", this.beforeLoad, this);
- ds.un("load", this.onLoad, this);
- ds.un("loadexception", this.onLoadError, this);
- ds.un("remove", this.updateInfo, this);
- ds.un("add", this.updateInfo, this);
- this.ds = undefined;
+
+ onMouseUp : function(e)
+ {
+ e.stopEvent();
+
+ this.dragable = false;
},
-
- /**
- * Binds the paging toolbar to the specified {@link Roo.data.Store}
- * @param {Roo.data.Store} store The data store to bind
- */
- bind : function(ds){
- ds.on("beforeload", this.beforeLoad, this);
- ds.on("load", this.onLoad, this);
- ds.on("loadexception", this.onLoadError, this);
- ds.on("remove", this.updateInfo, this);
- ds.on("add", this.updateInfo, this);
- this.ds = ds;
- }
-});/*
- * - LGPL
- *
- * element
- *
- */
-
-/**
- * @class Roo.bootstrap.MessageBar
- * @extends Roo.bootstrap.Component
- * Bootstrap MessageBar class
- * @cfg {String} html contents of the MessageBar
- * @cfg {String} weight (info | success | warning | danger) default info
- * @cfg {String} beforeClass insert the bar before the given class
- * @cfg {Boolean} closable (true | false) default false
- * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
- *
- * @constructor
- * Create a new Element
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.MessageBar = function(config){
- Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
- html: '',
- weight: 'info',
- closable: false,
- fixed: false,
- beforeClass: 'bootstrap-sticky-wrap',
+ onMouseWheel : function(e)
+ {
+ e.stopEvent();
+
+ this.startScale = this.scale;
+
+ this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
+
+ if(!this.zoomable()){
+ this.scale = this.startScale;
+ return;
+ }
+
+ this.draw();
+
+ return;
+ },
- getAutoCreate : function(){
+ zoomable : function()
+ {
+ var minScale = this.thumbEl.getWidth() / this.minWidth;
- var cfg = {
- tag: 'div',
- cls: 'alert alert-dismissable alert-' + this.weight,
- cn: [
- {
- tag: 'span',
- cls: 'message',
- html: this.html || ''
- }
- ]
+ if(this.minWidth < this.minHeight){
+ minScale = this.thumbEl.getHeight() / this.minHeight;
}
- if(this.fixed){
- cfg.cls += ' alert-messages-fixed';
+ var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
+ var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
+
+ if(
+ this.isDocument &&
+ (this.rotate == 0 || this.rotate == 180) &&
+ (
+ width > this.imageEl.OriginWidth ||
+ height > this.imageEl.OriginHeight ||
+ (width < this.minWidth && height < this.minHeight)
+ )
+ ){
+ return false;
}
- if(this.closable){
- cfg.cn.push({
- tag: 'button',
- cls: 'close',
- html: 'x'
- });
+ if(
+ this.isDocument &&
+ (this.rotate == 90 || this.rotate == 270) &&
+ (
+ width > this.imageEl.OriginWidth ||
+ height > this.imageEl.OriginHeight ||
+ (width < this.minHeight && height < this.minWidth)
+ )
+ ){
+ return false;
}
- return cfg;
+ if(
+ !this.isDocument &&
+ (this.rotate == 0 || this.rotate == 180) &&
+ (
+ width < this.minWidth ||
+ width > this.imageEl.OriginWidth ||
+ height < this.minHeight ||
+ height > this.imageEl.OriginHeight
+ )
+ ){
+ return false;
+ }
+
+ if(
+ !this.isDocument &&
+ (this.rotate == 90 || this.rotate == 270) &&
+ (
+ width < this.minHeight ||
+ width > this.imageEl.OriginWidth ||
+ height < this.minWidth ||
+ height > this.imageEl.OriginHeight
+ )
+ ){
+ return false;
+ }
+
+ return true;
+
},
- onRender : function(ct, position)
+ onRotateLeft : function(e)
+ {
+ if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
+
+ var minScale = this.thumbEl.getWidth() / this.minWidth;
+
+ var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
+ var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
+
+ this.startScale = this.scale;
+
+ while (this.getScaleLevel() < minScale){
+
+ this.scale = this.scale + 1;
+
+ if(!this.zoomable()){
+ break;
+ }
+
+ if(
+ Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
+ Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
+ ){
+ continue;
+ }
+
+ this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
+
+ this.draw();
+
+ return;
+ }
+
+ this.scale = this.startScale;
+
+ this.onRotateFail();
+
+ return false;
+ }
+
+ this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
+
+ if(this.isDocument){
+ this.setThumbBoxSize();
+ this.setThumbBoxPosition();
+ this.setCanvasPosition();
+ }
+
+ this.draw();
+
+ this.fireEvent('rotate', this, 'left');
+
+ },
+
+ onRotateRight : function(e)
{
- Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
+ if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
+
+ var minScale = this.thumbEl.getWidth() / this.minWidth;
- if(!this.el){
- var cfg = Roo.apply({}, this.getAutoCreate());
- cfg.id = Roo.id();
+ var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
+ var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
- if (this.cls) {
- cfg.cls += ' ' + this.cls;
- }
- if (this.style) {
- cfg.style = this.style;
+ this.startScale = this.scale;
+
+ while (this.getScaleLevel() < minScale){
+
+ this.scale = this.scale + 1;
+
+ if(!this.zoomable()){
+ break;
+ }
+
+ if(
+ Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
+ Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
+ ){
+ continue;
+ }
+
+ this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
+
+ this.draw();
+
+ return;
}
- this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
- this.el.setVisibilityMode(Roo.Element.DISPLAY);
+ this.scale = this.startScale;
+
+ this.onRotateFail();
+
+ return false;
+ }
+
+ this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
+
+ if(this.isDocument){
+ this.setThumbBoxSize();
+ this.setThumbBoxPosition();
+ this.setCanvasPosition();
}
- this.el.select('>button.close').on('click', this.hide, this);
+ this.draw();
+ this.fireEvent('rotate', this, 'right');
},
- show : function()
+ onRotateFail : function()
{
- if (!this.rendered) {
- this.render();
- }
-
- this.el.show();
+ this.errorEl.show(true);
- this.fireEvent('show', this);
+ var _this = this;
+ (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
},
- hide : function()
+ draw : function()
{
- if (!this.rendered) {
- this.render();
+ this.previewEl.dom.innerHTML = '';
+
+ var canvasEl = document.createElement("canvas");
+
+ var contextEl = canvasEl.getContext("2d");
+
+ canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
+ canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
+ var center = this.imageEl.OriginWidth / 2;
+
+ if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
+ canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
+ canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
+ center = this.imageEl.OriginHeight / 2;
}
- this.el.hide();
+ contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
- this.fireEvent('hide', this);
- },
-
- update : function()
- {
-// var e = this.el.dom.firstChild;
-//
-// if(this.closable){
-// e = e.nextSibling;
-// }
-//
-// e.data = this.html || '';
-
- this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
- }
-
-});
-
-
-
- /*
- * - LGPL
- *
- * Graph
- *
- */
-
-
-/**
- * @class Roo.bootstrap.Graph
- * @extends Roo.bootstrap.Component
- * Bootstrap Graph class
-> Prameters
- -sm {number} sm 4
- -md {number} md 5
- @cfg {String} graphtype bar | vbar | pie
- @cfg {number} g_x coodinator | centre x (pie)
- @cfg {number} g_y coodinator | centre y (pie)
- @cfg {number} g_r radius (pie)
- @cfg {number} g_height height of the chart (respected by all elements in the set)
- @cfg {number} g_width width of the chart (respected by all elements in the set)
- @cfg {Object} title The title of the chart
-
- -{Array} values
- -opts (object) options for the chart
- o {
- o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
- o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
- o vgutter (number)
- o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
- o stacked (boolean) whether or not to tread values as in a stacked bar chart
- o to
- o stretch (boolean)
- o }
- -opts (object) options for the pie
- o{
- o cut
- o startAngle (number)
- o endAngle (number)
- }
- *
- * @constructor
- * Create a new Input
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.Graph = function(config){
- Roo.bootstrap.Graph.superclass.constructor.call(this, config);
-
- this.addEvents({
- // img events
- /**
- * @event click
- * The img click event for the img.
- * @param {Roo.EventObject} e
- */
- "click" : true
- });
-};
+ contextEl.translate(center, center);
+ contextEl.rotate(this.rotate * Math.PI / 180);
-Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
-
- sm: 4,
- md: 5,
- graphtype: 'bar',
- g_height: 250,
- g_width: 400,
- g_x: 50,
- g_y: 50,
- g_r: 30,
- opts:{
- //g_colors: this.colors,
- g_type: 'soft',
- g_gutter: '20%'
-
- },
- title : false,
-
- getAutoCreate : function(){
+ contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
- var cfg = {
- tag: 'div',
- html : null
+ this.canvasEl = document.createElement("canvas");
+
+ this.contextEl = this.canvasEl.getContext("2d");
+
+ switch (this.rotate) {
+ case 0 :
+
+ this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
+ this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
+
+ this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+
+ break;
+ case 90 :
+
+ this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
+ this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
+
+ if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+ this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+ break;
+ }
+
+ this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+
+ break;
+ case 180 :
+
+ this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
+ this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
+
+ if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+ this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+ break;
+ }
+
+ this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+
+ break;
+ case 270 :
+
+ this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
+ this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
+
+ if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+ this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+ break;
+ }
+
+ this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
+
+ break;
+ default :
+ break;
}
+ this.previewEl.appendChild(this.canvasEl);
- return cfg;
+ this.setCanvasPosition();
},
-
- onRender : function(ct,position){
- Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
- this.raphael = Raphael(this.el.dom);
+
+ crop : function()
+ {
+ if(!this.canvasLoaded){
+ return;
+ }
- // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
- // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
- // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
- // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
- /*
- r.text(160, 10, "Single Series Chart").attr(txtattr);
- r.text(480, 10, "Multiline Series Chart").attr(txtattr);
- r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
- r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
+ var imageCanvas = document.createElement("canvas");
+
+ var imageContext = imageCanvas.getContext("2d");
+
+ imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
+ imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
+
+ var center = imageCanvas.width / 2;
+
+ imageContext.translate(center, center);
+
+ imageContext.rotate(this.rotate * Math.PI / 180);
+
+ imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
+
+ var canvas = document.createElement("canvas");
+
+ var context = canvas.getContext("2d");
- r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
- r.barchart(330, 10, 300, 220, data1);
- r.barchart(10, 250, 300, 220, data2, {stacked: true});
- r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
- */
+ canvas.width = this.minWidth;
+ canvas.height = this.minHeight;
+
+ switch (this.rotate) {
+ case 0 :
- // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
- // r.barchart(30, 30, 560, 250, xdata, {
- // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
- // axis : "0 0 1 1",
- // axisxlabels : xdata
- // //yvalues : cols,
-
- // });
-// var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
-//
-// this.load(null,xdata,{
-// axis : "0 0 1 1",
-// axisxlabels : xdata
-// });
+ var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
+ var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
+
+ var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+ var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+
+ var targetWidth = this.minWidth - 2 * x;
+ var targetHeight = this.minHeight - 2 * y;
+
+ var scale = 1;
+
+ if((x == 0 && y == 0) || (x == 0 && y > 0)){
+ scale = targetWidth / width;
+ }
+
+ if(x > 0 && y == 0){
+ scale = targetHeight / height;
+ }
+
+ if(x > 0 && y > 0){
+ scale = targetWidth / width;
+
+ if(width < height){
+ scale = targetHeight / height;
+ }
+ }
+
+ context.scale(scale, scale);
+
+ var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+ var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
- },
+ sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+ sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
- load : function(graphtype,xdata,opts){
- this.raphael.clear();
- if(!graphtype) {
- graphtype = this.graphtype;
- }
- if(!opts){
- opts = this.opts;
- }
- var r = this.raphael,
- fin = function () {
- this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
- },
- fout = function () {
- this.flag.animate({opacity: 0}, 300, function () {this.remove();});
- },
- pfin = function() {
- this.sector.stop();
- this.sector.scale(1.1, 1.1, this.cx, this.cy);
+ context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+
+ break;
+ case 90 :
+
+ var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
+ var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
+
+ var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+ var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+
+ var targetWidth = this.minWidth - 2 * x;
+ var targetHeight = this.minHeight - 2 * y;
+
+ var scale = 1;
+
+ if((x == 0 && y == 0) || (x == 0 && y > 0)){
+ scale = targetWidth / width;
+ }
+
+ if(x > 0 && y == 0){
+ scale = targetHeight / height;
+ }
+
+ if(x > 0 && y > 0){
+ scale = targetWidth / width;
+
+ if(width < height){
+ scale = targetHeight / height;
+ }
+ }
+
+ context.scale(scale, scale);
+
+ var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+ var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
- if (this.label) {
- this.label[0].stop();
- this.label[0].attr({ r: 7.5 });
- this.label[1].attr({ "font-weight": 800 });
+ sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+ sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+
+ sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
+
+ context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+
+ break;
+ case 180 :
+
+ var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
+ var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
+
+ var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+ var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+
+ var targetWidth = this.minWidth - 2 * x;
+ var targetHeight = this.minHeight - 2 * y;
+
+ var scale = 1;
+
+ if((x == 0 && y == 0) || (x == 0 && y > 0)){
+ scale = targetWidth / width;
+ }
+
+ if(x > 0 && y == 0){
+ scale = targetHeight / height;
+ }
+
+ if(x > 0 && y > 0){
+ scale = targetWidth / width;
+
+ if(width < height){
+ scale = targetHeight / height;
+ }
}
- },
- pfout = function() {
- this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
+
+ context.scale(scale, scale);
+
+ var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+ var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
- if (this.label) {
- this.label[0].animate({ r: 5 }, 500, "bounce");
- this.label[1].attr({ "font-weight": 400 });
- }
- };
+ sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+ sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
- switch(graphtype){
- case 'bar':
- this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
- break;
- case 'hbar':
- this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
- break;
- case 'pie':
-// opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
-// href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
-//
- this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
+ sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
+ sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
+
+ context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
break;
+ case 270 :
+
+ var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
+ var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
+
+ var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
+ var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
+
+ var targetWidth = this.minWidth - 2 * x;
+ var targetHeight = this.minHeight - 2 * y;
+
+ var scale = 1;
+
+ if((x == 0 && y == 0) || (x == 0 && y > 0)){
+ scale = targetWidth / width;
+ }
+
+ if(x > 0 && y == 0){
+ scale = targetHeight / height;
+ }
+
+ if(x > 0 && y > 0){
+ scale = targetWidth / width;
+
+ if(width < height){
+ scale = targetHeight / height;
+ }
+ }
+
+ context.scale(scale, scale);
+
+ var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
+ var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
+ sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
+ sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
+
+ sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
+
+ context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
+
+ break;
+ default :
+ break;
}
- if(this.title){
- this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
+ this.cropData = canvas.toDataURL(this.cropType);
+
+ if(this.fireEvent('crop', this, this.cropData) !== false){
+ this.process(this.file, this.cropData);
}
- },
-
- setTitle: function(o)
- {
- this.title = o;
- },
-
- initEvents: function() {
+ return;
- if(!this.href){
- this.el.on('click', this.onClick, this);
- }
},
- onClick : function(e)
+ setThumbBoxSize : function()
{
- Roo.log('img onclick');
- this.fireEvent('click', this, e);
- }
-
-});
-
-
-/*
- * - LGPL
- *
- * numberBox
- *
- */
-Roo.bootstrap.dash = Roo.bootstrap.dash || {};
-
-/**
- * @class Roo.bootstrap.dash.NumberBox
- * @extends Roo.bootstrap.Component
- * Bootstrap NumberBox class
- * @cfg {String} headline Box headline
- * @cfg {String} content Box content
- * @cfg {String} icon Box icon
- * @cfg {String} footer Footer text
- * @cfg {String} fhref Footer href
- *
- * @constructor
- * Create a new NumberBox
- * @param {Object} config The config object
- */
-
-
-Roo.bootstrap.dash.NumberBox = function(config){
- Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
-
-};
-
-Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
-
- headline : '',
- content : '',
- icon : '',
- footer : '',
- fhref : '',
- ficon : '',
-
- getAutoCreate : function(){
+ var width, height;
- var cfg = {
- tag : 'div',
- cls : 'small-box ',
- cn : [
- {
- tag : 'div',
- cls : 'inner',
- cn :[
- {
- tag : 'h3',
- cls : 'roo-headline',
- html : this.headline
- },
- {
- tag : 'p',
- cls : 'roo-content',
- html : this.content
- }
- ]
- }
- ]
+ if(this.isDocument && typeof(this.imageEl) != 'undefined'){
+ width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
+ height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
+
+ this.minWidth = width;
+ this.minHeight = height;
+
+ if(this.rotate == 90 || this.rotate == 270){
+ this.minWidth = height;
+ this.minHeight = width;
+ }
}
- if(this.icon){
- cfg.cn.push({
- tag : 'div',
- cls : 'icon',
- cn :[
- {
- tag : 'i',
- cls : 'ion ' + this.icon
- }
- ]
- });
- }
+ height = 300;
+ width = Math.ceil(this.minWidth * height / this.minHeight);
- if(this.footer){
- var footer = {
- tag : 'a',
- cls : 'small-box-footer',
- href : this.fhref || '#',
- html : this.footer
- };
-
- cfg.cn.push(footer);
-
+ if(this.minWidth > this.minHeight){
+ width = 300;
+ height = Math.ceil(this.minHeight * width / this.minWidth);
}
- return cfg;
- },
-
- onRender : function(ct,position){
- Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
-
+ this.thumbEl.setStyle({
+ width : width + 'px',
+ height : height + 'px'
+ });
-
-
+ return;
+
},
-
- setHeadline: function (value)
+
+ setThumbBoxPosition : function()
{
- this.el.select('.roo-headline',true).first().dom.innerHTML = value;
+ var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
+ var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
+
+ this.thumbEl.setLeft(x);
+ this.thumbEl.setTop(y);
+
},
- setFooter: function (value, href)
+ baseRotateLevel : function()
{
- this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
+ this.baseRotate = 1;
- if(href){
- this.el.select('a.small-box-footer',true).first().attr('href', href);
+ if(
+ typeof(this.exif) != 'undefined' &&
+ typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
+ [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
+ ){
+ this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
}
+ this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
+
},
-
- setContent: function (value)
+
+ baseScaleLevel : function()
{
- this.el.select('.roo-content',true).first().dom.innerHTML = value;
- },
-
- initEvents: function()
- {
+ var width, height;
- }
-
-});
-
-
-/*
- * - LGPL
- *
- * TabBox
- *
- */
-Roo.bootstrap.dash = Roo.bootstrap.dash || {};
+ if(this.isDocument){
+
+ if(this.baseRotate == 6 || this.baseRotate == 8){
+
+ height = this.thumbEl.getHeight();
+ this.baseScale = height / this.imageEl.OriginWidth;
-/**
- * @class Roo.bootstrap.dash.TabBox
- * @extends Roo.bootstrap.Component
- * Bootstrap TabBox class
- * @cfg {String} title Title of the TabBox
- * @cfg {String} icon Icon of the TabBox
- * @cfg {Boolean} showtabs (true|false) show the tabs default true
- * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
- *
- * @constructor
- * Create a new TabBox
- * @param {Object} config The config object
- */
+ if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
+ width = this.thumbEl.getWidth();
+ this.baseScale = width / this.imageEl.OriginHeight;
+ }
+ return;
+ }
-Roo.bootstrap.dash.TabBox = function(config){
- Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
- this.addEvents({
- // raw events
- /**
- * @event addpane
- * When a pane is added
- * @param {Roo.bootstrap.dash.TabPane} pane
- */
- "addpane" : true,
- /**
- * @event activatepane
- * When a pane is activated
- * @param {Roo.bootstrap.dash.TabPane} pane
- */
- "activatepane" : true
-
-
- });
-
- this.panes = [];
-};
+ height = this.thumbEl.getHeight();
+ this.baseScale = height / this.imageEl.OriginHeight;
-Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
+ if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
+ width = this.thumbEl.getWidth();
+ this.baseScale = width / this.imageEl.OriginWidth;
+ }
- title : '',
- icon : false,
- showtabs : true,
- tabScrollable : false,
+ return;
+ }
+
+ if(this.baseRotate == 6 || this.baseRotate == 8){
+
+ width = this.thumbEl.getHeight();
+ this.baseScale = width / this.imageEl.OriginHeight;
+
+ if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
+ height = this.thumbEl.getWidth();
+ this.baseScale = height / this.imageEl.OriginHeight;
+ }
+
+ if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+ height = this.thumbEl.getWidth();
+ this.baseScale = height / this.imageEl.OriginHeight;
+
+ if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
+ width = this.thumbEl.getHeight();
+ this.baseScale = width / this.imageEl.OriginWidth;
+ }
+ }
+
+ return;
+ }
+
+ width = this.thumbEl.getWidth();
+ this.baseScale = width / this.imageEl.OriginWidth;
+
+ if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
+ height = this.thumbEl.getHeight();
+ this.baseScale = height / this.imageEl.OriginHeight;
+ }
+
+ if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
+
+ height = this.thumbEl.getHeight();
+ this.baseScale = height / this.imageEl.OriginHeight;
+
+ if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
+ width = this.thumbEl.getWidth();
+ this.baseScale = width / this.imageEl.OriginWidth;
+ }
+
+ }
+
+ return;
+ },
- getChildContainer : function()
+ getScaleLevel : function()
{
- return this.el.select('.tab-content', true).first();
+ return this.baseScale * Math.pow(1.1, this.scale);
},
- getAutoCreate : function(){
+ onTouchStart : function(e)
+ {
+ if(!this.canvasLoaded){
+ this.beforeSelectFile(e);
+ return;
+ }
- var header = {
- tag: 'li',
- cls: 'pull-left header',
- html: this.title,
- cn : []
- };
+ var touches = e.browserEvent.touches;
- if(this.icon){
- header.cn.push({
- tag: 'i',
- cls: 'fa ' + this.icon
- });
+ if(!touches){
+ return;
}
- var h = {
- tag: 'ul',
- cls: 'nav nav-tabs pull-right',
- cn: [
- header
- ]
- };
+ if(touches.length == 1){
+ this.onMouseDown(e);
+ return;
+ }
- if(this.tabScrollable){
- h = {
- tag: 'div',
- cls: 'tab-header',
- cn: [
- {
- tag: 'ul',
- cls: 'nav nav-tabs pull-right',
- cn: [
- header
- ]
- }
- ]
- }
+ if(touches.length != 2){
+ return;
}
- var cfg = {
- tag: 'div',
- cls: 'nav-tabs-custom',
- cn: [
- h,
- {
- tag: 'div',
- cls: 'tab-content no-padding',
- cn: []
- }
- ]
+ var coords = [];
+
+ for(var i = 0, finger; finger = touches[i]; i++){
+ coords.push(finger.pageX, finger.pageY);
}
-
- return cfg;
- },
- initEvents : function()
- {
- //Roo.log('add add pane handler');
- this.on('addpane', this.onAddPane, this);
- },
- /**
- * Updates the box title
- * @param {String} html to set the title to.
- */
- setTitle : function(value)
- {
- this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
+
+ var x = Math.pow(coords[0] - coords[2], 2);
+ var y = Math.pow(coords[1] - coords[3], 2);
+
+ this.startDistance = Math.sqrt(x + y);
+
+ this.startScale = this.scale;
+
+ this.pinching = true;
+ this.dragable = false;
+
},
- onAddPane : function(pane)
+
+ onTouchMove : function(e)
{
- this.panes.push(pane);
- //Roo.log('addpane');
- //Roo.log(pane);
- // tabs are rendere left to right..
- if(!this.showtabs){
+ if(!this.pinching && !this.dragable){
return;
}
- var ctr = this.el.select('.nav-tabs', true).first();
-
-
- var existing = ctr.select('.nav-tab',true);
- var qty = existing.getCount();;
+ var touches = e.browserEvent.touches;
+ if(!touches){
+ return;
+ }
- var tab = ctr.createChild({
- tag : 'li',
- cls : 'nav-tab' + (qty ? '' : ' active'),
- cn : [
- {
- tag : 'a',
- href:'#',
- html : pane.title
- }
- ]
- }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
- pane.tab = tab;
+ if(this.dragable){
+ this.onMouseMove(e);
+ return;
+ }
- tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
- if (!qty) {
- pane.el.addClass('active');
+ var coords = [];
+
+ for(var i = 0, finger; finger = touches[i]; i++){
+ coords.push(finger.pageX, finger.pageY);
}
-
- },
- onTabClick : function(ev,un,ob,pane)
- {
- //Roo.log('tab - prev default');
- ev.preventDefault();
+ var x = Math.pow(coords[0] - coords[2], 2);
+ var y = Math.pow(coords[1] - coords[3], 2);
+ this.endDistance = Math.sqrt(x + y);
- this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
- pane.tab.addClass('active');
- //Roo.log(pane.title);
- this.getChildContainer().select('.tab-pane',true).removeClass('active');
- // technically we should have a deactivate event.. but maybe add later.
- // and it should not de-activate the selected tab...
- this.fireEvent('activatepane', pane);
- pane.el.addClass('active');
- pane.fireEvent('activate');
+ this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
+
+ if(!this.zoomable()){
+ this.scale = this.startScale;
+ return;
+ }
+ this.draw();
},
- getActivePane : function()
+ onTouchEnd : function(e)
{
- var r = false;
- Roo.each(this.panes, function(p) {
- if(p.el.hasClass('active')){
- r = p;
- return false;
- }
-
- return;
- });
+ this.pinching = false;
+ this.dragable = false;
- return r;
- }
-
+ },
-});
-
-
-/*
- * - LGPL
- *
- * Tab pane
- *
- */
-Roo.bootstrap.dash = Roo.bootstrap.dash || {};
-/**
- * @class Roo.bootstrap.TabPane
- * @extends Roo.bootstrap.Component
- * Bootstrap TabPane class
- * @cfg {Boolean} active (false | true) Default false
- * @cfg {String} title title of panel
+ process : function(file, crop)
+ {
+ this.xhr = new XMLHttpRequest();
+
+ file.xhr = this.xhr;
- *
- * @constructor
- * Create a new TabPane
- * @param {Object} config The config object
- */
+ this.xhr.open(this.method, this.url, true);
+
+ var headers = {
+ "Accept": "application/json",
+ "Cache-Control": "no-cache",
+ "X-Requested-With": "XMLHttpRequest"
+ };
+
+ for (var headerName in headers) {
+ var headerValue = headers[headerName];
+ if (headerValue) {
+ this.xhr.setRequestHeader(headerName, headerValue);
+ }
+ }
+
+ var _this = this;
+
+ this.xhr.onload = function()
+ {
+ _this.xhrOnLoad(_this.xhr);
+ }
+
+ this.xhr.onerror = function()
+ {
+ _this.xhrOnError(_this.xhr);
+ }
+
+ var formData = new FormData();
-Roo.bootstrap.dash.TabPane = function(config){
- Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
+ formData.append('returnHTML', 'NO');
+
+ if(crop){
+ formData.append('crop', crop);
+ }
+
+ if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
+ formData.append(this.paramName, file, file.name);
+ }
+
+ if(typeof(file.filename) != 'undefined'){
+ formData.append('filename', file.filename);
+ }
+
+ if(typeof(file.mimetype) != 'undefined'){
+ formData.append('mimetype', file.mimetype);
+ }
+
+ if(this.fireEvent('arrange', this, formData) != false){
+ this.xhr.send(formData);
+ };
+ },
- this.addEvents({
- // raw events
- /**
- * @event activate
- * When a pane is activated
- * @param {Roo.bootstrap.dash.TabPane} pane
- */
- "activate" : true
-
- });
-};
+ xhrOnLoad : function(xhr)
+ {
+ if (xhr.readyState !== 4) {
+ this.fireEvent('exception', this, xhr);
+ return;
+ }
-Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
+ var response = Roo.decode(xhr.responseText);
+
+ if(!response.success){
+ this.fireEvent('exception', this, xhr);
+ return;
+ }
+
+ var response = Roo.decode(xhr.responseText);
+
+ this.fireEvent('upload', this, response);
+
+ },
- active : false,
- title : '',
+ xhrOnError : function()
+ {
+ Roo.log('xhr on error');
+
+ var response = Roo.decode(xhr.responseText);
+
+ Roo.log(response);
+
+ },
+
+ prepare : function(file)
+ {
+ this.file = false;
+ this.exif = {};
+
+ if(typeof(file) === 'string'){
+ this.loadCanvas(file);
+ return;
+ }
+
+ if(!file || !this.urlAPI){
+ return;
+ }
+
+ this.file = file;
+ this.cropType = file.type;
+
+ var _this = this;
+
+ if(this.fireEvent('prepare', this, this.file) != false){
+
+ var reader = new FileReader();
+
+ reader.onload = function (e) {
+ if (e.target.error) {
+ Roo.log(e.target.error);
+ return;
+ }
+
+ var buffer = e.target.result,
+ dataView = new DataView(buffer),
+ offset = 2,
+ maxOffset = dataView.byteLength - 4,
+ markerBytes,
+ markerLength;
+
+ if (dataView.getUint16(0) === 0xffd8) {
+ while (offset < maxOffset) {
+ markerBytes = dataView.getUint16(offset);
+
+ if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
+ markerLength = dataView.getUint16(offset + 2) + 2;
+ if (offset + markerLength > dataView.byteLength) {
+ Roo.log('Invalid meta data: Invalid segment size.');
+ break;
+ }
+
+ if(markerBytes == 0xffe1){
+ _this.parseExifData(
+ dataView,
+ offset,
+ markerLength
+ );
+ }
+
+ offset += markerLength;
+
+ continue;
+ }
+
+ break;
+ }
+
+ }
+
+ var url = _this.urlAPI.createObjectURL(_this.file);
+
+ _this.loadCanvas(url);
+
+ return;
+ }
+
+ reader.readAsArrayBuffer(this.file);
+
+ }
+
+ },
- // the tabBox that this is attached to.
- tab : false,
-
- getAutoCreate : function()
+ parseExifData : function(dataView, offset, length)
{
- var cfg = {
- tag: 'div',
- cls: 'tab-pane'
+ var tiffOffset = offset + 10,
+ littleEndian,
+ dirOffset;
+
+ if (dataView.getUint32(offset + 4) !== 0x45786966) {
+ // No Exif data, might be XMP data instead
+ return;
}
- if(this.active){
- cfg.cls += ' active';
+ // Check for the ASCII code for "Exif" (0x45786966):
+ if (dataView.getUint32(offset + 4) !== 0x45786966) {
+ // No Exif data, might be XMP data instead
+ return;
+ }
+ if (tiffOffset + 8 > dataView.byteLength) {
+ Roo.log('Invalid Exif data: Invalid segment size.');
+ return;
+ }
+ // Check for the two null bytes:
+ if (dataView.getUint16(offset + 8) !== 0x0000) {
+ Roo.log('Invalid Exif data: Missing byte alignment offset.');
+ return;
+ }
+ // Check the byte alignment:
+ switch (dataView.getUint16(tiffOffset)) {
+ case 0x4949:
+ littleEndian = true;
+ break;
+ case 0x4D4D:
+ littleEndian = false;
+ break;
+ default:
+ Roo.log('Invalid Exif data: Invalid byte alignment marker.');
+ return;
+ }
+ // Check for the TIFF tag marker (0x002A):
+ if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
+ Roo.log('Invalid Exif data: Missing TIFF marker.');
+ return;
}
+ // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
+ dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
- return cfg;
+ this.parseExifTags(
+ dataView,
+ tiffOffset,
+ tiffOffset + dirOffset,
+ littleEndian
+ );
},
- initEvents : function()
+
+ parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
{
- //Roo.log('trigger add pane handler');
- this.parent().fireEvent('addpane', this)
+ var tagsNumber,
+ dirEndOffset,
+ i;
+ if (dirOffset + 6 > dataView.byteLength) {
+ Roo.log('Invalid Exif data: Invalid directory offset.');
+ return;
+ }
+ tagsNumber = dataView.getUint16(dirOffset, littleEndian);
+ dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
+ if (dirEndOffset + 4 > dataView.byteLength) {
+ Roo.log('Invalid Exif data: Invalid directory size.');
+ return;
+ }
+ for (i = 0; i < tagsNumber; i += 1) {
+ this.parseExifTag(
+ dataView,
+ tiffOffset,
+ dirOffset + 2 + 12 * i, // tag offset
+ littleEndian
+ );
+ }
+ // Return the offset to the next directory:
+ return dataView.getUint32(dirEndOffset, littleEndian);
},
- /**
- * Updates the tab title
- * @param {String} html to set the title to.
- */
- setTitle: function(str)
+ parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
{
- if (!this.tab) {
+ var tag = dataView.getUint16(offset, littleEndian);
+
+ this.exif[tag] = this.getExifValue(
+ dataView,
+ tiffOffset,
+ offset,
+ dataView.getUint16(offset + 2, littleEndian), // tag type
+ dataView.getUint32(offset + 4, littleEndian), // tag length
+ littleEndian
+ );
+ },
+
+ getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
+ {
+ var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
+ tagSize,
+ dataOffset,
+ values,
+ i,
+ str,
+ c;
+
+ if (!tagType) {
+ Roo.log('Invalid Exif data: Invalid tag type.');
return;
}
- this.title = str;
- this.tab.select('a', true).first().dom.innerHTML = str;
+ tagSize = tagType.size * length;
+ // Determine if the value is contained in the dataOffset bytes,
+ // or if the value at the dataOffset is a pointer to the actual data:
+ dataOffset = tagSize > 4 ?
+ tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
+ if (dataOffset + tagSize > dataView.byteLength) {
+ Roo.log('Invalid Exif data: Invalid data offset.');
+ return;
+ }
+ if (length === 1) {
+ return tagType.getValue(dataView, dataOffset, littleEndian);
+ }
+ values = [];
+ for (i = 0; i < length; i += 1) {
+ values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
+ }
+
+ if (tagType.ascii) {
+ str = '';
+ // Concatenate the chars:
+ for (i = 0; i < values.length; i += 1) {
+ c = values[i];
+ // Ignore the terminating NULL byte(s):
+ if (c === '\u0000') {
+ break;
+ }
+ str += c;
+ }
+ return str;
+ }
+ return values;
}
+});
+
+Roo.apply(Roo.bootstrap.UploadCropbox, {
+ tags : {
+ 'Orientation': 0x0112
+ },
+
+ Orientation: {
+ 1: 0, //'top-left',
+// 2: 'top-right',
+ 3: 180, //'bottom-right',
+// 4: 'bottom-left',
+// 5: 'left-top',
+ 6: 90, //'right-top',
+// 7: 'right-bottom',
+ 8: 270 //'left-bottom'
+ },
+ exifTagTypes : {
+ // byte, 8-bit unsigned int:
+ 1: {
+ getValue: function (dataView, dataOffset) {
+ return dataView.getUint8(dataOffset);
+ },
+ size: 1
+ },
+ // ascii, 8-bit byte:
+ 2: {
+ getValue: function (dataView, dataOffset) {
+ return String.fromCharCode(dataView.getUint8(dataOffset));
+ },
+ size: 1,
+ ascii: true
+ },
+ // short, 16 bit int:
+ 3: {
+ getValue: function (dataView, dataOffset, littleEndian) {
+ return dataView.getUint16(dataOffset, littleEndian);
+ },
+ size: 2
+ },
+ // long, 32 bit int:
+ 4: {
+ getValue: function (dataView, dataOffset, littleEndian) {
+ return dataView.getUint32(dataOffset, littleEndian);
+ },
+ size: 4
+ },
+ // rational = two long values, first is numerator, second is denominator:
+ 5: {
+ getValue: function (dataView, dataOffset, littleEndian) {
+ return dataView.getUint32(dataOffset, littleEndian) /
+ dataView.getUint32(dataOffset + 4, littleEndian);
+ },
+ size: 8
+ },
+ // slong, 32 bit signed int:
+ 9: {
+ getValue: function (dataView, dataOffset, littleEndian) {
+ return dataView.getInt32(dataOffset, littleEndian);
+ },
+ size: 4
+ },
+ // srational, two slongs, first is numerator, second is denominator:
+ 10: {
+ getValue: function (dataView, dataOffset, littleEndian) {
+ return dataView.getInt32(dataOffset, littleEndian) /
+ dataView.getInt32(dataOffset + 4, littleEndian);
+ },
+ size: 8
+ }
+ },
+ footer : {
+ STANDARD : [
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-rotate-left',
+ action : 'rotate-left',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-undo"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-picture',
+ action : 'picture',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-picture-o"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-rotate-right',
+ action : 'rotate-right',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-repeat"></i>'
+ }
+ ]
+ }
+ ],
+ DOCUMENT : [
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-rotate-left',
+ action : 'rotate-left',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-undo"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-download',
+ action : 'download',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-download"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-crop',
+ action : 'crop',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-crop"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-trash',
+ action : 'trash',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-trash"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-rotate-right',
+ action : 'rotate-right',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-repeat"></i>'
+ }
+ ]
+ }
+ ],
+ ROTATOR : [
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-rotate-left',
+ action : 'rotate-left',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-undo"></i>'
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'btn-group roo-upload-cropbox-rotate-right',
+ action : 'rotate-right',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default',
+ html : '<i class="fa fa-repeat"></i>'
+ }
+ ]
+ }
+ ]
+ }
});
-
-
-
- /*
- * - LGPL
- *
- * menu
- *
- */
-Roo.bootstrap.menu = Roo.bootstrap.menu || {};
+/*
+* Licence: LGPL
+*/
/**
- * @class Roo.bootstrap.menu.Menu
+ * @class Roo.bootstrap.DocumentManager
* @extends Roo.bootstrap.Component
- * Bootstrap Menu class - container for Menu
- * @cfg {String} html Text of the menu
- * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
- * @cfg {String} icon Font awesome icon
- * @cfg {String} pos Menu align to (top | bottom) default bottom
- *
+ * Bootstrap DocumentManager class
+ * @cfg {String} paramName default 'imageUpload'
+ * @cfg {String} method default POST
+ * @cfg {String} url action url
+ * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
+ * @cfg {Boolean} multiple multiple upload default true
+ * @cfg {Number} thumbSize default 300
+ * @cfg {String} fieldLabel
+ * @cfg {Number} labelWidth default 4
+ * @cfg {String} labelAlign (left|top) default left
+ * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
*
* @constructor
- * Create a new Menu
+ * Create a new DocumentManager
* @param {Object} config The config object
*/
-
-Roo.bootstrap.menu.Menu = function(config){
- Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
+Roo.bootstrap.DocumentManager = function(config){
+ Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
this.addEvents({
/**
- * @event beforeshow
- * Fires before this menu is displayed
- * @param {Roo.bootstrap.menu.Menu} this
+ * @event initial
+ * Fire when initial the DocumentManager
+ * @param {Roo.bootstrap.DocumentManager} this
*/
- beforeshow : true,
+ "initial" : true,
/**
- * @event beforehide
- * Fires before this menu is hidden
- * @param {Roo.bootstrap.menu.Menu} this
+ * @event inspect
+ * inspect selected file
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {File} file
*/
- beforehide : true,
+ "inspect" : true,
/**
- * @event show
- * Fires after this menu is displayed
- * @param {Roo.bootstrap.menu.Menu} this
+ * @event exception
+ * Fire when xhr load exception
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {XMLHttpRequest} xhr
*/
- show : true,
+ "exception" : true,
/**
- * @event hide
- * Fires after this menu is hidden
- * @param {Roo.bootstrap.menu.Menu} this
+ * @event prepare
+ * prepare the form data
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {Object} formData
*/
- hide : true,
+ "prepare" : true,
+ /**
+ * @event remove
+ * Fire when remove the file
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {Object} file
+ */
+ "remove" : true,
+ /**
+ * @event refresh
+ * Fire after refresh the file
+ * @param {Roo.bootstrap.DocumentManager} this
+ */
+ "refresh" : true,
/**
* @event click
- * Fires when this menu is clicked (or when the enter key is pressed while it is active)
- * @param {Roo.bootstrap.menu.Menu} this
- * @param {Roo.EventObject} e
+ * Fire after click the image
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {Object} file
*/
- click : true
- });
-
-};
-
-Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
-
- submenu : false,
- html : '',
- weight : 'default',
- icon : false,
- pos : 'bottom',
-
-
- getChildContainer : function() {
- if(this.isSubMenu){
- return this.el;
- }
-
- return this.el.select('ul.dropdown-menu', true).first();
- },
-
- getAutoCreate : function()
- {
- var text = [
- {
- tag : 'span',
- cls : 'roo-menu-text',
- html : this.html
- }
- ];
-
- if(this.icon){
- text.unshift({
- tag : 'i',
- cls : 'fa ' + this.icon
- })
- }
-
+ "click" : true,
+ /**
+ * @event edit
+ * Fire when upload a image and editable set to true
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {Object} file
+ */
+ "edit" : true,
+ /**
+ * @event beforeselectfile
+ * Fire before select file
+ * @param {Roo.bootstrap.DocumentManager} this
+ */
+ "beforeselectfile" : true,
+ /**
+ * @event process
+ * Fire before process file
+ * @param {Roo.bootstrap.DocumentManager} this
+ * @param {Object} file
+ */
+ "process" : true
- var cfg = {
+ });
+};
+
+Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
+
+ boxes : 0,
+ inputName : '',
+ thumbSize : 300,
+ multiple : true,
+ files : [],
+ method : 'POST',
+ url : '',
+ paramName : 'imageUpload',
+ fieldLabel : '',
+ labelWidth : 4,
+ labelAlign : 'left',
+ editable : true,
+ delegates : [],
+
+ getAutoCreate : function()
+ {
+ var managerWidget = {
tag : 'div',
- cls : 'btn-group',
+ cls : 'roo-document-manager',
cn : [
{
- tag : 'button',
- cls : 'dropdown-button btn btn-' + this.weight,
- cn : text
+ tag : 'input',
+ cls : 'roo-document-manager-selector',
+ type : 'file'
},
{
- tag : 'button',
- cls : 'dropdown-toggle btn btn-' + this.weight,
+ tag : 'div',
+ cls : 'roo-document-manager-uploader',
cn : [
{
- tag : 'span',
- cls : 'caret'
+ tag : 'div',
+ cls : 'roo-document-manager-upload-btn',
+ html : '<i class="fa fa-plus"></i>'
}
]
- },
- {
- tag : 'ul',
- cls : 'dropdown-menu'
+
}
]
-
};
- if(this.pos == 'top'){
- cfg.cls += ' dropup';
- }
+ var content = [
+ {
+ tag : 'div',
+ cls : 'column col-md-12',
+ cn : managerWidget
+ }
+ ];
- if(this.isSubMenu){
- cfg = {
- tag : 'ul',
- cls : 'dropdown-menu'
+ if(this.fieldLabel.length){
+
+ content = [
+ {
+ tag : 'div',
+ cls : 'column col-md-12',
+ html : this.fieldLabel
+ },
+ {
+ tag : 'div',
+ cls : 'column col-md-12',
+ cn : managerWidget
+ }
+ ];
+
+ if(this.labelAlign == 'left'){
+ content = [
+ {
+ tag : 'div',
+ cls : 'column col-md-' + this.labelWidth,
+ html : this.fieldLabel
+ },
+ {
+ tag : 'div',
+ cls : 'column col-md-' + (12 - this.labelWidth),
+ cn : managerWidget
+ }
+ ];
+
}
}
-
+
+ var cfg = {
+ tag : 'div',
+ cls : 'row clearfix',
+ cn : content
+ };
+
return cfg;
+
},
- onRender : function(ct, position)
+ initEvents : function()
{
- this.isSubMenu = ct.hasClass('dropdown-submenu');
+ this.managerEl = this.el.select('.roo-document-manager', true).first();
+ this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
+ this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
+ this.selectorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+ this.selectorEl.hide();
+
+ if(this.multiple){
+ this.selectorEl.attr('multiple', 'multiple');
+ }
+
+ this.selectorEl.on('change', this.onFileSelected, this);
+
+ this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
+ this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ this.uploader.on('click', this.onUploaderClick, this);
+
+ this.renderProgressDialog();
+
+ var _this = this;
+
+ window.addEventListener("resize", function() { _this.refresh(); } );
+
+ this.fireEvent('initial', this);
},
- initEvents : function()
+ renderProgressDialog : function()
{
- if(this.isSubMenu){
- return;
- }
+ var _this = this;
- this.hidden = true;
+ this.progressDialog = new Roo.bootstrap.Modal({
+ cls : 'roo-document-manager-progress-dialog',
+ allow_close : false,
+ title : '',
+ buttons : [
+ {
+ name :'cancel',
+ weight : 'danger',
+ html : 'Cancel'
+ }
+ ],
+ listeners : {
+ btnclick : function() {
+ _this.uploadCancel();
+ this.hide();
+ }
+ }
+ });
+
+ this.progressDialog.render(Roo.get(document.body));
+
+ this.progress = new Roo.bootstrap.Progress({
+ cls : 'roo-document-manager-progress',
+ active : true,
+ striped : true
+ });
- this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
- this.triggerEl.on('click', this.onTriggerPress, this);
+ this.progress.render(this.progressDialog.getChildContainer());
- this.buttonEl = this.el.select('button.dropdown-button', true).first();
- this.buttonEl.on('click', this.onClick, this);
+ this.progressBar = new Roo.bootstrap.ProgressBar({
+ cls : 'roo-document-manager-progress-bar',
+ aria_valuenow : 0,
+ aria_valuemin : 0,
+ aria_valuemax : 12,
+ panel : 'success'
+ });
+ this.progressBar.render(this.progress.getChildContainer());
},
- list : function()
+ onUploaderClick : function(e)
{
- if(this.isSubMenu){
- return this.el;
+ e.preventDefault();
+
+ if(this.fireEvent('beforeselectfile', this) != false){
+ this.selectorEl.dom.click();
}
- return this.el.select('ul.dropdown-menu', true).first();
},
- onClick : function(e)
+ onFileSelected : function(e)
{
- this.fireEvent("click", this, e);
- },
-
- onTriggerPress : function(e)
- {
- if (this.isVisible()) {
- this.hide();
- } else {
- this.show();
+ e.preventDefault();
+
+ if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+ return;
}
+
+ Roo.each(this.selectorEl.dom.files, function(file){
+ if(this.fireEvent('inspect', this, file) != false){
+ this.files.push(file);
+ }
+ }, this);
+
+ this.queue();
+
},
- isVisible : function(){
- return !this.hidden;
- },
-
- show : function()
+ queue : function()
{
- this.fireEvent("beforeshow", this);
+ this.selectorEl.dom.value = '';
- this.hidden = false;
- this.el.addClass('open');
+ if(!this.files.length){
+ return;
+ }
- Roo.get(document).on("mouseup", this.onMouseUp, this);
+ if(this.boxes > 0 && this.files.length > this.boxes){
+ this.files = this.files.slice(0, this.boxes);
+ }
- this.fireEvent("show", this);
+ this.uploader.show();
+ if(this.boxes > 0 && this.files.length > this.boxes - 1){
+ this.uploader.hide();
+ }
- },
-
- hide : function()
- {
- this.fireEvent("beforehide", this);
+ var _this = this;
- this.hidden = true;
- this.el.removeClass('open');
+ var files = [];
- Roo.get(document).un("mouseup", this.onMouseUp);
+ var docs = [];
- this.fireEvent("hide", this);
- },
-
- onMouseUp : function()
- {
- this.hide();
- }
-
-});
-
-
- /*
- * - LGPL
- *
- * menu item
- *
- */
-Roo.bootstrap.menu = Roo.bootstrap.menu || {};
-
-/**
- * @class Roo.bootstrap.menu.Item
- * @extends Roo.bootstrap.Component
- * Bootstrap MenuItem class
- * @cfg {Boolean} submenu (true | false) default false
- * @cfg {String} html text of the item
- * @cfg {String} href the link
- * @cfg {Boolean} disable (true | false) default false
- * @cfg {Boolean} preventDefault (true | false) default true
- * @cfg {String} icon Font awesome icon
- * @cfg {String} pos Submenu align to (left | right) default right
- *
- *
- * @constructor
- * Create a new Item
- * @param {Object} config The config object
- */
-
-
-Roo.bootstrap.menu.Item = function(config){
- Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
- this.addEvents({
- /**
- * @event mouseover
- * Fires when the mouse is hovering over this menu
- * @param {Roo.bootstrap.menu.Item} this
- * @param {Roo.EventObject} e
- */
- mouseover : true,
- /**
- * @event mouseout
- * Fires when the mouse exits this menu
- * @param {Roo.bootstrap.menu.Item} this
- * @param {Roo.EventObject} e
- */
- mouseout : true,
- // raw events
- /**
- * @event click
- * The raw click event for the entire grid.
- * @param {Roo.EventObject} e
- */
- click : true
- });
-};
-
-Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
-
- submenu : false,
- href : '',
- html : '',
- preventDefault: true,
- disable : false,
- icon : false,
- pos : 'right',
-
- getAutoCreate : function()
- {
- var text = [
- {
- tag : 'span',
- cls : 'roo-menu-item-text',
- html : this.html
+ Roo.each(this.files, function(file){
+
+ if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
+ var f = this.renderPreview(file);
+ files.push(f);
+ return;
}
- ];
+
+ if(file.type.indexOf('image') != -1){
+ this.delegates.push(
+ (function(){
+ _this.process(file);
+ }).createDelegate(this)
+ );
- if(this.icon){
- text.unshift({
- tag : 'i',
- cls : 'fa ' + this.icon
- })
- }
+ return;
+ }
+
+ docs.push(
+ (function(){
+ _this.process(file);
+ }).createDelegate(this)
+ );
+
+ }, this);
- var cfg = {
- tag : 'li',
- cn : [
- {
- tag : 'a',
- href : this.href || '#',
- cn : text
- }
- ]
- };
+ this.files = files;
- if(this.disable){
- cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
- }
+ this.delegates = this.delegates.concat(docs);
- if(this.submenu){
- cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
-
- if(this.pos == 'left'){
- cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
- }
+ if(!this.delegates.length){
+ this.refresh();
+ return;
}
- return cfg;
+ this.progressBar.aria_valuemax = this.delegates.length;
+
+ this.arrange();
+
+ return;
},
- initEvents : function()
+ arrange : function()
{
- this.el.on('mouseover', this.onMouseOver, this);
- this.el.on('mouseout', this.onMouseOut, this);
+ if(!this.delegates.length){
+ this.progressDialog.hide();
+ this.refresh();
+ return;
+ }
- this.el.select('a', true).first().on('click', this.onClick, this);
+ var delegate = this.delegates.shift();
+
+ this.progressDialog.show();
+
+ this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
+ this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
+
+ delegate();
},
- onClick : function(e)
+ refresh : function()
{
- if(this.preventDefault){
- e.preventDefault();
+ this.uploader.show();
+
+ if(this.boxes > 0 && this.files.length > this.boxes - 1){
+ this.uploader.hide();
}
- this.fireEvent("click", this, e);
+ Roo.isTouch ? this.closable(false) : this.closable(true);
+
+ this.fireEvent('refresh', this);
},
- onMouseOver : function(e)
+ onRemove : function(e, el, o)
{
- if(this.submenu && this.pos == 'left'){
- this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
- }
+ e.preventDefault();
+
+ this.fireEvent('remove', this, o);
- this.fireEvent("mouseover", this, e);
},
- onMouseOut : function(e)
+ remove : function(o)
{
- this.fireEvent("mouseout", this, e);
- }
-});
-
-
-
- /*
- * - LGPL
- *
- * menu separator
- *
- */
-Roo.bootstrap.menu = Roo.bootstrap.menu || {};
-
-/**
- * @class Roo.bootstrap.menu.Separator
- * @extends Roo.bootstrap.Component
- * Bootstrap Separator class
- *
- * @constructor
- * Create a new Separator
- * @param {Object} config The config object
- */
-
-
-Roo.bootstrap.menu.Separator = function(config){
- Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
-
- getAutoCreate : function(){
- var cfg = {
- tag : 'li',
- cls: 'divider'
- };
+ var files = [];
- return cfg;
- }
-
-});
-
-
-
- /*
- * - LGPL
- *
- * Tooltip
- *
- */
-
-/**
- * @class Roo.bootstrap.Tooltip
- * Bootstrap Tooltip class
- * This is basic at present - all componets support it by default, however they should add tooltipEl() method
- * to determine which dom element triggers the tooltip.
- *
- * It needs to add support for additional attributes like tooltip-position
- *
- * @constructor
- * Create a new Toolti
- * @param {Object} config The config object
- */
+ Roo.each(this.files, function(file){
+ if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
+ files.push(file);
+ return;
+ }
-Roo.bootstrap.Tooltip = function(config){
- Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
-};
+ o.target.remove();
-Roo.apply(Roo.bootstrap.Tooltip, {
- /**
- * @function init initialize tooltip monitoring.
- * @static
- */
- currentEl : false,
- currentTip : false,
- currentRegion : false,
-
- // init : delay?
+ }, this);
+
+ this.files = files;
+
+ this.refresh();
+ },
- init : function()
+ clear : function()
{
- Roo.get(document).on('mouseover', this.enter ,this);
- Roo.get(document).on('mouseout', this.leave, this);
-
+ Roo.each(this.files, function(file){
+ if(!file.target){
+ return;
+ }
+
+ file.target.remove();
+
+ }, this);
- this.currentTip = new Roo.bootstrap.Tooltip();
+ this.files = [];
+
+ this.refresh();
},
- enter : function(ev)
+ onClick : function(e, el, o)
{
- var dom = ev.getTarget();
+ e.preventDefault();
- //Roo.log(['enter',dom]);
- var el = Roo.fly(dom);
- if (this.currentEl) {
- //Roo.log(dom);
- //Roo.log(this.currentEl);
- //Roo.log(this.currentEl.contains(dom));
- if (this.currentEl == el) {
- return;
- }
- if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
+ this.fireEvent('click', this, o);
+
+ },
+
+ closable : function(closable)
+ {
+ Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
+
+ el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+
+ if(closable){
+ el.show();
return;
}
+
+ el.hide();
+
+ }, this);
+ },
+
+ xhrOnLoad : function(xhr)
+ {
+ Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
+ el.remove();
+ }, this);
+
+ if (xhr.readyState !== 4) {
+ this.arrange();
+ this.fireEvent('exception', this, xhr);
+ return;
+ }
+ var response = Roo.decode(xhr.responseText);
+
+ if(!response.success){
+ this.arrange();
+ this.fireEvent('exception', this, xhr);
+ return;
}
+ var file = this.renderPreview(response.data);
+ this.files.push(file);
- if (this.currentTip.el) {
- this.currentTip.el.hide(); // force hiding...
- }
- //Roo.log(ev);
- var bindEl = el;
+ this.arrange();
- // you can not look for children, as if el is the body.. then everythign is the child..
- if (!el.attr('tooltip')) { //
- if (!el.select("[tooltip]").elements.length) {
- return;
- }
- // is the mouse over this child...?
- bindEl = el.select("[tooltip]").first();
- var xy = ev.getXY();
- if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
- //Roo.log("not in region.");
+ },
+
+ xhrOnError : function()
+ {
+ Roo.log('xhr on error');
+
+ var response = Roo.decode(xhr.responseText);
+
+ Roo.log(response);
+
+ this.arrange();
+ },
+
+ process : function(file)
+ {
+ if(this.fireEvent('process', this, file) !== false){
+ if(this.editable && file.type.indexOf('image') != -1){
+ this.fireEvent('edit', this, file);
return;
}
- //Roo.log("child element over..");
-
+
+ this.uploadStart(file, false);
+
+ return;
}
- this.currentEl = bindEl;
- this.currentTip.bind(bindEl);
- this.currentRegion = Roo.lib.Region.getRegion(dom);
- this.currentTip.enter();
},
- leave : function(ev)
+
+ uploadStart : function(file, crop)
{
- var dom = ev.getTarget();
- //Roo.log(['leave',dom]);
- if (!this.currentEl) {
+ this.xhr = new XMLHttpRequest();
+
+ if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
+ this.arrange();
return;
}
+ file.xhr = this.xhr;
+
+ this.managerEl.createChild({
+ tag : 'div',
+ cls : 'roo-document-manager-loading',
+ cn : [
+ {
+ tag : 'div',
+ tooltip : file.name,
+ cls : 'roo-document-manager-thumb',
+ html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
+ }
+ ]
+
+ });
+
+ this.xhr.open(this.method, this.url, true);
+
+ var headers = {
+ "Accept": "application/json",
+ "Cache-Control": "no-cache",
+ "X-Requested-With": "XMLHttpRequest"
+ };
- if (dom != this.currentEl.dom) {
- return;
- }
- var xy = ev.getXY();
- if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
- return;
+ for (var headerName in headers) {
+ var headerValue = headers[headerName];
+ if (headerValue) {
+ this.xhr.setRequestHeader(headerName, headerValue);
+ }
}
- // only activate leave if mouse cursor is outside... bounding box..
+ var _this = this;
+
+ this.xhr.onload = function()
+ {
+ _this.xhrOnLoad(_this.xhr);
+ }
+ this.xhr.onerror = function()
+ {
+ _this.xhrOnError(_this.xhr);
+ }
+ var formData = new FormData();
+
+ formData.append('returnHTML', 'NO');
- if (this.currentTip) {
- this.currentTip.leave();
+ if(crop){
+ formData.append('crop', crop);
}
- //Roo.log('clear currentEl');
- this.currentEl = false;
+ formData.append(this.paramName, file, file.name);
- },
- alignment : {
- 'left' : ['r-l', [-2,0], 'right'],
- 'right' : ['l-r', [2,0], 'left'],
- 'bottom' : ['t-b', [0,2], 'top'],
- 'top' : [ 'b-t', [0,-2], 'bottom']
- }
-
-});
-
-
-Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
-
-
- bindEl : false,
-
- delay : null, // can be { show : 300 , hide: 500}
-
- timeout : null,
-
- hoverState : null, //???
-
- placement : 'bottom',
+ if(this.fireEvent('prepare', this, formData) != false){
+ this.xhr.send(formData);
+ };
+ },
- getAutoCreate : function(){
+ uploadCancel : function()
+ {
+ this.xhr.abort();
+
+ this.delegates = [];
+
+ Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
+ el.remove();
+ }, this);
+
+ this.arrange();
+ },
- var cfg = {
- cls : 'tooltip',
- role : 'tooltip',
- cn : [
+ renderPreview : function(file)
+ {
+ if(typeof(file.target) != 'undefined' && file.target){
+ return file;
+ }
+
+ var previewEl = this.managerEl.createChild({
+ tag : 'div',
+ cls : 'roo-document-manager-preview',
+ cn : [
{
- cls : 'tooltip-arrow'
+ tag : 'div',
+ tooltip : file.filename,
+ cls : 'roo-document-manager-thumb',
+ html : '<img src="' + baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename + '">'
},
{
- cls : 'tooltip-inner'
+ tag : 'button',
+ cls : 'close',
+ html : '<i class="fa fa-times-circle"></i>'
}
- ]
- };
+ ]
+ });
+
+ var close = previewEl.select('button.close', true).first();
+
+ close.on('click', this.onRemove, this, file);
+
+ file.target = previewEl;
+
+ var image = previewEl.select('img', true).first();
+
+ var _this = this;
+
+ image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
+
+ image.on('click', this.onClick, this, file);
+
+ return file;
- return cfg;
- },
- bind : function(el)
- {
- this.bindEl = el;
},
-
- enter : function () {
-
- if (this.timeout != null) {
- clearTimeout(this.timeout);
- }
-
- this.hoverState = 'in';
- //Roo.log("enter - show");
- if (!this.delay || !this.delay.show) {
- this.show();
+ onPreviewLoad : function(file, image)
+ {
+ if(typeof(file.target) == 'undefined' || !file.target){
return;
}
- var _t = this;
- this.timeout = setTimeout(function () {
- if (_t.hoverState == 'in') {
- _t.show();
- }
- }, this.delay.show);
- },
- leave : function()
- {
- clearTimeout(this.timeout);
-
- this.hoverState = 'out';
- if (!this.delay || !this.delay.hide) {
- this.hide();
+
+ var width = image.dom.naturalWidth || image.dom.width;
+ var height = image.dom.naturalHeight || image.dom.height;
+
+ if(width > height){
+ file.target.addClass('wide');
return;
}
-
- var _t = this;
- this.timeout = setTimeout(function () {
- //Roo.log("leave - timeout");
-
- if (_t.hoverState == 'out') {
- _t.hide();
- Roo.bootstrap.Tooltip.currentEl = false;
- }
- }, delay);
+
+ file.target.addClass('tall');
+ return;
+
},
- show : function ()
+ uploadFromSource : function(file, crop)
{
- if (!this.el) {
- this.render(document.body);
- }
- // set content.
- //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
-
- var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
+ this.xhr = new XMLHttpRequest();
- this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
+ this.managerEl.createChild({
+ tag : 'div',
+ cls : 'roo-document-manager-loading',
+ cn : [
+ {
+ tag : 'div',
+ tooltip : file.name,
+ cls : 'roo-document-manager-thumb',
+ html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
+ }
+ ]
+
+ });
+
+ this.xhr.open(this.method, this.url, true);
- this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
+ var headers = {
+ "Accept": "application/json",
+ "Cache-Control": "no-cache",
+ "X-Requested-With": "XMLHttpRequest"
+ };
- var placement = typeof this.placement == 'function' ?
- this.placement.call(this, this.el, on_el) :
- this.placement;
-
- var autoToken = /\s?auto?\s?/i;
- var autoPlace = autoToken.test(placement);
- if (autoPlace) {
- placement = placement.replace(autoToken, '') || 'top';
+ for (var headerName in headers) {
+ var headerValue = headers[headerName];
+ if (headerValue) {
+ this.xhr.setRequestHeader(headerName, headerValue);
+ }
}
- //this.el.detach()
- //this.el.setXY([0,0]);
- this.el.show();
- //this.el.dom.style.display='block';
- this.el.addClass(placement);
-
- //this.el.appendTo(on_el);
+ var _this = this;
- var p = this.getPosition();
- var box = this.el.getBox();
+ this.xhr.onload = function()
+ {
+ _this.xhrOnLoad(_this.xhr);
+ }
- if (autoPlace) {
- // fixme..
+ this.xhr.onerror = function()
+ {
+ _this.xhrOnError(_this.xhr);
}
- var align = Roo.bootstrap.Tooltip.alignment[placement];
- this.el.alignTo(this.bindEl, align[0],align[1]);
- //var arrow = this.el.select('.arrow',true).first();
- //arrow.set(align[2],
- this.el.addClass('in fade');
- this.hoverState = null;
+ var formData = new FormData();
+
+ formData.append('returnHTML', 'NO');
- if (this.el.hasClass('fade')) {
- // fade it?
+ formData.append('crop', crop);
+
+ if(typeof(file.filename) != 'undefined'){
+ formData.append('filename', file.filename);
}
- },
- hide : function()
- {
-
- if (!this.el) {
- return;
+ if(typeof(file.mimetype) != 'undefined'){
+ formData.append('mimetype', file.mimetype);
}
- //this.el.setXY([0,0]);
- this.el.removeClass('in');
- //this.el.hide();
+ if(this.fireEvent('prepare', this, formData) != false){
+ this.xhr.send(formData);
+ };
}
-
});
-
- /*
- * - LGPL
- *
- * Location Picker
- *
- */
+/*
+* Licence: LGPL
+*/
/**
- * @class Roo.bootstrap.LocationPicker
+ * @class Roo.bootstrap.DocumentViewer
* @extends Roo.bootstrap.Component
- * Bootstrap LocationPicker class
- * @cfg {Number} latitude Position when init default 0
- * @cfg {Number} longitude Position when init default 0
- * @cfg {Number} zoom default 15
- * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
- * @cfg {Boolean} mapTypeControl default false
- * @cfg {Boolean} disableDoubleClickZoom default false
- * @cfg {Boolean} scrollwheel default true
- * @cfg {Boolean} streetViewControl default false
- * @cfg {Number} radius default 0
- * @cfg {String} locationName
- * @cfg {Boolean} draggable default true
- * @cfg {Boolean} enableAutocomplete default false
- * @cfg {Boolean} enableReverseGeocode default true
- * @cfg {String} markerTitle
+ * Bootstrap DocumentViewer class
*
* @constructor
- * Create a new LocationPicker
+ * Create a new DocumentViewer
* @param {Object} config The config object
*/
-
-Roo.bootstrap.LocationPicker = function(config){
-
- Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
+Roo.bootstrap.DocumentViewer = function(config){
+ Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
this.addEvents({
/**
* @event initial
- * Fires when the picker initialized.
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Google Location} location
- */
- initial : true,
- /**
- * @event positionchanged
- * Fires when the picker position changed.
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Google Location} location
- */
- positionchanged : true,
- /**
- * @event resize
- * Fires when the map resize.
- * @param {Roo.bootstrap.LocationPicker} this
+ * Fire after initEvent
+ * @param {Roo.bootstrap.DocumentViewer} this
*/
- resize : true,
- /**
- * @event show
- * Fires when the map show.
- * @param {Roo.bootstrap.LocationPicker} this
- */
- show : true,
- /**
- * @event hide
- * Fires when the map hide.
- * @param {Roo.bootstrap.LocationPicker} this
- */
- hide : true,
- /**
- * @event mapClick
- * Fires when click the map.
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Map event} e
- */
- mapClick : true,
- /**
- * @event mapRightClick
- * Fires when right click the map.
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Map event} e
- */
- mapRightClick : true,
- /**
- * @event markerClick
- * Fires when click the marker.
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Map event} e
- */
- markerClick : true,
- /**
- * @event markerRightClick
- * Fires when right click the marker.
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Map event} e
- */
- markerRightClick : true,
- /**
- * @event OverlayViewDraw
- * Fires when OverlayView Draw
- * @param {Roo.bootstrap.LocationPicker} this
- */
- OverlayViewDraw : true,
- /**
- * @event OverlayViewOnAdd
- * Fires when OverlayView Draw
- * @param {Roo.bootstrap.LocationPicker} this
- */
- OverlayViewOnAdd : true,
- /**
- * @event OverlayViewOnRemove
- * Fires when OverlayView Draw
- * @param {Roo.bootstrap.LocationPicker} this
- */
- OverlayViewOnRemove : true,
+ "initial" : true,
/**
- * @event OverlayViewShow
- * Fires when OverlayView Draw
- * @param {Roo.bootstrap.LocationPicker} this
- * @param {Pixel} cpx
+ * @event click
+ * Fire after click
+ * @param {Roo.bootstrap.DocumentViewer} this
*/
- OverlayViewShow : true,
+ "click" : true,
/**
- * @event OverlayViewHide
- * Fires when OverlayView Draw
- * @param {Roo.bootstrap.LocationPicker} this
+ * @event trash
+ * Fire after trash button
+ * @param {Roo.bootstrap.DocumentViewer} this
*/
- OverlayViewHide : true
- });
+ "trash" : true
+ });
};
-Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
-
- gMapContext: false,
-
- latitude: 0,
- longitude: 0,
- zoom: 15,
- mapTypeId: false,
- mapTypeControl: false,
- disableDoubleClickZoom: false,
- scrollwheel: true,
- streetViewControl: false,
- radius: 0,
- locationName: '',
- draggable: true,
- enableAutocomplete: false,
- enableReverseGeocode: true,
- markerTitle: '',
+Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
- getAutoCreate: function()
+ getAutoCreate : function()
{
-
var cfg = {
- tag: 'div',
- cls: 'roo-location-picker'
+ tag : 'div',
+ cls : 'roo-document-viewer',
+ cn : [
+ {
+ tag : 'div',
+ cls : 'roo-document-viewer-body',
+ cn : [
+ {
+ tag : 'div',
+ cls : 'roo-document-viewer-thumb',
+ cn : [
+ {
+ tag : 'img',
+ cls : 'roo-document-viewer-image'
+ }
+ ]
+ }
+ ]
+ },
+ {
+ tag : 'div',
+ cls : 'roo-document-viewer-footer',
+ cn : {
+ tag : 'div',
+ cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
+ cn : [
+ {
+ tag : 'div',
+ cls : 'btn-group',
+ cn : [
+ {
+ tag : 'button',
+ cls : 'btn btn-default roo-document-viewer-trash',
+ html : '<i class="fa fa-trash"></i>'
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
};
- return cfg
- },
-
- initEvents: function(ct, position)
- {
- if(!this.el.getWidth() || this.isApplied()){
- return;
- }
-
- this.el.setVisibilityMode(Roo.Element.DISPLAY);
-
- this.initial();
+ return cfg;
},
- initial: function()
+ initEvents : function()
{
- if(!this.mapTypeId){
- this.mapTypeId = google.maps.MapTypeId.ROADMAP;
- }
- this.gMapContext = this.GMapContext();
+ this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
+ this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- this.initOverlayView();
+ this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
+ this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
+ this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
+ this.imageEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- var _this = this;
-
- google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
- _this.setPosition(_this.gMapContext.marker.position);
- });
+ this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
+ this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
- _this.fireEvent('mapClick', this, event);
-
- });
-
- google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
- _this.fireEvent('mapRightClick', this, event);
-
- });
+ this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
+ this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
- google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
- _this.fireEvent('markerClick', this, event);
-
- });
-
- google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
- _this.fireEvent('markerRightClick', this, event);
-
- });
+ this.bodyEl.on('click', this.onClick, this);
- this.setPosition(this.gMapContext.location);
+ this.trashBtn.on('click', this.onTrash, this);
- this.fireEvent('initial', this, this.gMapContext.location);
},
- initOverlayView: function()
+ initial : function()
{
- var _this = this;
+// this.thumbEl.setStyle('line-height', this.thumbEl.getHeight(true) + 'px');
+
+
+ this.fireEvent('initial', this);
- Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
-
- draw: function()
- {
- _this.fireEvent('OverlayViewDraw', _this);
- },
-
- onAdd: function()
- {
- _this.fireEvent('OverlayViewOnAdd', _this);
- },
-
- onRemove: function()
- {
- _this.fireEvent('OverlayViewOnRemove', _this);
- },
-
- show: function(cpx)
- {
- _this.fireEvent('OverlayViewShow', _this, cpx);
- },
-
- hide: function()
- {
- _this.fireEvent('OverlayViewHide', _this);
- }
-
- });
},
- fromLatLngToContainerPixel: function(event)
+ onClick : function(e)
{
- return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
+ e.preventDefault();
+
+ this.fireEvent('click', this);
},
- isApplied: function()
+ onTrash : function(e)
{
- return this.getGmapContext() == false ? false : true;
- },
+ e.preventDefault();
+
+ this.fireEvent('trash', this);
+ }
- getGmapContext: function()
- {
- return this.gMapContext
- },
+});
+/*
+ * - LGPL
+ *
+ * nav progress bar
+ *
+ */
+
+/**
+ * @class Roo.bootstrap.NavProgressBar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap NavProgressBar class
+ *
+ * @constructor
+ * Create a new nav progress bar
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.NavProgressBar = function(config){
+ Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
+
+ this.bullets = this.bullets || [];
+
+// Roo.bootstrap.NavProgressBar.register(this);
+ this.addEvents({
+ /**
+ * @event changed
+ * Fires when the active item changes
+ * @param {Roo.bootstrap.NavProgressBar} this
+ * @param {Roo.bootstrap.NavProgressItem} selected The item selected
+ * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
+ */
+ 'changed': true
+ });
- GMapContext: function()
- {
- var position = new google.maps.LatLng(this.latitude, this.longitude);
-
- var _map = new google.maps.Map(this.el.dom, {
- center: position,
- zoom: this.zoom,
- mapTypeId: this.mapTypeId,
- mapTypeControl: this.mapTypeControl,
- disableDoubleClickZoom: this.disableDoubleClickZoom,
- scrollwheel: this.scrollwheel,
- streetViewControl: this.streetViewControl,
- locationName: this.locationName,
- draggable: this.draggable,
- enableAutocomplete: this.enableAutocomplete,
- enableReverseGeocode: this.enableReverseGeocode
- });
-
- var _marker = new google.maps.Marker({
- position: position,
- map: _map,
- title: this.markerTitle,
- draggable: this.draggable
- });
-
- return {
- map: _map,
- marker: _marker,
- circle: null,
- location: position,
- radius: this.radius,
- locationName: this.locationName,
- addressComponents: {
- formatted_address: null,
- addressLine1: null,
- addressLine2: null,
- streetName: null,
- streetNumber: null,
- city: null,
- district: null,
- state: null,
- stateOrProvince: null
- },
- settings: this,
- domContainer: this.el.dom,
- geodecoder: new google.maps.Geocoder()
- };
- },
+};
+
+Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
- drawCircle: function(center, radius, options)
- {
- if (this.gMapContext.circle != null) {
- this.gMapContext.circle.setMap(null);
- }
- if (radius > 0) {
- radius *= 1;
- options = Roo.apply({}, options, {
- strokeColor: "#0000FF",
- strokeOpacity: .35,
- strokeWeight: 2,
- fillColor: "#0000FF",
- fillOpacity: .2
- });
-
- options.map = this.gMapContext.map;
- options.radius = radius;
- options.center = center;
- this.gMapContext.circle = new google.maps.Circle(options);
- return this.gMapContext.circle;
- }
-
- return null;
- },
+ bullets : [],
+ barItems : [],
- setPosition: function(location)
+
+ getAutoCreate : function()
{
- this.gMapContext.location = location;
- this.gMapContext.marker.setPosition(location);
- this.gMapContext.map.panTo(location);
- this.drawCircle(location, this.gMapContext.radius, {});
-
- var _this = this;
+ var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
- if (this.gMapContext.settings.enableReverseGeocode) {
- this.gMapContext.geodecoder.geocode({
- latLng: this.gMapContext.location
- }, function(results, status) {
-
- if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
- _this.gMapContext.locationName = results[0].formatted_address;
- _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
-
- _this.fireEvent('positionchanged', this, location);
- }
- });
-
- return;
+ cfg = {
+ tag : 'ul',
+ cls: 'roo-navigation-bar'
}
- this.fireEvent('positionchanged', this, location);
+ return cfg;
+
},
- resize: function()
+ onRender : function(ct, position)
{
- google.maps.event.trigger(this.gMapContext.map, "resize");
+ Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
- this.gMapContext.map.setCenter(this.gMapContext.marker.position);
+ if(this.bullets.length){
+ Roo.each(this.bullets, function(b){
+ this.addItem(b);
+ }, this);
+ }
- this.fireEvent('resize', this);
},
- setPositionByLatLng: function(latitude, longitude)
+ addItem : function(cfg)
{
- this.setPosition(new google.maps.LatLng(latitude, longitude));
+ var item = new Roo.bootstrap.NavProgressItem(cfg);
+
+ item.parentId = this.id;
+ item.render(this.el, null);
+
+ this.barItems.push(item);
+
+ this.formatBullets();
+
+ return item;
},
- getCurrentPosition: function()
+ getActive : function()
{
- return {
- latitude: this.gMapContext.location.lat(),
- longitude: this.gMapContext.location.lng()
- };
+ var active = false;
+
+ Roo.each(this.barItems, function(v){
+
+ if (!v.isActive()) {
+ return;
+ }
+
+ active = v;
+ return false;
+
+ });
+
+ return active;
},
- getAddressName: function()
+ setActiveItem : function(item)
{
- return this.gMapContext.locationName;
+ var prev = false;
+
+ Roo.each(this.barItems, function(v){
+ if (v.rid == item.rid) {
+ return ;
+ }
+
+ if (v.isActive()) {
+ v.setActive(false);
+ prev = v;
+ }
+ });
+
+ item.setActive(true);
+
+ this.fireEvent('changed', this, item, prev);
},
- getAddressComponents: function()
+ getBarItem: function(rid)
{
- return this.gMapContext.addressComponents;
+ var ret = false;
+
+ Roo.each(this.barItems, function(e) {
+ if (e.rid != rid) {
+ return;
+ }
+
+ ret = e;
+ return false;
+ });
+
+ return ret;
},
- address_component_from_google_geocode: function(address_components)
+ indexOfItem : function(item)
{
- var result = {};
+ var index = false;
- for (var i = 0; i < address_components.length; i++) {
- var component = address_components[i];
- if (component.types.indexOf("postal_code") >= 0) {
- result.postalCode = component.short_name;
- } else if (component.types.indexOf("street_number") >= 0) {
- result.streetNumber = component.short_name;
- } else if (component.types.indexOf("route") >= 0) {
- result.streetName = component.short_name;
- } else if (component.types.indexOf("neighborhood") >= 0) {
- result.city = component.short_name;
- } else if (component.types.indexOf("locality") >= 0) {
- result.city = component.short_name;
- } else if (component.types.indexOf("sublocality") >= 0) {
- result.district = component.short_name;
- } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
- result.stateOrProvince = component.short_name;
- } else if (component.types.indexOf("country") >= 0) {
- result.country = component.short_name;
+ Roo.each(this.barItems, function(v, i){
+
+ if (v.rid != item.rid) {
+ return;
}
- }
+
+ index = i;
+ return false
+ });
- result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
- result.addressLine2 = "";
- return result;
+ return index;
},
- setZoomLevel: function(zoom)
+ setActiveNext : function()
{
- this.gMapContext.map.setZoom(zoom);
+ var i = this.indexOfItem(this.getActive());
+
+ if (i > this.barItems.length) {
+ return;
+ }
+
+ this.setActiveItem(this.barItems[i+1]);
},
- show: function()
+ setActivePrev : function()
{
- if(!this.el){
+ var i = this.indexOfItem(this.getActive());
+
+ if (i < 1) {
return;
}
- this.el.show();
-
- this.resize();
-
- this.fireEvent('show', this);
+ this.setActiveItem(this.barItems[i-1]);
},
- hide: function()
+ formatBullets : function()
{
- if(!this.el){
+ if(!this.barItems.length){
return;
}
- this.el.hide();
+ var width = 100 / this.barItems.length;
- this.fireEvent('hide', this);
+ Roo.each(this.barItems, function(i){
+ i.el.setStyle('width', width + '%');
+ }, this);
}
});
-
-Roo.apply(Roo.bootstrap.LocationPicker, {
-
- OverlayView : function(map, options)
- {
- options = options || {};
-
- this.setMap(map);
- }
-
-
-});/*
+/*
* - LGPL
*
- * Alert
+ * Nav Progress Item
*
*/
/**
- * @class Roo.bootstrap.Alert
+ * @class Roo.bootstrap.NavProgressItem
* @extends Roo.bootstrap.Component
- * Bootstrap Alert class
- * @cfg {String} title The title of alert
- * @cfg {String} html The content of alert
- * @cfg {String} weight ( success | info | warning | danger )
- * @cfg {String} faicon font-awesomeicon
+ * Bootstrap NavProgressItem class
+ * @cfg {String} rid the reference id
+ * @cfg {Boolean} active (true|false) Is item active default false
+ * @cfg {Boolean} disabled (true|false) Is item active default false
+ * @cfg {String} html
+ * @cfg {String} position (top|bottom) text position default bottom
+ * @cfg {String} icon show icon instead of number
+ * @cfg {Boolean} forceIcon (true|false) true to force show icon..if set to false, Roo.isTouch showing icon, otherwish number
*
* @constructor
- * Create a new alert
+ * Create a new NavProgressItem
* @param {Object} config The config object
*/
-
-
-Roo.bootstrap.Alert = function(config){
- Roo.bootstrap.Alert.superclass.constructor.call(this, config);
-
+Roo.bootstrap.NavProgressItem = function(config){
+ Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
+ this.addEvents({
+ // raw events
+ /**
+ * @event click
+ * The raw click event for the entire grid.
+ * @param {Roo.bootstrap.NavProgressItem} this
+ * @param {Roo.EventObject} e
+ */
+ "click" : true
+ });
+
};
-Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
+Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
- title: '',
- html: '',
- weight: false,
- faicon: false,
+ rid : '',
+ active : false,
+ disabled : false,
+ html : '',
+ position : 'bottom',
+ icon : false,
+ forceIcon : false,
getAutoCreate : function()
{
+ var iconCls = 'roo-navigation-bar-item-icon';
+
+ if((this.forceIcon && this.icon) || !this.forceIcon && Roo.isTouch){
+ iconCls += ' ' + this.icon;
+ }
var cfg = {
- tag : 'div',
- cls : 'alert',
+ tag: 'li',
+ cls: 'roo-navigation-bar-item',
cn : [
{
tag : 'i',
- cls : 'roo-alert-icon'
-
- },
- {
- tag : 'b',
- cls : 'roo-alert-title',
- html : this.title
+ cls : iconCls
},
{
tag : 'span',
- cls : 'roo-alert-text',
+ cls : 'roo-navigation-bar-item-text ' + this.position,
html : this.html
}
]
- };
-
- if(this.faicon){
- cfg.cn[0].cls += ' fa ' + this.faicon;
}
- if(this.weight){
- cfg.cls += ' alert-' + this.weight;
+ if(this.active){
+ cfg.cls += ' active';
+ }
+ if(this.disabled){
+ cfg.cls += ' disabled';
}
return cfg;
},
- initEvents: function()
+ disable : function()
{
- this.el.setVisibilityMode(Roo.Element.DISPLAY);
+ this.setDisabled(true);
},
- setTitle : function(str)
+ enable : function()
{
- this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
+ this.setDisabled(false);
},
- setText : function(str)
+ initEvents: function()
{
- this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
+ this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
+ this.textEl = this.el.select('.roo-navigation-bar-item-text', true).first();
+
+ if(Roo.isTouch){
+ this.textEl.setVisibilityMode(Roo.Element.DISPLAY).hide();
+ }
+
+ this.iconEl.on('click', this.onClick, this);
+
},
- setWeight : function(weight)
+ onClick : function(e)
{
- if(this.weight){
- this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
+ e.preventDefault();
+
+ if(this.disabled){
+ return;
}
- this.weight = weight;
+ if(this.fireEvent('click', this, e) === false){
+ return;
+ };
- this.el.select('.alert',true).first().addClass('alert-' + this.weight);
+ this.parent().setActiveItem(this);
},
- setIcon : function(icon)
+ isActive: function ()
{
- if(this.faicon){
- this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
+ return this.active;
+ },
+
+ setActive : function(state)
+ {
+ if(this.active == state){
+ return;
}
- this.faicon = icon
+ this.active = state;
- this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
+ if (state) {
+ this.el.addClass('active');
+ return;
+ }
+
+ this.el.removeClass('active');
+
+ return;
},
- hide: function()
+ setDisabled : function(state)
{
- this.el.hide();
+ if(this.disabled == state){
+ return;
+ }
+
+ this.disabled = state;
+
+ if (state) {
+ this.el.addClass('disabled');
+ return;
+ }
+
+ this.el.removeClass('disabled');
},
- show: function()
- {
- this.el.show();
+ tooltipEl : function()
+ {
+ return this.el.select('.roo-navigation-bar-item-icon', true).first();;
}
-
});
+
\ No newline at end of file