From: Alan Knowles Date: Fri, 30 Jul 2021 07:09:46 +0000 (+0800) Subject: MOVED Roo/bootstrap/TriggerField.js to Roo/bootstrap/form/TriggerField.js X-Git-Url: http://git.roojs.org/?p=roojs1;a=commitdiff_plain;h=0402519584faf1cafc1ef4ecd94f9e424fd3984d MOVED Roo/bootstrap/TriggerField.js to Roo/bootstrap/form/TriggerField.js MOVED Roo/bootstrap/TextArea.js to Roo/bootstrap/form/TextArea.js Roo/bootstrap/TriggerField.js Roo/bootstrap/TextArea.js MOVED Roo/bootstrap/TimeField.js to Roo/bootstrap/form/TimeField.js Roo/bootstrap/TimeField.js MOVED Roo/bootstrap/SecurePass.js to Roo/bootstrap/form/SecurePass.js Roo/bootstrap/SecurePass.js --- diff --git a/Roo/bootstrap/form/SecurePass.js b/Roo/bootstrap/form/SecurePass.js new file mode 100644 index 0000000000..bbb84ca8d1 --- /dev/null +++ b/Roo/bootstrap/form/SecurePass.js @@ -0,0 +1,354 @@ +/* + * - LGPL + * + * Input + * + */ + +/** + * @class Roo.bootstrap.SecurePass + * @extends Roo.bootstrap.Input + * Bootstrap SecurePass class + * + * + * @constructor + * Create a new SecurePass + * @param {Object} config The config object + */ + +Roo.bootstrap.SecurePass = function (config) { + // these go here, so the translation tool can replace them.. + this.errors = { + PwdEmpty: "Please type a password, and then retype it to confirm.", + PwdShort: "Your password must be at least 6 characters long. Please type a different password.", + PwdLong: "Your password can't contain more than 16 characters. Please type a different password.", + PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.", + IDInPwd: "Your password can't include the part of your ID. Please type a different password.", + FNInPwd: "Your password can't contain your first name. Please type a different password.", + LNInPwd: "Your password can't contain your last name. Please type a different password.", + TooWeak: "Your password is Too Weak." + }, + this.meterLabel = "Password strength:"; + this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"]; + this.meterClass = [ + "roo-password-meter-tooweak", + "roo-password-meter-weak", + "roo-password-meter-medium", + "roo-password-meter-strong", + "roo-password-meter-grey" + ]; + + this.errors = {}; + + Roo.bootstrap.SecurePass.superclass.constructor.call(this, config); +} + +Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, { + /** + * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to + * { + * PwdEmpty: "Please type a password, and then retype it to confirm.", + * PwdShort: "Your password must be at least 6 characters long. Please type a different password.", + * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.", + * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.", + * IDInPwd: "Your password can't include the part of your ID. Please type a different password.", + * FNInPwd: "Your password can't contain your first name. Please type a different password.", + * LNInPwd: "Your password can't contain your last name. Please type a different password." + * }) + */ + // private + + meterWidth: 300, + errorMsg :'', + errors: false, + imageRoot: '/', + /** + * @cfg {String/Object} Label for the strength meter (defaults to + * 'Password strength:') + */ + // private + meterLabel: '', + /** + * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to + * ['Weak', 'Medium', 'Strong']) + */ + // private + pwdStrengths: false, + // private + strength: 0, + // private + _lastPwd: null, + // private + kCapitalLetter: 0, + kSmallLetter: 1, + kDigit: 2, + kPunctuation: 3, + + insecure: false, + // private + initEvents: function () + { + Roo.bootstrap.SecurePass.superclass.initEvents.call(this); + + if (this.el.is('input[type=password]') && Roo.isSafari) { + this.el.on('keydown', this.SafariOnKeyDown, this); + } + + this.el.on('keyup', this.checkStrength, this, {buffer: 50}); + }, + // private + onRender: function (ct, position) + { + Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position); + this.wrap = this.el.wrap({cls: 'x-form-field-wrap'}); + this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass}); + + this.trigger.createChild({ + cn: [ + { + //id: 'PwdMeter', + tag: 'div', + cls: 'roo-password-meter-grey col-xs-12', + style: { + //width: 0, + //width: this.meterWidth + 'px' + } + }, + { + cls: 'roo-password-meter-text' + } + ] + }); + + + if (this.hideTrigger) { + this.trigger.setDisplayed(false); + } + this.setSize(this.width || '', this.height || ''); + }, + // private + onDestroy: function () + { + if (this.trigger) { + this.trigger.removeAllListeners(); + this.trigger.remove(); + } + if (this.wrap) { + this.wrap.remove(); + } + Roo.bootstrap.TriggerField.superclass.onDestroy.call(this); + }, + // private + checkStrength: function () + { + var pwd = this.inputEl().getValue(); + if (pwd == this._lastPwd) { + return; + } + + var strength; + if (this.ClientSideStrongPassword(pwd)) { + strength = 3; + } else if (this.ClientSideMediumPassword(pwd)) { + strength = 2; + } else if (this.ClientSideWeakPassword(pwd)) { + strength = 1; + } else { + strength = 0; + } + + Roo.log('strength1: ' + strength); + + //var pm = this.trigger.child('div/div/div').dom; + var pm = this.trigger.child('div/div'); + pm.removeClass(this.meterClass); + pm.addClass(this.meterClass[strength]); + + + var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom; + + pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength]; + + this._lastPwd = pwd; + }, + reset: function () + { + Roo.bootstrap.SecurePass.superclass.reset.call(this); + + this._lastPwd = ''; + + var pm = this.trigger.child('div/div'); + pm.removeClass(this.meterClass); + pm.addClass('roo-password-meter-grey'); + + + var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom; + + pt.innerHTML = ''; + this.inputEl().dom.type='password'; + }, + // private + validateValue: function (value) + { + if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) { + return false; + } + if (value.length == 0) { + if (this.allowBlank) { + this.clearInvalid(); + return true; + } + + this.markInvalid(this.errors.PwdEmpty); + this.errorMsg = this.errors.PwdEmpty; + return false; + } + + if(this.insecure){ + return true; + } + + if (!value.match(/[\x21-\x7e]+/)) { + this.markInvalid(this.errors.PwdBadChar); + this.errorMsg = this.errors.PwdBadChar; + return false; + } + if (value.length < 6) { + this.markInvalid(this.errors.PwdShort); + this.errorMsg = this.errors.PwdShort; + return false; + } + if (value.length > 16) { + this.markInvalid(this.errors.PwdLong); + this.errorMsg = this.errors.PwdLong; + return false; + } + var strength; + if (this.ClientSideStrongPassword(value)) { + strength = 3; + } else if (this.ClientSideMediumPassword(value)) { + strength = 2; + } else if (this.ClientSideWeakPassword(value)) { + strength = 1; + } else { + strength = 0; + } + + + if (strength < 2) { + //this.markInvalid(this.errors.TooWeak); + this.errorMsg = this.errors.TooWeak; + //return false; + } + + + console.log('strength2: ' + strength); + + //var pm = this.trigger.child('div/div/div').dom; + + var pm = this.trigger.child('div/div'); + pm.removeClass(this.meterClass); + pm.addClass(this.meterClass[strength]); + + var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom; + + pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength]; + + this.errorMsg = ''; + return true; + }, + // private + CharacterSetChecks: function (type) + { + this.type = type; + this.fResult = false; + }, + // private + isctype: function (character, type) + { + switch (type) { + case this.kCapitalLetter: + if (character >= 'A' && character <= 'Z') { + return true; + } + break; + + case this.kSmallLetter: + if (character >= 'a' && character <= 'z') { + return true; + } + break; + + case this.kDigit: + if (character >= '0' && character <= '9') { + return true; + } + break; + + case this.kPunctuation: + if ('!@#$%^&*()_+-=\'";:[{]}|.>,= 0) { + return true; + } + break; + + default: + return false; + } + + }, + // private + IsLongEnough: function (pwd, size) + { + return !(pwd == null || isNaN(size) || pwd.length < size); + }, + // private + SpansEnoughCharacterSets: function (word, nb) + { + if (!this.IsLongEnough(word, nb)) + { + return false; + } + + var characterSetChecks = new Array( + new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter), + new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation) + ); + + for (var index = 0; index < word.length; ++index) { + for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) { + if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) { + characterSetChecks[nCharSet].fResult = true; + break; + } + } + } + + var nCharSets = 0; + for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) { + if (characterSetChecks[nCharSet].fResult) { + ++nCharSets; + } + } + + if (nCharSets < nb) { + return false; + } + return true; + }, + // private + ClientSideStrongPassword: function (pwd) + { + return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3); + }, + // private + ClientSideMediumPassword: function (pwd) + { + return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2); + }, + // private + ClientSideWeakPassword: function (pwd) + { + return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0); + } + +}) \ No newline at end of file diff --git a/Roo/bootstrap/form/TextArea.js b/Roo/bootstrap/form/TextArea.js new file mode 100644 index 0000000000..3eb51d9c30 --- /dev/null +++ b/Roo/bootstrap/form/TextArea.js @@ -0,0 +1,369 @@ +/* + * - LGPL + * + * Input + * + */ + +/** + * @class Roo.bootstrap.TextArea + * @extends Roo.bootstrap.Input + * Bootstrap TextArea class + * @cfg {Number} cols Specifies the visible width of a text area + * @cfg {Number} rows Specifies the visible number of lines in a text area + * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form + * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial) + * @cfg {string} html text + * + * @constructor + * Create a new TextArea + * @param {Object} config The config object + */ + +Roo.bootstrap.TextArea = function(config){ + Roo.bootstrap.TextArea.superclass.constructor.call(this, config); + +}; + +Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, { + + cols : false, + rows : 5, + readOnly : false, + warp : 'soft', + resize : false, + value: false, + html: false, + + getAutoCreate : function(){ + + var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign; + + var id = Roo.id(); + + var cfg = {}; + + if(this.inputType != 'hidden'){ + cfg.cls = 'form-group' //input-group + } + + var input = { + tag: 'textarea', + id : id, + warp : this.warp, + rows : this.rows, + value : this.value || '', + html: this.html || '', + cls : 'form-control', + placeholder : this.placeholder || '' + + }; + + if(this.maxLength && this.maxLength != Number.MAX_VALUE){ + input.maxLength = this.maxLength; + } + + if(this.resize){ + input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize; + } + + if(this.cols){ + input.cols = this.cols; + } + + if (this.readOnly) { + input.readonly = true; + } + + if (this.name) { + input.name = this.name; + } + + if (this.size) { + input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size; + } + + var settings=this; + ['xs','sm','md','lg'].map(function(size){ + if (settings[size]) { + cfg.cls += ' col-' + size + '-' + settings[size]; + } + }); + + var inputblock = input; + + if(this.hasFeedback && !this.allowBlank){ + + var feedback = { + tag: 'span', + cls: 'glyphicon form-control-feedback' + }; + + inputblock = { + cls : 'has-feedback', + cn : [ + input, + feedback + ] + }; + } + + + 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.hasFeedback && !this.allowBlank){ + inputblock.cls += ' has-feedback'; + inputblock.cn.push(feedback); + } + + if (this.after) { + inputblock.cn.push({ + tag :'span', + cls : 'input-group-addon', + html : this.after + }); + } + + } + + if (align ==='left' && this.fieldLabel.length) { + cfg.cn = [ + { + tag: 'label', + 'for' : id, + cls : 'control-label', + html : this.fieldLabel + }, + { + cls : "", + cn: [ + inputblock + ] + } + + ]; + + if(this.labelWidth > 12){ + cfg.cn[0].style = "width: " + this.labelWidth + 'px'; + } + + if(this.labelWidth < 13 && this.labelmd == 0){ + this.labelmd = this.labelWidth; + } + + if(this.labellg > 0){ + cfg.cn[0].cls += ' col-lg-' + this.labellg; + cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg); + } + + if(this.labelmd > 0){ + cfg.cn[0].cls += ' col-md-' + this.labelmd; + cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd); + } + + if(this.labelsm > 0){ + cfg.cn[0].cls += ' col-sm-' + this.labelsm; + cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm); + } + + if(this.labelxs > 0){ + cfg.cn[0].cls += ' col-xs-' + this.labelxs; + cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs); + } + + } else if ( this.fieldLabel.length) { + cfg.cn = [ + + { + tag: 'label', + //cls : 'input-group-addon', + html : this.fieldLabel + + }, + + inputblock + + ]; + + } else { + + cfg.cn = [ + + inputblock + + ]; + + } + + if (this.disabled) { + input.disabled=true; + } + + return cfg; + + }, + /** + * return the real textarea element. + */ + inputEl: function () + { + return this.el.select('textarea.form-control',true).first(); + }, + + /** + * Clear any invalid styles/messages for this field + */ + clearInvalid : function() + { + + if(!this.el || this.preventMark){ // not rendered + return; + } + + var label = this.el.select('label', true).first(); + var icon = this.el.select('i.fa-star', true).first(); + + if(label && icon){ + icon.remove(); + } + this.el.removeClass( this.validClass); + this.inputEl().removeClass('is-invalid'); + + if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){ + + var feedback = this.el.select('.form-control-feedback', true).first(); + + if(feedback){ + this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass); + } + + } + + this.fireEvent('valid', this); + }, + + /** + * Mark this field as valid + */ + markValid : function() + { + if(!this.el || this.preventMark){ // not rendered + return; + } + + this.el.removeClass([this.invalidClass, this.validClass]); + this.inputEl().removeClass(['is-valid', 'is-invalid']); + + 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; + } + + var label = this.el.select('label', true).first(); + var icon = this.el.select('i.fa-star', true).first(); + + if(label && icon){ + icon.remove(); + } + if (Roo.bootstrap.version == 3) { + this.el.addClass(this.validClass); + } else { + this.inputEl().addClass('is-valid'); + } + + + if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){ + + 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]); + this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]); + } + + } + + this.fireEvent('valid', this); + }, + + /** + * Mark this field as invalid + * @param {String} msg The validation message + */ + markInvalid : function(msg) + { + if(!this.el || this.preventMark){ // not rendered + return; + } + + this.el.removeClass([this.invalidClass, this.validClass]); + this.inputEl().removeClass(['is-valid', 'is-invalid']); + + 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; + } + + var label = this.el.select('label', true).first(); + var icon = this.el.select('i.fa-star', true).first(); + + if(!this.getValue().length && label && !icon){ + this.el.createChild({ + tag : 'i', + cls : 'text-danger fa fa-lg fa-star', + tooltip : 'This field is required', + style : 'margin-right:5px;' + }, label, true); + } + + if (Roo.bootstrap.version == 3) { + this.el.addClass(this.invalidClass); + } else { + this.inputEl().addClass('is-invalid'); + } + + // fixme ... this may be depricated need to test.. + if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){ + + 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.getValue().length || this.forceFeedback){ + this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]); + } + + } + + } + + this.fireEvent('invalid', this, msg); + } +}); + + diff --git a/Roo/bootstrap/form/TimeField.js b/Roo/bootstrap/form/TimeField.js new file mode 100644 index 0000000000..b258728282 --- /dev/null +++ b/Roo/bootstrap/form/TimeField.js @@ -0,0 +1,517 @@ +/* + * - LGPL + * + * TimeField + * + */ + +/** + * @class Roo.bootstrap.TimeField + * @extends Roo.bootstrap.Input + * Bootstrap DateField class + * + * + * @constructor + * Create a new TimeField + * @param {Object} config The config object + */ + +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.TimeField, Roo.bootstrap.Input, { + + /** + * @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", + + getAutoCreate : function() + { + this.after = ''; + return Roo.bootstrap.TimeField.superclass.getAutoCreate.call(this); + + + }, + onRender: function(ct, position) + { + + Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position); + + this.pickerEl = Roo.get(document.body).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'); + + this.fillTime(); + this.update(); + + this.pop.select('.hours-up', true).first().on('click', this.onIncrementHours, this); + this.pop.select('.hours-down', true).first().on('click', this.onDecrementHours, this); + this.pop.select('.minutes-up', true).first().on('click', this.onIncrementMinutes, this); + this.pop.select('.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); + + }, + + 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; + } + }, + + onClick: function(e) { + e.stopPropagation(); + e.preventDefault(); + }, + + picker : function() + { + return this.pickerEl; + }, + + 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: 'i', + cls: 'hours-up fa fas fa-chevron-up' + } + ] + } + ] + }, + { + tag: 'td', + cls: 'separator' + }, + { + tag: 'td', + cn: [ + { + tag: 'a', + href: '#', + cls: 'btn', + cn: [ + { + tag: 'i', + cls: 'minutes-up fa fas fa-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 fa fas fa-chevron-down' + } + ] + } + ] + }, + { + tag: 'td', + cls: 'separator' + }, + { + tag: 'td', + cn: [ + { + tag: 'a', + href: '#', + cls: 'btn', + cn: [ + { + tag: 'span', + cls: 'minutes-down fa fas fa-chevron-down' + } + ] + } + ] + }, + { + tag: 'td', + cls: 'separator' + } + ] + }); + + }, + + update: function() + { + + this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time; + + this.fill(); + }, + + fill: function() + { + var hours = this.time.getHours(); + var minutes = this.time.getMinutes(); + var period = 'AM'; + + if(hours > 11){ + period = 'PM'; + } + + if(hours == 0){ + hours = 12; + } + + + if(hours > 12){ + hours = hours - 12; + } + + if(hours < 10){ + hours = '0' + hours; + } + + 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; + + }, + + place: function() + { + this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']); + + 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'); + } + + 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.picker().setXY(20000,20000); + this.picker().addClass(cls.join('-')); + + var _this = this; + + Roo.each(cls, function(c){ + if(c == 'bottom'){ + (function() { + // + }).defer(200); + _this.picker().alignTo(_this.inputEl(), "tr-br", [0, 10], false); + //_this.picker().setTop(_this.inputEl().getHeight()); + return; + } + if(c == 'top'){ + _this.picker().alignTo(_this.inputEl(), "br-tr", [0, 10], false); + + //_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(); + }, + + onBlur : function() + { + Roo.bootstrap.TimeField.superclass.onBlur.call(this); + this.hide(); + }, + + show : function() + { + this.picker().show(); + this.pop.show(); + this.update(); + this.place(); + + this.fireEvent('show', this, this.date); + }, + + hide : function() + { + this.picker().hide(); + this.pop.hide(); + + this.fireEvent('hide', this, this.date); + }, + + setTime : function() + { + this.hide(); + this.setValue(this.time.format(this.format)); + + this.fireEvent('select', this, this.date); + + + }, + + 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.TimeField, { + + template : { + tag: 'div', + cls: 'datepicker dropdown-menu', + cn: [ + { + tag: 'div', + cls: 'datepicker-time', + cn: [ + { + tag: 'table', + cls: 'table-condensed', + cn:[ + { + tag: 'tbody', + cn: [ + { + tag: 'tr', + cn: [ + { + tag: 'td', + colspan: '7' + } + ] + } + ] + }, + { + tag: 'tfoot', + cn: [ + { + tag: 'tr', + cn: [ + { + tag: 'th', + colspan: '7', + cls: '', + cn: [ + { + tag: 'button', + cls: 'btn btn-info ok', + html: 'OK' + } + ] + } + + ] + } + ] + } + ] + } + ] + } + ] + } +}); + + + + \ No newline at end of file diff --git a/Roo/bootstrap/form/TriggerField.js b/Roo/bootstrap/form/TriggerField.js new file mode 100644 index 0000000000..73731e487d --- /dev/null +++ b/Roo/bootstrap/form/TriggerField.js @@ -0,0 +1,606 @@ +/* + * - LGPL + * + * trigger field - base class for combo.. + * + */ + +/** + * @class Roo.bootstrap.TriggerField + * @extends Roo.bootstrap.Input + * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default). + * The trigger has no default action, so you must assign a function to implement the trigger click handler by + * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox + * for which you can provide a custom implementation. For example: + *

