Merge branch 'devel_knockout_bindings' of https://github.com/BillyBlaze/OctoPrint into pr/BillyBlaze/devel_knockout_bindings

This commit is contained in:
Gina Häußge 2016-01-05 11:17:04 +01:00
commit d4260468be
15 changed files with 128 additions and 97 deletions

View file

@ -891,6 +891,13 @@ def collect_plugin_assets(enable_gcodeviewer=True, preferred_stylesheet="css"):
less=[]
)
assets["js"] = [
'js/app/bindings/allowbindings.js',
'js/app/bindings/contextmenu.js',
'js/app/bindings/invisible.js',
'js/app/bindings/popover.js',
'js/app/bindings/qrcode.js',
'js/app/bindings/slimscrolledforeach.js',
'js/app/bindings/togglecontent.js',
'js/app/viewmodels/appearance.js',
'js/app/viewmodels/connection.js',
'js/app/viewmodels/control.js',

View file

@ -46,6 +46,7 @@
.wrapper .outer .inner {
display: table-cell;
vertical-align: middle;
padding: 20px;
}
.wrapper .outer .inner .content {
@ -60,6 +61,10 @@
color: #990000;
}
#message {
line-height: 1.3;
}
.pulsate3 {
-webkit-animation: pulsate 3s ease-out;
-webkit-animation-iteration-count: infinite;

View file

@ -0,0 +1,6 @@
ko.bindingHandlers.allowBindings = {
init: function (elem, valueAccessor) {
return { controlsDescendantBindings: !valueAccessor() };
}
};
ko.virtualElements.allowedBindings.allowBindings = true;

View file

@ -0,0 +1,12 @@
ko.bindingHandlers.contextMenu = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
$(element).contextMenu(val);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
$(element).contextMenu(val);
}
};

View file

@ -0,0 +1,8 @@
ko.bindingHandlers.invisible = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
if (!valueAccessor()) return;
ko.bindingHandlers.style.update(element, function() {
return { visibility: 'hidden' };
})
}
};

View file

@ -0,0 +1,16 @@
ko.bindingHandlers.popover = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
var options = {
title: val.title,
animation: val.animation,
placement: val.placement,
trigger: val.trigger,
delay: val.delay,
content: val.content,
html: val.html
};
$(element).popover(options);
}
};

View file

@ -0,0 +1,24 @@
ko.bindingHandlers.qrcode = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
var defaultOptions = {
text: "",
size: 200,
fill: "#000",
background: null,
label: "",
fontname: "sans",
fontcolor: "#000",
radius: 0,
ecLevel: "L"
};
var options = {};
_.each(defaultOptions, function(value, key) {
options[key] = ko.utils.unwrapObservable(val[key]) || value;
});
$(element).empty().qrcode(options);
}
};

View file

@ -0,0 +1,17 @@
ko.bindingHandlers.slimScrolledForeach = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
return ko.bindingHandlers.foreach.init(element, valueAccessor(), allBindings, viewModel, bindingContext);
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
setTimeout(function() {
if (element.nodeName == "#comment") {
// foreach is bound to a virtual element
$(element.parentElement).slimScroll({scrollBy: 0});
} else {
$(element).slimScroll({scrollBy: 0});
}
}, 10);
return ko.bindingHandlers.foreach.update(element, valueAccessor(), allBindings, viewModel, bindingContext);
}
};
ko.virtualElements.allowedBindings.slimScrolledForeach = true;

View file

@ -0,0 +1,28 @@
ko.bindingHandlers.toggleContent = {
init: function(element, valueAccessor) {
var $elm = $(element),
options = $.extend({
class: null,
container: null,
parent: null,
onComplete: function() {
$(document).trigger("slideCompleted");
}
}, valueAccessor());
$elm.on("click", function(e) {
e.preventDefault();
if(options.class) {
$elm.children('[class^="icon-"]').toggleClass(options.class);
}
if(options.container) {
if(options.parent) {
$elm.parents(options.parent).find(options.container).stop().slideToggle('fast', options.onComplete);
} else {
$(options.container).stop().slideToggle('fast', options.onComplete);
}
}
});
}
};

View file

@ -304,97 +304,6 @@ $(function() {
var dataUpdater = new DataUpdater(allViewModels);
//~~ Custom knockout.js bindings
ko.bindingHandlers.popover = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
var options = {
title: val.title,
animation: val.animation,
placement: val.placement,
trigger: val.trigger,
delay: val.delay,
content: val.content,
html: val.html
};
$(element).popover(options);
}
};
ko.bindingHandlers.allowBindings = {
init: function (elem, valueAccessor) {
return { controlsDescendantBindings: !valueAccessor() };
}
};
ko.virtualElements.allowedBindings.allowBindings = true;
ko.bindingHandlers.slimScrolledForeach = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
return ko.bindingHandlers.foreach.init(element, valueAccessor(), allBindings, viewModel, bindingContext);
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
setTimeout(function() {
if (element.nodeName == "#comment") {
// foreach is bound to a virtual element
$(element.parentElement).slimScroll({scrollBy: 0});
} else {
$(element).slimScroll({scrollBy: 0});
}
}, 10);
return ko.bindingHandlers.foreach.update(element, valueAccessor(), allBindings, viewModel, bindingContext);
}
};
ko.virtualElements.allowedBindings.slimScrolledForeach = true;
ko.bindingHandlers.qrcode = {
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
var defaultOptions = {
text: "",
size: 200,
fill: "#000",
background: null,
label: "",
fontname: "sans",
fontcolor: "#000",
radius: 0,
ecLevel: "L"
};
var options = {};
_.each(defaultOptions, function(value, key) {
options[key] = ko.utils.unwrapObservable(val[key]) || value;
});
$(element).empty().qrcode(options);
}
};
ko.bindingHandlers.invisible = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
if (!valueAccessor()) return;
ko.bindingHandlers.style.update(element, function() {
return { visibility: 'hidden' };
})
}
};
ko.bindingHandlers.contextMenu = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
$(element).contextMenu(val);
},
update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var val = ko.utils.unwrapObservable(valueAccessor());
$(element).contextMenu(val);
}
};
//~~ some additional hooks and initializations
// make sure modals max out at the window height
@ -615,4 +524,3 @@ $(function() {
.done(bindViewModels);
}
);

