Options retrieval working

pull/1/head
Piero Toffanin 2016-07-25 20:10:18 -05:00
rodzic 0d605d4722
commit a769b5425f
8 zmienionych plików z 1199 dodań i 26 usunięć

Wyświetl plik

@ -29,6 +29,7 @@ let bodyParser = require('body-parser');
let morgan = require('morgan');
let TaskManager = require('./libs/taskManager');
let Task = require('./libs/Task');
let odmOptionsParser = require('./libs/odmOptionsParser');
app.use(morgan('tiny'));
app.use(bodyParser.urlencoded({extended: true}));
@ -137,6 +138,13 @@ app.post('/task/restart', uuidCheck, (req, res) => {
taskManager.restart(req.body.uuid, successHandler(res));
});
app.get('/getOptions', (req, res) => {
odmOptionsParser.getOptions((err, options) => {
if (err) res.json({error: err.message});
else res.json(options);
});
});
let gracefulShutdown = done => {
async.series([
cb => { taskManager.dumpTaskList(cb) },
@ -158,7 +166,7 @@ process.on ('SIGINT', gracefulShutdown);
// Startup
let taskManager;
let server;
/*
async.series([
cb => { taskManager = new TaskManager(cb); },
cb => { server = app.listen(3000, err => {
@ -168,6 +176,4 @@ async.series([
}
], err => {
if (err) console.log("Error during startup: " + err.message);
});*/
let odmOptionsParser = require('./libs/odmOptionsParser');
odmOptionsParser.getOptions(function(){});
});

Wyświetl plik

@ -18,57 +18,69 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"use strict";
let odmRunner = require('./odmRunner');
let options = null;
module.exports = {
getOptions: function(done){
if (options){
done(null, options);
return;
}
odmRunner.getJsonOptions((err, json) => {
if (err) done(err);
else{
options = {};
for (let option in json){
if (option === "-h") continue;
if (["-h", "--project-path", "--zip-results"].indexOf(option) !== -1) continue;
let values = json[option];
option = option.replace(/^--/, "");
let type = "";
let defaultValue = "";
let value = "";
let help = values.help || "";
let range = values.metavar.replace(/[<>]/g, "").trim();
let domain = values.metavar !== undefined ?
values.metavar.replace(/^[<>]/g, "")
.replace(/[<>]$/g, "")
.trim() :
"";
switch(values.type.trim()){
switch((values.type || "").trim()){
case "<type 'int'>":
type = "int";
defaultValue = values['default'] !== undefined ?
value = values['default'] !== undefined ?
parseInt(values['default']) :
0;
break;
case "<type 'float'>":
type = "float";
defaultValue = values['default'] !== undefined ?
value = values['default'] !== undefined ?
parseFloat(values['default']) :
0.0;
break;
default:
type = "string";
defaultValue = values['default'].trim();
value = values['default'] !== undefined ?
values['default'].trim() :
"";
}
if (values['default'] === "True"){
type = "bool";
defaultValue = true;
value = true;
}else if (values['default'] === "False"){
type = "bool";
defaultValue = false;
value = false;
}
help = help.replace(/\%\(default\)s/g, value);
let result = {
type, defaultValue, range, help
options[option] = {
type, value, domain, help
};
console.log(values);
console.log(result);
console.log('-----');
}
done();
done(null, options);
}
});
}

Wyświetl plik

@ -55,4 +55,8 @@
height: 200px;
font-family: monospace;
font-size: 90%;
}
.selectric-items li{
background: #fff;
}

Wyświetl plik

@ -0,0 +1,198 @@
/*======================================
Selectric v1.10.1
======================================*/
.selectric-wrapper {
position: relative;
cursor: pointer;
}
.selectric-responsive {
width: 100%;
}
.selectric {
border: 1px solid #DDD;
background: #F8F8F8;
position: relative;
}
.selectric .label {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin: 0 38px 0 10px;
font-size: 12px;
line-height: 38px;
color: #444;
height: 38px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.selectric .button {
display: block;
position: absolute;
right: 0;
top: 0;
width: 38px;
height: 38px;
color: #BBB;
text-align: center;
font: 0/0 a;
*font: 20px/38px Lucida Sans Unicode, Arial Unicode MS, Arial;
}
.selectric .button:after {
content: " ";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 0;
height: 0;
border: 4px solid transparent;
border-top-color: #BBB;
border-bottom: none;
}
.selectric-focus .selectric {
border-color: #AAA;
}
.selectric-hover .selectric {
border-color: #C4C4C4;
}
.selectric-hover .selectric .button {
color: #A2A2A2;
}
.selectric-hover .selectric .button:after {
border-top-color: #A2A2A2;
}
.selectric-open {
z-index: 9999;
}
.selectric-open .selectric {
border-color: #C4C4C4;
}
.selectric-open .selectric-items {
display: block;
}
.selectric-disabled {
filter: alpha(opacity=50);
opacity: 0.5;
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.selectric-hide-select {
position: relative;
overflow: hidden;
width: 0;
height: 0;
}
.selectric-hide-select select {
position: absolute;
left: -100%;
display: none;
}
.selectric-input {
position: absolute !important;
top: 0 !important;
left: 0 !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
margin: 0 !important;
padding: 0 !important;
width: 1px !important;
height: 1px !important;
outline: none !important;
border: none !important;
*font: 0/0 a !important;
background: none !important;
}
.selectric-temp-show {
position: absolute !important;
visibility: hidden !important;
display: block !important;
}
/* Items box */
.selectric-items {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #F8F8F8;
border: 1px solid #C4C4C4;
z-index: -1;
box-shadow: 0 0 10px -6px;
}
.selectric-items .selectric-scroll {
height: 100%;
overflow: auto;
}
.selectric-above .selectric-items {
top: auto;
bottom: 100%;
}
.selectric-items ul, .selectric-items li {
list-style: none;
padding: 0;
margin: 0;
font-size: 12px;
line-height: 20px;
min-height: 20px;
}
.selectric-items li {
display: block;
padding: 10px;
color: #666;
cursor: pointer;
}
.selectric-items li.selected {
background: #E0E0E0;
color: #444;
}
.selectric-items li:hover {
background: #D5D5D5;
color: #444;
}
.selectric-items .disabled {
filter: alpha(opacity=50);
opacity: 0.5;
cursor: default !important;
background: none !important;
color: #666 !important;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.selectric-items .selectric-group .selectric-group-label {
font-weight: bold;
padding-left: 10px;
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background: none;
color: #444;
}
.selectric-items .selectric-group.disabled li {
filter: alpha(opacity=100);
opacity: 1;
}
.selectric-items .selectric-group li {
padding-left: 25px;
}

Wyświetl plik

@ -15,6 +15,7 @@
}
</style>
<link href="css/fileinput.css" media="all" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="css/selectric.css">
<link rel="stylesheet" href="css/main.css">
@ -47,14 +48,18 @@
<label for="images">Aerial Imageries:</label> <input id="images" name="images" multiple type="file">
<div id="errorBlock" class="help-block"></div>
</div>
<div class="form-group">
<!-- <label>Options:</label> -->
<div class="text-right"><input type="submit" class="btn btn-success" value="Start Task" id="btnUpload" /></div>
<div class="form-group" id="options">
<label>Set Options:</label>
<div data-bind="visible: error(), text: error()" class="alert alert-warning" role="alert"></div>
<select data-bind="foreach: options">
<option data-bind="text: params.help + ' (--' + name + ')'"></option>
</select>
</div>
<div class="text-right"><input type="submit" class="btn btn-success" value="Start Task" id="btnUpload" /></div>
</form>
</div>
<div class="col-md-7">
<div class="col-md-7" id="taskList">
<h2>Current Tasks (<span data-bind="text: tasks().length"></span>)</h2>
<p data-bind="visible: tasks().length === 0">No running tasks.</p>
<div data-bind="foreach: tasks">
@ -113,6 +118,8 @@
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/vendor/knockout-3.4.0.js"></script>
<script src="js/fileinput.js" type="text/javascript"></script>
<script src="js/jquery.selectric.js" type="text/javascript"></script>
<script src="js/main.js"></script>
</body>
</html>

Wyświetl plik

@ -0,0 +1,911 @@
/*!
* ,/
* ,'/
* ,' /
* ,' /_____,
* .'____ ,'
* / ,'
* / ,'
* /,'
* /'
*
* Selectric ϟ v1.10.1 (Jun 30 2016) - http://lcdsantos.github.io/jQuery-Selectric/
*
* Copyright (c) 2016 Leonardo Santos; MIT License
*
*/
(function(factory) {
/* global define */
/* istanbul ignore next */
if ( typeof define === 'function' && define.amd ) {
define(['jquery'], factory);
} else if ( typeof module === 'object' && module.exports ) {
// Node/CommonJS
module.exports = function( root, jQuery ) {
if ( jQuery === undefined ) {
if ( typeof window !== 'undefined' ) {
jQuery = require('jquery');
} else {
jQuery = require('jquery')(root);
}
}
factory(jQuery);
return jQuery;
};
} else {
// Browser globals
factory(jQuery);
}
}(function($) {
'use strict';
var $doc = $(document);
var $win = $(window);
var pluginName = 'selectric';
var classList = 'Input Items Open Disabled TempShow HideSelect Wrapper Focus Hover Responsive Above Scroll Group GroupLabel';
var bindSufix = '.sl';
var chars = ['a', 'e', 'i', 'o', 'u', 'n', 'c', 'y'];
var diacritics = [
/[\xE0-\xE5]/g, // a
/[\xE8-\xEB]/g, // e
/[\xEC-\xEF]/g, // i
/[\xF2-\xF6]/g, // o
/[\xF9-\xFC]/g, // u
/[\xF1]/g, // n
/[\xE7]/g, // c
/[\xFD-\xFF]/g // y
];
/**
* Create an instance of Selectric
*
* @constructor
* @param {Node} element - The &lt;select&gt; element
* @param {object} opts - Options
*/
var Selectric = function(element, opts) {
var _this = this;
_this.element = element;
_this.$element = $(element);
_this.state = {
enabled : false,
opened : false,
currValue : -1,
selectedIdx : -1
};
_this.eventTriggers = {
open : _this.open,
close : _this.close,
destroy : _this.destroy,
refresh : _this.refresh,
init : _this.init
};
_this.init(opts);
};
Selectric.prototype = {
utils: {
/**
* Detect mobile browser
*
* @return {boolean}
*/
isMobile: function() {
return /android|ip(hone|od|ad)/i.test(navigator.userAgent);
},
/**
* Escape especial characters in string (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
*
* @param {string} str - The string to be escaped
* @return {string} The string with the special characters escaped
*/
escapeRegExp: function(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
},
/**
* Replace diacritics
*
* @param {string} str - The string to replace the diacritics
* @return {string} The string with diacritics replaced with ascii characters
*/
replaceDiacritics: function(str) {
var k = diacritics.length;
while (k--) {
str = str.toLowerCase().replace(diacritics[k], chars[k]);
}
return str;
},
/**
* Format string
* https://gist.github.com/atesgoral/984375
*
* @param {string} f - String to be formated
* @return {string} String formated
*/
format: function (f) {
var a = arguments; // store outer arguments
return ('' + f) // force format specifier to String
.replace( // replace tokens in format specifier
/\{(?:(\d+)|(\w+))\}/g, // match {token} references
function (
s, // the matched string (ignored)
i, // an argument index
p // a property name
) {
return p && a[1] // if property name and first argument exist
? a[1][p] // return property from first argument
: a[i]; // assume argument index and return i-th argument
});
},
/**
* Get the next enabled item in the options list.
*
* @param {object} selectItems - The options object.
* @param {number} selected - Index of the currently selected option.
* @return {object} The next enabled item.
*/
nextEnabledItem: function(selectItems, selected) {
while ( selectItems[ selected = (selected + 1) % selectItems.length ].disabled ) {
// empty
}
return selected;
},
/**
* Get the previous enabled item in the options list.
*
* @param {object} selectItems - The options object.
* @param {number} selected - Index of the currently selected option.
* @return {object} The previous enabled item.
*/
previousEnabledItem: function(selectItems, selected) {
while ( selectItems[ selected = (selected > 0 ? selected : selectItems.length) - 1 ].disabled ) {
// empty
}
return selected;
},
/**
* Transform camelCase string to dash-case.
*
* @param {string} str - The camelCased string.
* @return {string} The string transformed to dash-case.
*/
toDash: function(str) {
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
},
/**
* Calls the events and hooks registered with function name.
*
* @param {string} fn - The name of the function.
* @param {number} scope - Scope that should be set on the function.
*/
triggerCallback: function(fn, scope) {
var elm = scope.element;
var func = scope.options['on' + fn];
if ( $.isFunction(func) ) {
func.call(elm, elm, scope);
}
if ( $.fn[pluginName].hooks[fn] ) {
$.each($.fn[pluginName].hooks[fn], function() {
this.call(elm, elm, scope);
});
}
$(elm).trigger(pluginName + '-' + this.toDash(fn), scope);
}
},
/** Initializes */
init: function(opts) {
var _this = this;
// Set options
_this.options = $.extend(true, {}, $.fn[pluginName].defaults, _this.options, opts);
_this.utils.triggerCallback('BeforeInit', _this);
// Preserve data
_this.destroy(true);
// Disable on mobile browsers
if ( _this.options.disableOnMobile && _this.utils.isMobile() ) {
_this.disableOnMobile = true;
return;
}
// Get classes
_this.classes = _this.getClassNames();
// Create elements
var input = $('<input/>', { 'class': _this.classes.input, 'readonly': _this.utils.isMobile() });
var items = $('<div/>', { 'class': _this.classes.items, 'tabindex': -1 });
var itemsScroll = $('<div/>', { 'class': _this.classes.scroll });
var wrapper = $('<div/>', { 'class': _this.classes.prefix, 'html': _this.options.arrowButtonMarkup });
var label = $('<span/>', { 'class': 'label' });
var outerWrapper = _this.$element.wrap('<div/>').parent().append(wrapper.prepend(label), items, input);
_this.elements = {
input : input,
items : items,
itemsScroll : itemsScroll,
wrapper : wrapper,
label : label,
outerWrapper : outerWrapper
};
_this.$element
.on(_this.eventTriggers)
.wrap('<div class="' + _this.classes.hideselect + '"/>');
_this.originalTabindex = _this.$element.prop('tabindex');
_this.$element.prop('tabindex', false);
_this.populate();
_this.activate();
_this.utils.triggerCallback('Init', _this);
},
/** Activates the plugin */
activate: function() {
var _this = this;
var originalWidth = _this.$element.width();
_this.utils.triggerCallback('BeforeActivate', _this);
_this.elements.outerWrapper.prop('class', [
_this.classes.wrapper,
_this.$element.prop('class').replace(/\S+/g, _this.classes.prefix + '-$&'),
_this.options.responsive ? _this.classes.responsive : ''
].join(' '));
if ( _this.options.inheritOriginalWidth && originalWidth > 0 ) {
_this.elements.outerWrapper.width(originalWidth);
}
if ( !_this.$element.prop('disabled') ) {
_this.state.enabled = true;
// Not disabled, so... Removing disabled class
_this.elements.outerWrapper.removeClass(_this.classes.disabled);
// Remove styles from items box
// Fix incorrect height when refreshed is triggered with fewer options
_this.$li = _this.elements.items.removeAttr('style').find('li');
_this.bindEvents();
} else {
_this.elements.outerWrapper.addClass(_this.classes.disabled);
_this.elements.input.prop('disabled', true);
}
_this.utils.triggerCallback('Activate', _this);
},
/**
* Generate classNames for elements
*
* @return {object} Classes object
*/
getClassNames: function() {
var _this = this;
var customClass = _this.options.customClass;
var classesObj = {};
$.each(classList.split(' '), function(i, currClass) {
var c = customClass.prefix + currClass;
classesObj[currClass.toLowerCase()] = customClass.camelCase ? c : _this.utils.toDash(c);
});
classesObj.prefix = customClass.prefix;
return classesObj;
},
/** Set the label text */
setLabel: function() {
var _this = this;
var labelBuilder = _this.options.labelBuilder;
var currItem = _this.lookupItems[_this.state.currValue];
_this.elements.label.html(
$.isFunction(labelBuilder)
? labelBuilder(currItem)
: _this.utils.format(labelBuilder, currItem)
);
},
/** Get and save the available options */
populate: function() {
var _this = this;
var $options = _this.$element.children();
var $justOptions = _this.$element.find('option');
var selectedIndex = $justOptions.index($justOptions.filter(':selected'));
var currIndex = 0;
_this.state.currValue = (_this.state.selected = ~selectedIndex ? selectedIndex : 0);
_this.state.selectedIdx = _this.state.currValue;
_this.items = [];
_this.lookupItems = [];
if ( $options.length ) {
// Build options markup
$options.each(function(i) {
var $elm = $(this);
if ( $elm.is('optgroup') ) {
var optionsGroup = {
element : $elm,
label : $elm.prop('label'),
groupDisabled : $elm.prop('disabled'),
items : []
};
$elm.children().each(function(i) {
var $elm = $(this);
var optionText = $elm.html();
optionsGroup.items[i] = {
index : currIndex,
element : $elm,
value : $elm.val(),
text : optionText,
slug : _this.utils.replaceDiacritics(optionText),
disabled : optionsGroup.groupDisabled
};
_this.lookupItems[currIndex] = optionsGroup.items[i];
currIndex++;
});
_this.items[i] = optionsGroup;
} else {
var optionText = $elm.html();
_this.items[i] = {
index : currIndex,
element : $elm,
value : $elm.val(),
text : optionText,
slug : _this.utils.replaceDiacritics(optionText),
disabled : $elm.prop('disabled')
};
_this.lookupItems[currIndex] = _this.items[i];
currIndex++;
}
});
_this.setLabel();
_this.elements.items.append( _this.elements.itemsScroll.html( _this.getItemsMarkup(_this.items) ) );
}
},
/**
* Generate options markup
*
* @param {object} items - Object containing all available options
* @return {string} HTML for the options box
*/
getItemsMarkup: function(items) {
var _this = this;
var markup = '<ul>';
$.each(items, function(i, elm) {
if ( elm.label !== undefined ) {
markup += _this.utils.format('<ul class="{1}"><li class="{2}">{3}</li>',
$.trim([_this.classes.group, elm.groupDisabled ? 'disabled' : '', elm.element.prop('class')].join(' ')),
_this.classes.grouplabel,
elm.element.prop('label')
);
$.each(elm.items, function(i, elm) {
markup += _this.getItemMarkup(elm.index, elm);
});
markup += '</ul>';
} else {
markup += _this.getItemMarkup(elm.index, elm);
}
});
return markup + '</ul>';
},
/**
* Generate every option markup
*
* @param {number} i - Index of current item
* @param {object} elm - Current item
* @return {string} HTML for the option
*/
getItemMarkup: function(i, elm) {
var _this = this;
var itemBuilder = _this.options.optionsItemBuilder;
return _this.utils.format('<li data-index="{1}" class="{2}">{3}</li>',
i,
$.trim([
i === _this.state.currValue ? 'selected' : '',
i === _this.items.length - 1 ? 'last' : '',
elm.disabled ? 'disabled' : ''
].join(' ')),
$.isFunction(itemBuilder) ? itemBuilder(elm, elm.element, i) : _this.utils.format(itemBuilder, elm)
);
},
/** Bind events on the elements */
bindEvents: function() {
var _this = this;
_this.elements.wrapper
.add(_this.$element)
.add(_this.elements.outerWrapper)
.add(_this.elements.input)
.off(bindSufix);
_this.elements.outerWrapper.on('mouseenter' + bindSufix + ' mouseleave' + bindSufix, function(e) {
$(this).toggleClass(_this.classes.hover, e.type === 'mouseenter');
// Delay close effect when openOnHover is true
if ( _this.options.openOnHover ) {
clearTimeout(_this.closeTimer);
if ( e.type === 'mouseleave' ) {
_this.closeTimer = setTimeout($.proxy(_this.close, _this), _this.options.hoverIntentTimeout);
} else {
_this.open();
}
}
});
// Toggle open/close
_this.elements.wrapper.on('click' + bindSufix, function(e) {
_this.state.opened ? _this.close() : _this.open(e);
});
_this.elements.input
.prop({ tabindex: _this.originalTabindex, disabled: false })
.on('keydown' + bindSufix, $.proxy(_this.handleKeys, _this))
.on('focusin' + bindSufix, function(e) {
_this.elements.outerWrapper.addClass(_this.classes.focus);
// Prevent the flicker when focusing out and back again in the browser window
_this.elements.input.one('blur', function() {
_this.elements.input.blur();
});
if ( _this.options.openOnFocus && !_this.state.opened ) {
_this.open(e);
}
})
.on('focusout' + bindSufix, function() {
_this.elements.outerWrapper.removeClass(_this.classes.focus);
})
.on('input propertychange', function() {
var val = _this.elements.input.val();
// Clear search
clearTimeout(_this.resetStr);
_this.resetStr = setTimeout(function() {
_this.elements.input.val('');
}, _this.options.keySearchTimeout);
if ( val.length ) {
// Search in select options
$.each(_this.items, function(i, elm) {
if ( RegExp('^' + _this.utils.escapeRegExp(val), 'i').test(elm.slug) && !elm.disabled ) {
_this.select(i);
return false;
}
});
}
});
_this.$li.on({
// Prevent <input> blur on Chrome
mousedown: function(e) {
e.preventDefault();
e.stopPropagation();
},
click: function() {
// The second parameter is to close the box after click
_this.select($(this).data('index'), true);
// Chrome doesn't close options box if select is wrapped with a label
// We need to 'return false' to avoid that
return false;
}
});
},
/**
* Behavior when keyboard keys is pressed
*
* @param {object} e - Event object
*/
handleKeys: function(e) {
var _this = this;
var key = e.keyCode || e.which;
var keys = _this.options.keys;
var isPrev = $.inArray(key, keys.previous) > -1;
var isNext = $.inArray(key, keys.next) > -1;
var isSelect = $.inArray(key, keys.select) > -1;
var isOpen = $.inArray(key, keys.open) > -1;
var idx = _this.state.selectedIdx;
var isFirstOrLastItem = (isPrev && idx === 0) || (isNext && (idx + 1) === _this.items.length);
var goToItem = 0;
// Enter / Space
if ( key === 13 || key === 32 ) {
e.preventDefault();
}
// If it's a directional key
if ( isPrev || isNext ) {
if ( !_this.options.allowWrap && isFirstOrLastItem ) {
return;
}
if ( isPrev ) {
goToItem = _this.utils.previousEnabledItem(_this.items, idx);
}
if ( isNext ) {
goToItem = _this.utils.nextEnabledItem(_this.items, idx);
}
_this.select(goToItem);
}
// Tab / Enter / ESC
if ( isSelect && _this.state.opened ) {
_this.select(idx, true);
return;
}
// Space / Enter / Left / Up / Right / Down
if ( isOpen && !_this.state.opened ) {
_this.open();
}
},
/** Update the items object */
refresh: function() {
var _this = this;
_this.populate();
_this.activate();
_this.utils.triggerCallback('Refresh', _this);
},
/** Set options box width/height */
setOptionsDimensions: function() {
var _this = this;
// Calculate options box height
// Set a temporary class on the hidden parent of the element
var hiddenChildren = _this.elements.items.closest(':visible').children(':hidden').addClass(_this.classes.tempshow);
var maxHeight = _this.options.maxHeight;
var itemsWidth = _this.elements.items.outerWidth();
var wrapperWidth = _this.elements.wrapper.outerWidth() - (itemsWidth - _this.elements.items.width());
// Set the dimensions, minimum is wrapper width, expand for long items if option is true
if ( !_this.options.expandToItemText || wrapperWidth > itemsWidth ) {
_this.finalWidth = wrapperWidth;
} else {
// Make sure the scrollbar width is included
_this.elements.items.css('overflow', 'scroll');
// Set a really long width for _this.elements.outerWrapper
_this.elements.outerWrapper.width(9e4);
_this.finalWidth = _this.elements.items.width();
// Set scroll bar to auto
_this.elements.items.css('overflow', '');
_this.elements.outerWrapper.width('');
}
_this.elements.items.width(_this.finalWidth).height() > maxHeight && _this.elements.items.height(maxHeight);
// Remove the temporary class
hiddenChildren.removeClass(_this.classes.tempshow);
},
/** Detect if the options box is inside the window */
isInViewport: function() {
var _this = this;
var scrollTop = $win.scrollTop();
var winHeight = $win.height();
var uiPosX = _this.elements.outerWrapper.offset().top;
var uiHeight = _this.elements.outerWrapper.outerHeight();
var fitsDown = (uiPosX + uiHeight + _this.itemsHeight) <= (scrollTop + winHeight);
var fitsAbove = (uiPosX - _this.itemsHeight) > scrollTop;
// If it does not fit below, only render it
// above it fit's there.
// It's acceptable that the user needs to
// scroll the viewport to see the cut off UI
var renderAbove = !fitsDown && fitsAbove;
_this.elements.outerWrapper.toggleClass(_this.classes.above, renderAbove);
},
/**
* Detect if currently selected option is visible and scroll the options box to show it
*
* @param {number} index - Index of the selected items
*/
detectItemVisibility: function(index) {
var _this = this;
var liHeight = _this.$li.eq(index).outerHeight();
var liTop = _this.$li[index].offsetTop;
var itemsScrollTop = _this.elements.itemsScroll.scrollTop();
var scrollT = liTop + liHeight * 2;
_this.elements.itemsScroll.scrollTop(
scrollT > itemsScrollTop + _this.itemsHeight ? scrollT - _this.itemsHeight :
liTop - liHeight < itemsScrollTop ? liTop - liHeight :
itemsScrollTop
);
},
/**
* Open the select options box
*
* @param {event} e - Event
*/
open: function(e) {
var _this = this;
_this.utils.triggerCallback('BeforeOpen', _this);
if ( e ) {
e.preventDefault();
e.stopPropagation();
}
if ( _this.state.enabled ) {
_this.setOptionsDimensions();
// Find any other opened instances of select and close it
$('.' + _this.classes.hideselect, '.' + _this.classes.open).children()[pluginName]('close');
_this.state.opened = true;
_this.itemsHeight = _this.elements.items.outerHeight();
_this.itemsInnerHeight = _this.elements.items.height();
// Toggle options box visibility
_this.elements.outerWrapper.addClass(_this.classes.open);
// Give dummy input focus
_this.elements.input.val('');
if ( e && e.type !== 'focusin' ) {
_this.elements.input.focus();
}
$doc
.on('click' + bindSufix, $.proxy(_this.close, _this))
.on('scroll' + bindSufix, $.proxy(_this.isInViewport, _this));
_this.isInViewport();
// Prevent window scroll when using mouse wheel inside items box
if ( _this.options.preventWindowScroll ) {
/* istanbul ignore next */
$doc.on('mousewheel' + bindSufix + ' DOMMouseScroll' + bindSufix, '.' + _this.classes.scroll, function(e) {
var orgEvent = e.originalEvent;
var scrollTop = $(this).scrollTop();
var deltaY = 0;
if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; }
if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; }
if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; }
if ( 'deltaY' in orgEvent ) { deltaY = orgEvent.deltaY * -1; }
if ( scrollTop === (this.scrollHeight - _this.itemsInnerHeight) && deltaY < 0 || scrollTop === 0 && deltaY > 0 ) {
e.preventDefault();
}
});
}
_this.detectItemVisibility(_this.state.selectedIdx);
_this.utils.triggerCallback('Open', _this);
}
},
/** Close the select options box */
close: function() {
var _this = this;
_this.utils.triggerCallback('BeforeClose', _this);
_this.change();
// Remove custom events on document
$doc.off(bindSufix);
// Remove visible class to hide options box
_this.elements.outerWrapper.removeClass(_this.classes.open);
_this.state.opened = false;
_this.utils.triggerCallback('Close', _this);
},
/** Select current option and change the label */
change: function() {
var _this = this;
_this.utils.triggerCallback('BeforeChange', _this);
if ( _this.state.currValue !== _this.state.selectedIdx ) {
// Apply changed value to original select
_this.$element
.prop('selectedIndex', _this.state.currValue = _this.state.selectedIdx)
.data('value', _this.lookupItems[_this.state.selectedIdx].text);
// Change label text
_this.setLabel();
}
_this.utils.triggerCallback('Change', _this);
},
/**
* Select option
*
* @param {number} index - Index of the option that will be selected
* @param {boolean} close - Close the options box after selecting
*/
select: function(index, close) {
var _this = this;
// Parameter index is required
if ( index === undefined ) {
return;
}
// If element is disabled, can't select it
if ( !_this.lookupItems[index].disabled ) {
_this.$li.filter('[data-index]')
.removeClass('selected')
.eq(_this.state.selectedIdx = index)
.addClass('selected');
_this.detectItemVisibility(index);
// If 'close' is false (default), the options box won't close after
// each selected item, this is necessary for keyboard navigation
if ( close ) {
_this.close();
}
}
},
/**
* Unbind and remove
*
* @param {boolean} preserveData - Check if the data on the element should be removed too
*/
destroy: function(preserveData) {
var _this = this;
if ( _this.state && _this.state.enabled ) {
_this.elements.items.add(_this.elements.wrapper).add(_this.elements.input).remove();
if ( !preserveData ) {
_this.$element.removeData(pluginName).removeData('value');
}
_this.$element.prop('tabindex', _this.originalTabindex).off(bindSufix).off(_this.eventTriggers).unwrap().unwrap();
_this.state.enabled = false;
}
}
};
// A really lightweight plugin wrapper around the constructor,
// preventing against multiple instantiations
$.fn[pluginName] = function(args) {
return this.each(function() {
var data = $.data(this, pluginName);
if ( data && !data.disableOnMobile ) {
(typeof args === 'string' && data[args]) ? data[args]() : data.init(args);
} else {
$.data(this, pluginName, new Selectric(this, args));
}
});
};
/**
* Hooks for the callbacks
*
* @type {object}
*/
$.fn[pluginName].hooks = {
/**
* @param {string} callbackName - The callback name.
* @param {string} hookName - The name of the hook to be attached.
* @param {function} fn - Callback function.
*/
add: function(callbackName, hookName, fn) {
if ( !this[callbackName] ) {
this[callbackName] = {};
}
this[callbackName][hookName] = fn;
},
/**
* @param {string} callbackName - The callback name.
* @param {string} hookName - The name of the hook that will be removed.
*/
remove: function(callbackName, hookName) {
delete this[callbackName][hookName];
}
};
/**
* Default plugin options
*
* @type {object}
*/
$.fn[pluginName].defaults = {
onChange : function(elm) { $(elm).change(); },
maxHeight : 300,
keySearchTimeout : 500,
arrowButtonMarkup : '<b class="button">&#x25be;</b>',
disableOnMobile : true,
openOnFocus : true,
openOnHover : false,
hoverIntentTimeout : 500,
expandToItemText : false,
responsive : false,
preventWindowScroll : true,
inheritOriginalWidth : false,
allowWrap : true,
optionsItemBuilder : '{text}', // function(itemData, element, index)
labelBuilder : '{text}', // function(currItem)
keys : {
previous : [37, 38], // Left / Up
next : [39, 40], // Right / Down
select : [9, 13, 27], // Tab / Enter / Escape
open : [13, 32, 37, 38, 39, 40], // Enter / Space / Left / Up / Right / Down
close : [9, 27] // Tab / Escape
},
customClass : {
prefix: pluginName,
camelCase: false
}
};
}));

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -254,7 +254,7 @@ $(function(){
};
var taskList = new TaskList();
ko.applyBindings(taskList);
ko.applyBindings(taskList, document.getElementById('taskList'));
// Handle uploads
$("#images").fileinput({
@ -294,4 +294,37 @@ $(function(){
})
.on('filebatchuploaderror', function(e, data, msg){
});
// Load options
function Option(name, params){
this.name = name;
this.params = params;
}
function OptionsModel(){
var self = this;
this.options = ko.observableArray();
this.error = ko.observable();
$.get("/getOptions")
.done(function(json){
if (json.error) self.error(json.error);
else{
for (var optionName in json){
self.options.push(new Option(optionName, json[optionName]));
}
$('select').selectric({
maxHeight: 500
});
}
})
.fail(function(){
self.error("options are not available.");
})
}
var optionsModel = new OptionsModel();
ko.applyBindings(optionsModel, document.getElementById("options"));
});