// closure these in so they are only created once.
var alpha = /^[a-zA-Z_]+$/;
var alphanum = /^[a-zA-Z0-9_]+$/;
- var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
+ var email = /^([\w'-]+)(\.[\w'-]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
var url = /^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
var urlWeb = /^((https?):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
}
- this.el.removeClass([this.invalidClass, 'is-invalid']);
+ this.inputEl().removeClass([this.invalidClass, 'is-invalid']);
if(this.hasFeedback && this.inputType != 'hidden'){
});
-Roo.bootstrap.form.CardUploader.ID = -1;/*
+Roo.bootstrap.form.CardUploader.ID = -1;/**
+ *
+ * @class Roo.bootstrap.form.MultiLineTag
+ * @param {Object} config The config object
+ *
+ */
+
+Roo.bootstrap.form.MultiLineTag = function(config){
+ Roo.bootstrap.form.MultiLineTag.superclass.constructor.call(this, config);
+
+ this.addEvents({
+ /**
+ * @event beforeload
+ * Fires before a request is made for a new data object. If the beforeload handler returns false
+ * the load action will be canceled.
+ * @param {Roo.boostrap.form.MultiLineTag} this
+ * @param {Store} store
+ * @param {Object} options The loading options that were specified (see {@link #load} for details)
+ */
+ beforeload : true
+ });
+};
+
+Roo.extend(Roo.bootstrap.form.MultiLineTag, Roo.bootstrap.form.Input, {
+ tagRows : [],
+ minimumRow : 2,
+
+ // for combo box
+ displayField : '',
+ valueField : '',
+ placeholder : '',
+ queryParam : '',
+ listWidth : 300,
+ minChars : 2,
+
+ // for combo box store
+ url : undefined,
+ fields : [],
+
+
+
+ getAutoCreate : function()
+ {
+ var config = {
+ cls : 'roo-multi-line-tag form-group'
+ };
+
+ config = this.getAutoCreateLabel( config, {
+ cls : 'roo-multi-line-tag-container'
+ } );
+
+ return config;
+ },
+
+ initEvents : function()
+ {
+ this.tagRows = [];
+
+ for (var i = 0; i < this.minimumRow; i++) {
+ this.addTagRow();
+ }
+ },
+
+ addTagRow : function()
+ {
+ var _this = this;
+
+ var comboBox = Roo.factory({
+ xns: Roo.bootstrap.form,
+ xtype : 'ComboBox',
+ editable : true,
+ triggerAction: 'all',
+ minChars: _this.minChars,
+ displayField: _this.displayField,
+ valueField : _this.valueField,
+ listWidth: _this.listWidth,
+ placeholder : _this.placeholder,
+ queryParam : _this.queryParam,
+ store : {
+ xns : Roo.data,
+ xtype : 'Store',
+ listeners : {
+ beforeload : function(_self, options)
+ {
+ _this.fireEvent('beforeload', _this, _self, options);
+ }
+ },
+ proxy : {
+ xns : Roo.data,
+ xtype : 'HttpProxy',
+ method : 'GET',
+ url : _this.url
+ },
+ reader : {
+ xns : Roo.data,
+ xtype : 'JsonReader',
+ fields : _this.fields
+ }
+ },
+ listeners : {
+ 'render' : function (_self) {
+ _self.inputEl().on('keyup', function(e) {
+ if(_this.shouldAutoAddTagRow()) {
+ _this.addTagRow();
+ }
+ });
+ _self.inputEl().on('change', function(e) {
+ _this.fireEvent('change', _this, _this.getValue(), false);
+ _this.showHideRemoveBtn();
+
+ });
+ },
+ 'select' : function(_self, record, index) {
+ _this.fireEvent('change', _this, _this.getValue(), false);
+ }
+ }
+ });
+
+ var button = Roo.factory({
+ xns : Roo.bootstrap,
+ xtype : 'Button',
+ html : '-'
+ });
+
+ var row = {
+ xns : Roo.bootstrap,
+ xtype : 'Row',
+ items : [
+ comboBox,
+ button
+ ],
+ listeners : {
+ 'render' : function (_self) {
+ this.inputCb = comboBox;
+ this.removeBtn = button;
+
+ this.removeBtn.on('click', function() {
+ _this.removeTagRow(_self);
+ _this.fireEvent('change', _this, _this.getValue(), false);
+ });
+ }
+ }
+ };
+ this.tagRows.push(this.addxtype(row));
+
+ _this.showHideRemoveBtn();
+ },
+
+ // a new tags should be added automatically when all existing tags are not empty
+ shouldAutoAddTagRow : function()
+ {
+ var ret = true;
+
+ Roo.each(this.tagRows, function(r) {
+ if(r.inputCb.getRawValue() == '') {
+ ret = false;
+ }
+ });
+
+ return ret;
+ },
+
+ removeTagRow : function(row)
+ {
+ row.destroy();
+ this.tagRows.splice(this.tagRows.indexOf(row), 1);
+ this.showHideRemoveBtn();
+ },
+
+ // hide all remove buttons if there are {minimumRow} or less tags
+ // hide the remove button for empty tag
+ showHideRemoveBtn : function()
+ {
+ var _this = this;
+
+ Roo.each(this.tagRows, function (r) {
+
+ r.removeBtn.show();
+
+ if(_this.tagRows.length <= _this.minimumRow || r.inputCb.getRawValue() == '') {
+ r.removeBtn.hide();
+ }
+ });
+ },
+
+ getValue : function()
+ {
+ var _this = this;
+ var tags = [];
+ Roo.each(_this.tagRows, function(r) {
+ var value = r.inputCb.getRawValue();
+ if(value != '') {
+ var tag = {};
+ tag[_this.valueField] = r.inputCb.getRawValue();
+ tags.push(tag);
+ }
+ });
+
+ return JSON.stringify(tags);
+ },
+
+ setValue : function(json)
+ {
+
+ // remove all old tags
+ var oldTotal = this.tagRows.length;
+
+ for(var i = 0; i < oldTotal; i ++) {
+ this.removeTagRow(this.tagRows[0]);
+ }
+
+ // empty tag if invalid json
+ var arr = [];
+
+ try {
+ // set new tags
+ arr = JSON.parse(json);
+ }
+ catch {}
+
+ for (var i = 0; i < arr.length; i ++) {
+ this.addTagRow();
+ this.tagRows[i].inputCb.setRawValue(arr[i][this.valueField]);
+ }
+
+ // always add one extra empty tag
+ this.addTagRow();
+
+ // add empty tags until there are {minimumRow} tags
+ while(this.tagRows.length < this.minimumRow) {
+ this.addTagRow();
+ }
+
+ },
+
+ getChildContainer : function()
+ {
+ return Roo.select('.roo-multi-line-tag-container', true).elements[0];
+ }
+});/*
* Based on:
* Ext JS Library 1.1.1
* Copyright(c) 2006-2007, Ext JS, LLC.
/**
* @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
*/
- maxHeight: 300,
+ // maxHeight: 300, // not used (change maxHeight in CSS. target the list using listClass)
/**
* @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
* query specified by the allQuery config option (defaults to 'query')
//this.list = new Roo.Layer({
// shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
//});
+
+ this.list.addClass(this.listClass);
var _this = this;
if (!this.editable) {
Roo.get(document).on('keydown', this.listKeyPress, this);
}
+
+ this.list.setStyle('maxHeight', 'calc(100% - ' + this.list.getTop() + 'px - 50px)');
this.fireEvent('expand', this);
},
this.picker().hide();
this.viewMode = this.startViewMode;
this.showMode();
+
+ this.inputEl().blur();
this.fireEvent('hidepopup', this, this.date);
{
this.picker().hide();
this.pop.hide();
+
+ this.inputEl().blur();
this.fireEvent('hide', this, this.time);
},
}
node.parentNode.removeChild(node);
+ },
+
+ searchTag : function(dom)
+ {
+ if(this.tag === false) {
+ return;
+ }
+
+ var els = dom.getElementsByTagName(this.tag);
+
+ Roo.each(Array.from(els), function(e){
+ if(e.parentNode == null) {
+ return;
+ }
+ if(this.replaceTag) {
+ this.replaceTag(e);
+ }
+ }, this);
}
};
Roo.htmleditor.FilterParagraph = function(cfg)
{
// no need to apply config.
- this.walk(cfg.node);
+ this.searchTag(cfg.node);
}
Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
return false; // no need to walk..
}
+
var ar = Array.from(node.childNodes);
for (var i = 0; i < ar.length; i++) {
node.removeChild(ar[i]);
}
});/**
+ * @class Roo.htmleditor.FilterHashLink
+ * remove hash link
+ * @constructor
+ * Run a new Hash Link Filter
+ * @param {Object} config Configuration options
+ */
+
+ Roo.htmleditor.FilterHashLink = function(cfg)
+ {
+ // no need to apply config.
+ // this.walk(cfg.node);
+ this.searchTag(cfg.node);
+ }
+
+ Roo.extend(Roo.htmleditor.FilterHashLink, Roo.htmleditor.Filter,
+ {
+
+ tag : 'A',
+
+
+ replaceTag : function(node)
+ {
+ for(var i = 0; i < node.attributes.length; i ++) {
+ var a = node.attributes[i];
+
+ if(a.name.toLowerCase() == 'href' && a.value.startsWith('#')) {
+ this.removeNodeKeepChildren(node);
+ }
+ }
+
+ return false;
+
+ }
+
+ });/**
* @class Roo.htmleditor.FilterSpan
* filter span's with no attributes out..
* @constructor
Roo.htmleditor.FilterSpan = function(cfg)
{
// no need to apply config.
- this.walk(cfg.node);
+ this.searchTag(cfg.node);
}
Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
Roo.htmleditor.FilterLongBr = function(cfg)
{
// no need to apply config.
- this.walk(cfg.node);
+ this.searchTag(cfg.node);
}
Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
-
-
if (!node.previousSibling) {
return false;
}
]
};
}
- // we remove caption totally if its hidden... - will delete data.. but otherwise we end up with fake caption
- var captionhtml = this.caption_display == 'none' ? '' : (this.caption.length ? this.caption : "Caption");
-
+
+
var ret = {
tag: 'figure',
'data-block' : 'Figure',
'data-width' : this.width,
'data-caption' : this.caption,
+ 'data-caption-display' : this.caption_display,
contenteditable : 'false',
style : {
textAlign : this.align // seems to work for email..
},
-
align : this.align,
cn : [
- img,
-
- {
- tag: 'figcaption',
- 'data-display' : this.caption_display,
- style : {
- textAlign : 'left',
- fontSize : '16px',
- lineHeight : '24px',
- display : this.caption_display,
- maxWidth : (this.align == 'center' ? this.width : '100%' ) + ' !important',
- margin: m,
- width: this.align == 'center' ? this.width : '100%'
-
-
- },
- cls : this.cls.length > 0 ? (this.cls + '-thumbnail' ) : '',
- cn : [
- {
- tag: 'div',
- style : {
- marginTop : '16px',
- textAlign : 'left'
- },
- align: 'left',
- cn : [
- {
- // we can not rely on yahoo syndication to use CSS elements - so have to use '<i>' to encase stuff.
- tag : 'i',
- contenteditable : true,
- html : captionhtml
- }
-
- ]
- }
-
- ]
-
- }
+ img
]
};
+
+ // show figcaption only if caption_display is 'block'
+ if(this.caption_display == 'block') {
+ ret['cn'].push({
+ tag: 'figcaption',
+ style : {
+ textAlign : 'left',
+ fontSize : '16px',
+ lineHeight : '24px',
+ display : this.caption_display,
+ maxWidth : (this.align == 'center' ? this.width : '100%' ) + ' !important',
+ margin: m,
+ width: this.align == 'center' ? this.width : '100%'
+
+
+ },
+ cls : this.cls.length > 0 ? (this.cls + '-thumbnail' ) : '',
+ cn : [
+ {
+ tag: 'div',
+ style : {
+ marginTop : '16px',
+ textAlign : 'start'
+ },
+ align: 'left',
+ cn : [
+ {
+ // we can not rely on yahoo syndication to use CSS elements - so have to use '<i>' to encase stuff.
+ tag : 'i',
+ contenteditable : Roo.htmleditor.BlockFigure.caption_edit,
+ html : this.caption.length ? this.caption : "Caption" // fake caption
+ }
+
+ ]
+ }
+
+ ]
+
+ });
+ }
return ret;
},
this.image_src = this.getVal(node, 'img', 'src');
this.align = this.getVal(node, 'figure', 'align');
-
- /// not really used - as hidden captions do not store the content here..
+
+ // caption display is stored in figure
+ this.caption_display = this.getVal(node, true, 'data-caption-display');
+
+ // backward compatible
+ // it was stored in figcaption
+ if(this.caption_display == '') {
+ this.caption_display = this.getVal(node, 'figcaption', 'data-display');
+ }
+
+ // read caption from figcaption
var figcaption = this.getVal(node, 'figcaption', false);
+
if (figcaption !== '') {
this.caption = this.getVal(figcaption, 'i', 'html');
}
-
+
- this.caption_display = this.getVal(node, 'figcaption', 'data-display');
+ // read caption from data-caption in figure if no caption from figcaption
var dc = this.getVal(node, true, 'data-caption');
- if (dc && dc.length) {
+
+ if(this.caption_display == 'none' && dc && dc.length){
this.caption = dc;
}
+
//this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
this.width = this.getVal(node, true, 'data-width');
//this.margin = this.getVal(node, 'figure', 'style', 'margin');
-})
+});
+
+Roo.apply(Roo.htmleditor.BlockFigure, {
+ caption_edit : true
+});
'colspan',
'rowspan',
'data-display',
+ 'data-caption-display',
'data-width',
'data-caption',
'start' ,
new Roo.htmleditor.FilterStyleToTag({ node : d });
new Roo.htmleditor.FilterAttributes({
node : d,
- attrib_white : ['href', 'src', 'name', 'align', 'colspan', 'rowspan', 'data-display', 'data-width', 'start'],
+ attrib_white : [
+ 'href',
+ 'src',
+ 'name',
+ 'align',
+ 'colspan',
+ 'rowspan'
+ /* THESE ARE NOT ALLWOED FOR PASTE
+ * 'data-display',
+ 'data-caption-display',
+ 'data-width',
+ 'data-caption',
+ 'start' ,
+ 'style',
+ // youtube embed.
+ 'class',
+ 'allowfullscreen',
+ 'frameborder',
+ 'width',
+ 'height',
+ 'alt'
+ */
+ ],
attrib_clean : ['href', 'src' ]
});
new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
// should be fonts..
new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT', ':' ]} );
new Roo.htmleditor.FilterParagraph({ node : d });
+ new Roo.htmleditor.FilterHashLink({node : d});
new Roo.htmleditor.FilterSpan({ node : d });
new Roo.htmleditor.FilterLongBr({ node : d });
new Roo.htmleditor.FilterComment({ node : d });