overte/unpublishedScripts/marketplace/camera-move/hifi-jquery-ui.js
humbletim 01436675b1 * recent changes in master broke event bridge; updated to latest scheme
* fix update throttling for rapidly-changed values from the tablet UI
* include default values for several advanced settings (so if user changes the RESET button works better)
* reduce log spam
2017-06-21 15:22:32 -04:00

311 lines
12 KiB
JavaScript

// extended jQuery UI controls
/* eslint-env console, jquery, browser */
/* eslint-disable comma-dangle, no-empty */
/* global assert, log, debugPrint */
// ----------------------------------------------------------------------------
// WIDGET BASE
Object.assign($.Widget.prototype, {
// common bootstrapping across widget types
initHifiControl: function initHifiControl(hifiType) {
initHifiControl.widgetCount = (initHifiControl.widgetCount || 0) + 1;
hifiType = hifiType || this.widgetName;
var element = this.element, options = this.options, node = element.get(0), dataset = node.dataset;
assert(!this.element.is('.initialized'));
this.element.addClass('initialized');
var attributes = [].reduce.call(node.attributes, function(out, attribute) {
out[attribute.name] = attribute.value;
return out;
}, {});
var searchOrder = [ options, dataset, attributes, node ];
function setData(key, fallback) {
var value = searchOrder.map(function(obj) {
return obj[key];
}).concat(fallback).filter(function(value) {
return value !== undefined;
})[0];
return value === undefined ? null : (dataset[key] = value);
}
options.hifiWidgetId = hifiType + '-' + initHifiControl.widgetCount;
node.id = node.id || options.hifiWidgetId;
dataset.hifiType = hifiType;
setData('type');
setData('for', node.id);
setData('checked');
if (setData('value', null) !== null) {
element.attr('value', dataset.value);
}
return node.id;
},
hifiFindWidget: function(hifiType, quiet) {
var selector = ':ui-'+hifiType;
var _for = JSON.stringify(this.element.data('for')||undefined),
element = _for && $('[id='+_for+']').filter(selector);
if (!element.is(selector)) {
element = this.element.closest(selector);
}
var instance = element.filter(selector)[hifiType]('instance');
if (!instance && !quiet) {
// eslint-disable-next-line no-console
console.error([
instance, 'could not find target instance ' + selector +
' for ' + this.element.data('hifi-type') +
' #' + this.element.prop('id') + ' for=' + this.element.data('for')
]);
}
return instance;
},
});
// CHECKBOX
$.widget('ui.hifiCheckbox', $.ui.checkboxradio, {
value: function value(nv) {
if (arguments.length) {
var currentValue = this.element.prop('checked');
if (nv !== currentValue){
this.element.prop('checked', nv);
this.element.change();
}
}
return this.element.prop('checked');
},
_create: function() {
var id = this.initHifiControl();
this.element.attr('value', id);
// add an implicit label if missing
var forId = 'for=' + JSON.stringify(id);
var label = $(this.element.get(0)).closest('label').add($('label[' + forId + ']'));
if (!label.get(0)) {
$('<label ' + forId + '>' + forId + '</label>').appendTo(this.element);
}
this._super();
this.element.on('change._hifiCheckbox, click._hifiCheckbox', function() {
var checked = this.value(),
attr = this.element.attr('checked');
if (checked && !attr) {
this.element.attr('checked', 'checked');
} else if (!checked && attr) {
this.element.removeAttr('checked');
}
this.refresh();
}.bind(this));
},
});
// BUTTON
$.widget('ui.hifiButton', $.ui.button, {
value: function(nv) {
var dataset = this.element[0].dataset;
if (arguments.length) {
var checked = (dataset.checked === 'true');
nv = (nv === 'true' || !!nv);
if (nv !== checked) {
debugPrint('hifibutton checked changed', nv, checked);
dataset.checked = nv;
this.element.change();
} else {
debugPrint('hifibutton value same', nv, checked);
}
}
return dataset.checked === 'true';
},
_create: function() {
this.element.data('type', 'checkbox');
this.initHifiControl();
this._super();
this.element[0].dataset.checked = !!this.element.attr('checked');
var _for = this.element.data('for') || undefined;
if (_for && _for !== this.element[0].id) {
_for = JSON.stringify(_for);
var checkbox = this.hifiFindWidget('hifiCheckbox', true);
if (!checkbox) {
var input = $('<label><input type=checkbox id=' + _for + ' value=' + _for +' /></label>').hide();
input.appendTo(this.element);
checkbox = input.find('input')
.hifiCheckbox()
.hifiCheckbox('instance');
}
this.element.find('.tooltip-target').removeClass('tooltip-target');
this.element.prop('id', 'button-'+this.element.prop('id'));
checkbox.element.on('change._hifiButton', function() {
debugPrint('checkbox -> button');
this.value(checkbox.value());
}.bind(this));
this.element.on('change', function() {
debugPrint('button -> checkbox');
checkbox.value(this.value());
}.bind(this));
this.checkbox = checkbox;
}
},
});
// RADIO BUTTON
$.widget('ui.hifiRadioButton', $.ui.checkboxradio, {
value: function value(nv) {
if (arguments.length) {
this.element.prop('checked', !!nv);
this.element.change();
}
return this.element.prop('checked');
},
_create: function() {
var id = this.initHifiControl();
this.element.attr('value', this.element.data('value') || id);
// console.log(this.element[0]);
assert(this.element.data('for'));
this._super();
this.element.on('change._hifiRadioButton, click._hifiRadioButton', function() {
var group = this.hifiFindWidget('hifiRadioGroup'),
checked = !!this.element.attr('checked'),
dotchecked = this.element.prop('checked'),
value = this.element.attr('value');
if (dotchecked !== checked || group.value() !== value) {
if (dotchecked && group.value() !== value) {
log(value, 'UPDATING GRUOP', group.element[0].id);
group.value(value);
}
}
}.bind(this));
},
});
// RADIO GROUP
$.widget('ui.hifiRadioGroup', $.ui.controlgroup, {
radio: function(selector) {
return this.element.find(':ui-hifiRadioButton' + selector).hifiRadioButton('instance');
},
refresh: function() {
var value = this.value();
this.element.find(':ui-hifiRadioButton').each(function() {
$(this).prop('checked', $(this).attr('value') === value).hifiRadioButton('refresh');
});
this._super();
},
value: function value(nv) {
if (arguments.length) {
var id = this.element[0].id,
previous = this.value();
debugPrint('RADIOBUTTON GROUP value', id + ' = ' + nv + '(was: ' + previous + ')');
this.element.attr('value', nv);
this.refresh();
}
return this.element.attr('value');
},
_create: function(x) {
debugPrint('ui.hifiRadioGroup._create', this.element[0]);
this.initHifiControl();
this.options.items = {
hifiRadioButton: 'input[type=radio]',
};
this._super();
// allow setting correct radio button by assign to .value property (or $.fn.val() etc.)
Object.defineProperty(this.element[0], 'value', {
set: function(nv) {
try {
this.radio('#' + nv).value(true);
} catch (e) {}
return this.value();
}.bind(this),
get: function() {
return this.element.attr('value');
}.bind(this),
});
},
});
// SPINNER (numeric input + up/down buttons)
$.widget('ui.hifiSpinner', $.ui.spinner, {
value: function value(nv) {
if (arguments.length) {
var num = parseFloat(nv);
debugPrint('ui.hifiSpinner.value set', this.element[0].id, num, '(was: ' + this.value() + ')', 'raw:'+nv);
this._value(num);
this.element.change();
}
return parseFloat(this.element.val());
},
_value: function(value, allowAny) {
debugPrint('ui.hifiSpinner._value', value, allowAny);
return this._super(value, allowAny);
},
_create: function() {
this.initHifiControl();
var step = this.options.step = this.options.step || 1.0;
// allow step=".01" for precision and data-step=".1" for default increment amount
this.options.prescale = parseFloat(this.element.data('step') || step) / (step);
this._super();
this.previous = null;
this.element.on('change._hifiSpinner', function() {
var value = this.value(),
invalid = !this.isValid();
debugPrint('hifiSpinner.changed', value, invalid ? '!!!invalid' : 'valid');
!invalid && this.element.attr('value', value);
}.bind(this));
},
_spin: function( step, event ) {
step = step * this.options.prescale * (
event.shiftKey ? 0.1 : event.ctrlKey ? 10 : 1
);
return this._super( step, event );
},
_stop: function( event, ui ) {
try {
return this._super(event, ui);
} finally {
if (/mouse/.test(event && event.type)) {
var value = this.value();
if ((value || value === 0) && !isNaN(value) && this.previous !== null && this.previous !== value) {
this.value(this.value());
}
this.previous = value;
}
}
},
_format: function(n) {
var precision = this._precision();
return parseFloat(n).toFixed(precision);
},
_events: {
mousewheel: function(event, delta) {
if (document.activeElement === this.element[0]) {
// fix broken mousewheel on Chrome / embedded webkit
delta = delta === undefined ? -(event.originalEvent.deltaY+event.originalEvent.deltaX) : delta;
$.ui.spinner.prototype._events.mousewheel.call(this, event, delta);
}
}
}
});
// SLIDER
$.widget('ui.hifiSlider', $.ui.slider, {
value: function value(nv) {
if (arguments.length) {
var num = this._trimAlignValue(nv);
debugPrint('hifiSlider.value', nv, num);
if (this.options.value !== num) {
this.options.value = num;
this.element.change();
}
}
return this.options.value;
},
_create: function() {
this.initHifiControl();
this._super();
this.element
.attr('type', this.element.attr('type') || 'slider')
.find('.ui-slider-handle').html('<div class="inner-ui-slider-handle"></div>').end()
.on('change', function() {
this.hifiFindWidget('hifiSpinner').value(this.value());
this._refresh();
}.bind(this));
},
});