View file

@ -49,7 +49,7 @@
<div data-bind="visible: languagePacksAvailable()">
<div id="settings_appearance_managelanguagesdialog_list" data-bind="slimScrolledForeach: translations.paginatedItems" style="height: 300px">
<div class="entry">
<strong><a href="#" onclick="$(this).children('i').toggleClass('icon-caret-right icon-caret-down').parent().parent().next().slideToggle('fast')"><i class="icon-caret-down"></i> <span data-bind="text: $root.languagePackDisplay($data)"></span></a></strong>
<strong><a href="#" data-bind="toggleContent: { class: 'icon-caret-right icon-caret-down', parent: '.entry', container: '.packs' }"><i class="icon-caret-down"></i> <span data-bind="text: $root.languagePackDisplay($data)"></span></a></strong>
<div class="packs">
<!-- ko foreach: $data.packs -->
<div class="row-fluid">

View file

@ -94,7 +94,7 @@
</div>
<div>
<div><small><a href="#" class="muted" onclick="$(this).children().toggleClass('icon-caret-right icon-caret-down').parent().parent().parent().next().slideToggle('fast')"><i class="icon-caret-right"></i> {{ _('Advanced options') }}</a></small></div>
<div><small><a href="#" class="muted" data-bind="toggleContent: { class: 'icon-caret-right icon-caret-down', container: '#settings_serialConnection .hide' }"><i class="icon-caret-right"></i> {{ _('Advanced options') }}</a></small></div>
<div class="hide">
<div class="control-group" title="{{ _('Command to send to the firmware on first handshake attempt.') }}">
<label class="control-label" for="settings-serialHelloCommand">{{ _('"Hello" command') }}</label>

View file

@ -12,7 +12,7 @@
{% include "_snippets/settings/webcam/ffmpegPath.jinja2" %}
{% include "_snippets/settings/webcam/watermark.jinja2" %}
<div>
<div><small><a href="#" class="muted" onclick="$(this).children().toggleClass('icon-caret-right icon-caret-down').parent().parent().parent().next().slideToggle('fast')"><i class="icon-caret-right"></i> {{ _('Advanced options') }}</a></small></div>
<div><small><a href="#" class="muted" data-bind="toggleContent: { class: 'icon-caret-right icon-caret-down', parent: '.form-horizontal', container: '.hide' }"><i class="icon-caret-right"></i> {{ _('Advanced options') }}</a></small></div>
<div class="hide">
{% include "_snippets/settings/webcam/ffmpegBitrate.jinja2" %}
{% include "_snippets/settings/webcam/ffmpegThreads.jinja2" %}

View file

@ -116,7 +116,7 @@
</script>
<script type="text/html" id="customControls_containerTemplate_collapsable">
<div class="custom_section">
<h1 onclick="$(this).children().first().toggleClass('icon-caret-down icon-caret-right').parent().next().slideToggle('fast')"><i data-bind="css: {'icon-caret-down': !collapsed, 'icon-caret-right': collapsed}"></i> <span data-bind="text: name"></span></h1>
<h1 data-bind="toggleContent: { class: 'icon-caret-right icon-caret-down', parent: '.custom_section', container: '> div' }"><i data-bind="css: {'icon-caret-down': !collapsed, 'icon-caret-right': collapsed}"></i> <span data-bind="text: name"></span></h1>
<!-- ko template: { name: 'customControls_containerTemplate', data: $data } --><!-- /ko -->
</div>
</script>

View file

@ -22,7 +22,7 @@
</div>
<div>
<div><small><a href="javascript:void(0);" class="muted" onclick="$(this).children().toggleClass('icon-caret-right icon-caret-down').parent().parent().parent().next().slideToggle('fast')"><i class="icon-caret-right"></i> {{ _('Advanced options') }}</a></small></div>
<div><small><a href="#" class="muted" data-bind="toggleContent: { class: 'icon-caret-right icon-caret-down', container: '#term .hide' }"><i class="icon-caret-right"></i> {{ _('Advanced options') }}</a></small></div>
<div class="hide">
<button class="btn btn-block" type="button" data-bind="click: fakeAck, enable: isOperational() && loginState.isUser()">{{ _("Fake Acknowledgement") }}</button>
<small class="muted">{{ _("If acknowledgements (\"ok\"s) sent by the firmware get lost due to issues with the serial communication to your printer, OctoPrint's communication with it can become stuck. If that happens, this can help. Please be advised that such occurences hint at general communication issues with your printer which will probably negatively influence your printing results and which you should therefore try to resolve!") }}</small>