+var trigger = new Roo.bootstrap.TriggerField();
+trigger.onTriggerClick = myTriggerFn;
+trigger.applyTo('my-field');
+
+ * + * However, in general you will most likely want to use TriggerField as the base class for a reusable component. + * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this. + * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the + * class 'x-form-trigger' by default and triggerClass will be appended if specified. + * @cfg {String} caret (search|calendar) BS3 only - carat fa name + + * @constructor + * Create a new TriggerField. + * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied + * to the base TextField) + */ +Roo.bootstrap.TriggerField = function(config){ + this.mimicing = false; + Roo.bootstrap.TriggerField.superclass.constructor.call(this, config); +}; + +Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, { + /** + * @cfg {String} triggerClass A CSS class to apply to the trigger + */ + /** + * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false) + */ + hideTrigger:false, + + /** + * @cfg {Boolean} removable (true|false) special filter default false + */ + removable : false, + + /** @cfg {Boolean} grow @hide */ + /** @cfg {Number} growMin @hide */ + /** @cfg {Number} growMax @hide */ + + /** + * @hide + * @method + */ + autoSize: Roo.emptyFn, + // private + monitorTab : true, + // private + deferHeight : true, + + + actionMode : 'wrap', + + caret : false, + + + getAutoCreate : function(){ + + var align = this.labelAlign || this.parentLabelAlign(); + + var id = Roo.id(); + + var cfg = { + cls: 'form-group' //input-group + }; + + + var input = { + tag: 'input', + id : id, + type : this.inputType, + cls : 'form-control', + autocomplete: 'new-password', + placeholder : this.placeholder || '' + + }; + if (this.name) { + input.name = this.name; + } + if (this.size) { + input.cls += ' input-' + this.size; + } + + if (this.disabled) { + input.disabled=true; + } + + var inputblock = input; + + if(this.hasFeedback && !this.allowBlank){ + + var feedback = { + tag: 'span', + cls: 'glyphicon form-control-feedback' + }; + + if(this.removable && !this.editable ){ + inputblock = { + cls : 'has-feedback', + cn : [ + inputblock, + { + tag: 'button', + html : 'x', + cls : 'roo-combo-removable-btn close' + }, + feedback + ] + }; + } else { + inputblock = { + cls : 'has-feedback', + cn : [ + inputblock, + feedback + ] + }; + } + + } else { + if(this.removable && !this.editable ){ + inputblock = { + cls : 'roo-removable', + cn : [ + inputblock, + { + tag: 'button', + html : 'x', + cls : 'roo-combo-removable-btn close' + } + ] + }; + } + } + + if (this.before || this.after) { + + inputblock = { + cls : 'input-group', + cn : [] + }; + if (this.before) { + inputblock.cn.push({ + tag :'span', + cls : 'input-group-addon input-group-prepend input-group-text', + html : this.before + }); + } + + inputblock.cn.push(input); + + if(this.hasFeedback && !this.allowBlank){ + inputblock.cls += ' has-feedback'; + inputblock.cn.push(feedback); + } + + if (this.after) { + inputblock.cn.push({ + tag :'span', + cls : 'input-group-addon input-group-append input-group-text', + html : this.after + }); + } + + }; + + + + var ibwrap = inputblock; + + if(this.multiple){ + ibwrap = { + tag: 'ul', + cls: 'roo-select2-choices', + cn:[ + { + tag: 'li', + cls: 'roo-select2-search-field', + cn: [ + + inputblock + ] + } + ] + }; + + } + + var combobox = { + cls: 'roo-select2-container input-group', + cn: [ + { + tag: 'input', + type : 'hidden', + cls: 'form-hidden-field' + }, + ibwrap + ] + }; + + if(!this.multiple && this.showToggleBtn){ + + var caret = { + tag: 'span', + cls: 'caret' + }; + if (this.caret != false) { + caret = { + tag: 'i', + cls: 'fa fa-' + this.caret + }; + + } + + combobox.cn.push({ + tag :'span', + cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle', + cn : [ + Roo.bootstrap.version == 3 ? caret : '', + { + tag: 'span', + cls: 'combobox-clear', + cn : [ + { + tag : 'i', + cls: 'icon-remove' + } + ] + } + ] + + }) + } + + if(this.multiple){ + combobox.cls += ' roo-select2-container-multi'; + } + var indicator = { + tag : 'i', + cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star', + tooltip : 'This field is required' + }; + if (Roo.bootstrap.version == 4) { + indicator = { + tag : 'i', + style : 'display:none' + }; + } + + + if (align ==='left' && this.fieldLabel.length) { + + cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : ''); + + cfg.cn = [ + indicator, + { + tag: 'label', + 'for' : id, + cls : 'control-label', + html : this.fieldLabel + + }, + { + cls : "", + cn: [ + combobox + ] + } + + ]; + + var labelCfg = cfg.cn[1]; + var contentCfg = cfg.cn[2]; + + if(this.indicatorpos == 'right'){ + cfg.cn = [ + { + tag: 'label', + 'for' : id, + cls : 'control-label', + cn : [ + { + tag : 'span', + html : this.fieldLabel + }, + indicator + ] + }, + { + cls : "", + cn: [ + combobox + ] + } + + ]; + + labelCfg = cfg.cn[0]; + contentCfg = cfg.cn[1]; + } + + if(this.labelWidth > 12){ + labelCfg.style = "width: " + this.labelWidth + 'px'; + } + + if(this.labelWidth < 13 && this.labelmd == 0){ + this.labelmd = this.labelWidth; + } + + if(this.labellg > 0){ + labelCfg.cls += ' col-lg-' + this.labellg; + contentCfg.cls += ' col-lg-' + (12 - this.labellg); + } + + if(this.labelmd > 0){ + labelCfg.cls += ' col-md-' + this.labelmd; + contentCfg.cls += ' col-md-' + (12 - this.labelmd); + } + + if(this.labelsm > 0){ + labelCfg.cls += ' col-sm-' + this.labelsm; + contentCfg.cls += ' col-sm-' + (12 - this.labelsm); + } + + if(this.labelxs > 0){ + labelCfg.cls += ' col-xs-' + this.labelxs; + contentCfg.cls += ' col-xs-' + (12 - this.labelxs); + } + + } else if ( this.fieldLabel.length) { +// Roo.log(" label"); + cfg.cn = [ + indicator, + { + tag: 'label', + //cls : 'input-group-addon', + html : this.fieldLabel + + }, + + combobox + + ]; + + if(this.indicatorpos == 'right'){ + + cfg.cn = [ + { + tag: 'label', + cn : [ + { + tag : 'span', + html : this.fieldLabel + }, + indicator + ] + + }, + combobox + + ]; + + } + + } else { + +// Roo.log(" no label && no align"); + cfg = combobox + + + } + + var settings=this; + ['xs','sm','md','lg'].map(function(size){ + if (settings[size]) { + cfg.cls += ' col-' + size + '-' + settings[size]; + } + }); + + return cfg; + + }, + + + + // private + onResize : function(w, h){ +// Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments); +// if(typeof w == 'number'){ +// var x = w - this.trigger.getWidth(); +// this.inputEl().setWidth(this.adjustWidth('input', x)); +// this.trigger.setStyle('left', x+'px'); +// } + }, + + // private + adjustSize : Roo.BoxComponent.prototype.adjustSize, + + // private + getResizeEl : function(){ + return this.inputEl(); + }, + + // private + getPositionEl : function(){ + return this.inputEl(); + }, + + // private + alignErrorIcon : function(){ + this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]); + }, + + // private + initEvents : function(){ + + this.createList(); + + Roo.bootstrap.TriggerField.superclass.initEvents.call(this); + //this.wrap = this.el.wrap({cls: "x-form-field-wrap"}); + if(!this.multiple && this.showToggleBtn){ + this.trigger = this.el.select('span.dropdown-toggle',true).first(); + if(this.hideTrigger){ + this.trigger.setDisplayed(false); + } + this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true}); + } + + if(this.multiple){ + this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true}); + } + + if(this.removable && !this.editable && !this.tickable){ + var close = this.closeTriggerEl(); + + if(close){ + close.setVisibilityMode(Roo.Element.DISPLAY).hide(); + close.on('click', this.removeBtnClick, this, close); + } + } + + //this.trigger.addClassOnOver('x-form-trigger-over'); + //this.trigger.addClassOnClick('x-form-trigger-click'); + + //if(!this.width){ + // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth()); + //} + }, + + closeTriggerEl : function() + { + var close = this.el.select('.roo-combo-removable-btn', true).first(); + return close ? close : false; + }, + + removeBtnClick : function(e, h, el) + { + e.preventDefault(); + + if(this.fireEvent("remove", this) !== false){ + this.reset(); + this.fireEvent("afterremove", this) + } + }, + + createList : function() + { + this.list = Roo.get(document.body).createChild({ + tag: Roo.bootstrap.version == 4 ? 'div' : 'ul', + cls: 'typeahead typeahead-long dropdown-menu shadow', + style: 'display:none' + }); + + this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';; + + }, + + // private + initTrigger : function(){ + + }, + + // private + onDestroy : function(){ + if(this.trigger){ + this.trigger.removeAllListeners(); + // this.trigger.remove(); + } + //if(this.wrap){ + // this.wrap.remove(); + //} + Roo.bootstrap.TriggerField.superclass.onDestroy.call(this); + }, + + // private + onFocus : function(){ + Roo.bootstrap.TriggerField.superclass.onFocus.call(this); + /* + if(!this.mimicing){ + this.wrap.addClass('x-trigger-wrap-focus'); + this.mimicing = true; + Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this); + if(this.monitorTab){ + this.el.on("keydown", this.checkTab, this); + } + } + */ + }, + + // private + checkTab : function(e){ + if(e.getKey() == e.TAB){ + this.triggerBlur(); + } + }, + + // private + onBlur : function(){ + // do nothing + }, + + // private + mimicBlur : function(e, t){ + /* + if(!this.wrap.contains(t) && this.validateBlur()){ + this.triggerBlur(); + } + */ + }, + + // private + triggerBlur : function(){ + this.mimicing = false; + Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur); + if(this.monitorTab){ + this.el.un("keydown", this.checkTab, this); + } + //this.wrap.removeClass('x-trigger-wrap-focus'); + Roo.bootstrap.TriggerField.superclass.onBlur.call(this); + }, + + // private + // This should be overriden by any subclass that needs to check whether or not the field can be blurred. + validateBlur : function(e, t){ + return true; + }, + + // private + onDisable : function(){ + this.inputEl().dom.disabled = true; + //Roo.bootstrap.TriggerField.superclass.onDisable.call(this); + //if(this.wrap){ + // this.wrap.addClass('x-item-disabled'); + //} + }, + + // private + onEnable : function(){ + this.inputEl().dom.disabled = false; + //Roo.bootstrap.TriggerField.superclass.onEnable.call(this); + //if(this.wrap){ + // this.el.removeClass('x-item-disabled'); + //} + }, + + // private + onShow : function(){ + var ae = this.getActionEl(); + + if(ae){ + ae.dom.style.display = ''; + ae.dom.style.visibility = 'visible'; + } + }, + + // private + + onHide : function(){ + var ae = this.getActionEl(); + ae.dom.style.display = 'none'; + }, + + /** + * The function that should handle the trigger's click event. This method does nothing by default until overridden + * by an implementing function. + * @method + * @param {EventObject} e + */ + onTriggerClick : Roo.emptyFn +}); + \ No newline at end of file