--- /dev/null
+/*
+ * - 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 ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 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
--- /dev/null
+/*
+ * - 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);
+ }
+});
+
+
--- /dev/null
+/*
+ * - 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 = '<i class="fa far fa-clock"></i>';
+ 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
--- /dev/null
+/*
+ * - 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:
+ * <pre><code>
+var trigger = new Roo.bootstrap.TriggerField();
+trigger.onTriggerClick = myTriggerFn;
+trigger.applyTo('my-field');
+</code></pre>
+ *
+ * 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 <b>appended</b> 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