Commit 59ec95a4 authored by BFischer's avatar BFischer
Browse files

MainView: rebuild rendering using vuejs

parent 5f8d4c07
......@@ -499,8 +499,58 @@
inset -1px 0px 0px #b8b8b8;
transition: background-color 50ms;
}
> .vispa-ui-tab, > .vispa-centerview-tab {
> .vispa-ui-tab {
position: relative;
width: @tab-max-width;
> .vispa-comp-icon {
left: 0px;
> button {
border: none;
background: inherit;
height: 100%;
width: @tab-bar-button-width;
padding: 0px;
font-size: 1.5em;
> i > i {
position: absolute;
height: 50%;
width: 50%;
font-size: 0.7em;
line-height: 0.7em;
top: 75%;
left: 85%;
}
}
}
> .vispa-comp-label {
left: @tab-bar-button-width;
right: @tab-cross-width;
font-size: 1.2em;
text-overflow: ellipsis;
}
> .vispa-comp-badge {
position: absolute;
right: @tab-cross-width;
}
> .vispa-comp-close {
right: 0px;
width: @tab-cross-width;
text-align: center;
> i {
font-size: 14px;
vertical-align: middle;
}
}
:hover {
color: black;
}
> * {
line-height: @tab-bar-height - 1px;
position: absolute;
display: inline-block;
vertical-align: middle;
height: 100%;
}
}
> .vispa-ui-spawner {
width: @tab-bar-button-width;
......
<div class="vispa-mainview">
<div class="vispa-table-outer vispa-modal" style="display:none;">
<div :class.once="'vispa-mainview ' + classTag">
<div v-show="loading" class="vispa-table-outer vispa-modal">
<div class="vispa-table-inner text-center">
<img data-bind="loader-img" />
<img :src.once="spinner"/>
</div>
</div>
<div class="vispa-messages"></div>
<div class="vispa-fastmenu"></div>
<div class="vispa-content"></div>
<div v-el:msg class="vispa-messages"></div>
<div v-el:content class="vispa-content"></div>
</div>
<div class="vispa-centerview-menu">
<div class="vispa-table-outer">
<div class="vispa-table-inner">
<button data-toggle="dropdown" class="btn btn-primary btn-xs dropdown-toggle">
<i class="glyphicon glyphicon-cog"></i>
</button>
<ul class="dropdown-menu">
<li class="divider"></li>
<li>
<a href="#">
<i class="glyphicon glyphicon-remove"></i>
<span>Close</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="vispa-mainview-tab vispa-ui-tab">
<div class="vispa-mainview-tab-icon">
<div class="vispa-table-outer">
<div class="vispa-table-inner text-center dropdown">
<a data-toggle="dropdown" href="#" class="dropdown">
<i id="tab-icon" class="vispa-icon vispa-icon-file"></i>
</a>
<ul class="dropdown-menu text-left"></ul>
</div>
</div>
</div>
<a href="#" class="vispa-mainview-tab-label vispa-ui-handle">
<div class="vispa-table-outer">
<div class="vispa-table-inner text-left" style="white-space:nowrap;">
<span class="vispa-rtl-fix">i</span>
<span data-bind="label">UNTITLED</span>
<span class="vispa-rtl-fix-hidden">i</span>
</div>
</div>
</a>
<a href="#" class="vispa-mainview-tab-cross">
<div class="vispa-table-outer">
<div class="vispa-table-inner text-center">
<i class="glyphicon glyphicon-remove"></i>
</div>
</div>
</a>
<div class="vispa-mainview-tab-badge">
<div class="vispa-table-inner">
<span class="badge"></span>
</div>
</div>
<div class="vispa-ui-tab">
<menu-button
:items="menuItems"
class="vispa-comp-icon"
v-ref:menu
>
<i :class="iconClass | iconPrefix">
<i class="fa fa-caret-down"></i>
</i>
</menu-button>
<span
class="vispa-comp-label vispa-ui-handle"
data-toggle="tooltip"
data-placement="bottom"
:title="labelFull"
@click="focus"
@vmousedown="hideTooltip"
@mouseup="mayClose"
v-el:label
>
{{labelShort}}
</span>
<span v-show="badge" class="vispa-comp-badge">
<span class="badge">{{badge}}</span>
</span>
<span
class="vispa-comp-close"
@click="close"
>
<i :class="closeIconFinal | iconPrefix"></i>
</span>
</div>
......@@ -5,18 +5,83 @@
define([
"jquery",
"vispa/views/base",
"async",
"vue/vue",
"vispa/vue/base",
"vispa/vue/menu",
"vispa/views/base",
"text!html/index/mainview/content.html",
"text!html/index/mainview/tab.html"
], function(
$,
BaseView,
async,
Vue,
VueBase,
VueMenu,
BaseView,
tContent,
tTab
) {
var MainViewTab = Vue.extend({
template: tTab.trim(),
props: ["iconClass", "menuItems", "labelFull", "labelShort", "closeIcon", "badge"],
ready: function() {
$(this.$els.label).tooltip()
},
watch: {
labelShort: function(newLabel, oldLabel) {
if (newLabel === oldLabel) return;
var $label = $(this.$els.label);
var wasShown = $label.hasClass("tooltip");
if (wasShown)
$label.tooltip("hide");
$label.tooltip("fixTitle");
if (wasShown)
$label.tooltip("show");
},
},
computed: {
instance: {
cached: false,
get: function() {
return this.$options.instance;
},
},
closeIconFinal: function() {
return this.closeIcon || "fa-times";
},
},
methods: {
focus: function(event) {
this.instance.focus();
event.preventDefault();
event.stopPropagation();
},
close: function(event) {
this.instance.close();
event.preventDefault();
event.stopPropagation();
},
hideTooltip: function() {
$(this).tooltip("hide");
},
mayClose: function(event) {
if (event.which == 2) {
event.preventDefault();
event.stopPropagation();
this.close();
}
},
},
});
var MainViewContent = Vue.extend({
template: tContent.trim(),
props: ["loading"],
});
// shimmed events
var EventsShimmed = ["focus","blur","show","hide","close","resize"];
......@@ -40,90 +105,66 @@ define([
this.master = vispa.mainViewManager;
this._label = null;
this._loadingTimeout = null;
// register shimmed events
for (var i=0; i < EventsShimmed.length; i++) {
var event = EventsShimmed[i];
var handler = "on" + event[0].toUpperCase() + event.substr(1);
this.on(event, this[handler]);
}
this.on("pushedMessage", function() {
if (!this._$nodes) return;
this._$nodes.tabBadge.text(this.messageCount || "");
// Vue now
this.vue = {};
this.vue.tab = new MainViewTab({
instance: this,
data: {
iconClass: "fa-file-o",
closeIcon: "",
badge: "",
labelFull: "",
labelShort: "",
menuItems: {
close: {
label: "close",
iconClass: "fa-times",
callback: function(){
this.root.instance.close();
},
},
},
},
});
this.vue.node = new MainViewContent({
data: {
loading: false,
spinner: vispa.url.static("img/maingui/loader6.gif"),
classTag: (this.extension?this.extension.name:"vispa-core-")+this._class._members.name.toLowerCase(),
},
});
var nodes = {};
// mount it
this.vue.tab.$mount();
this.vue.node.$mount();
// content
this.$node = nodes.root = $(tContent).render({}, {
"loader-img": {
src: function() {
return vispa.url.static("img/maingui/loader6.gif");
}
}
});
nodes.modal = $(".vispa-modal", nodes.root).first();
nodes.content = $(".vispa-content", nodes.root);
nodes.fastMenu = $(".vispa-fastmenu", nodes.root);
this.messageContainer = $(".vispa-messages", nodes.root);
// add the view name as a class to nodes.content
nodes.content.addClass(this.name);
// tab
nodes.tab = $(tTab).data("instanceId", this.id);
nodes.tabIconWrapper = $(".vispa-mainview-tab-icon", nodes.tab);
nodes.tabIconButton = $("a.dropdown", nodes.tabIconWrapper);
nodes.tabIcon = $("a.dropdown > i", nodes.tabIconWrapper);
nodes.tabLabel = $(".vispa-mainview-tab-label", nodes.tab);
nodes.tabCrossWrapper = $(".vispa-mainview-tab-cross", nodes.tab);
nodes.tabCross = $("i", nodes.tabCrossWrapper);
nodes.tabMenu = $("ul", nodes.tabIconWrapper);
nodes.tabBadge = $(".vispa-mainview-tab-badge span.badge", nodes.tab);
// tooltip
nodes.tabLabel.tooltip({
title: "UNTITLED",
placement: "bottom",
delay: {
show: 1000,
hide: 0
}
}).on("vmousedown", function() {
$(this).tooltip("hide");
}).on("mouseup", function(event) {
if (event.which == 2) {
self.close();
event.preventDefault();
event.stopPropagation();
}
});
// menu
// TODO: get the actual menu
// show event
nodes.tab.click(function(event) {
self.focus();
event.preventDefault();
// save the nodes
this.$node = $(this.vue.node.$el);
this.messageContainer = $(this.vue.node.$els.msg);
// setup events
this.on("focus", function(){
this.vue.tab.badge = "";
});
// close event
nodes.tabCrossWrapper.click(function(event) {
self.close();
event.preventDefault();
event.stopPropagation();
this.on("pushedMessage", function() {
this.vue.tab.badge = this.messageCount || "";
});
// register shimmed events
for (var i=0; i < EventsShimmed.length; i++) {
var event = EventsShimmed[i];
var handler = "on" + event[0].toUpperCase() + event.substr(1);
this.on(event, this[handler]);
}
this._$nodes = nodes;
// finally attach & render
this.master.attach(this, viewArgs);
this.render(nodes.content);
this.render(this.$content);
this.applyPreferences();
},
/** indent: 1
......@@ -135,7 +176,33 @@ define([
$tab: {
descriptor: true,
get: function() {
return this._$nodes.tab;
return $(this.vue.tab.$el);
}
},
/** indent: 1
* .. js:attribute:: $content read-only
* :type: jQuery
*
* The jQuery object containing the node that is holding the views content.
*/
$content: {
descriptor: true,
get: function() {
return $(this.vue.node.$els.content);
}
},
/** indent: 1
* .. js:attribute:: menu read-only
* :type: MenuButton
*
* The vue instance representing the menu of this view.
*/
menu: {
descriptor: true,
get: function() {
return this.vue.tab.$refs.menu;
}
},
......@@ -147,13 +214,6 @@ define([
enumerable: true,
},
focus: function focus(opts) {
if (this._$nodes) {
this._$nodes.tabBadge.text("");
}
focus._super.apply(this, arguments);
},
close: function close(force) {
if (force !== true && this.onBeforeClose() === false) return;
close._super.call(this);
......@@ -189,11 +249,6 @@ define([
return this.isManaged() ? this.master.isFocused(this) : null;
},
/// transparent override
applyPreferences: function applyPreferences() {
applyPreferences._super.call(this);
},
/// transparent override
setState: function setState() {
var lastFragment = this.getFragment();
......@@ -217,10 +272,10 @@ define([
icon: {
descriptor: true,
set: function(icon) {
this._$nodes.tabIcon.attr("class", icon);
this.vue.tab.iconClass = icon;
},
get: function() {
return this._$nodes.tabIcon.attr("class");
return this.vue.tab.iconClass;
}
},
......@@ -233,11 +288,12 @@ define([
* Setting this is the same as calling :js:func:`setLabel` with the new label and *false* as second parameter.
*/
label: {
descriptor: true,
set: function(label) {
this.setLabel(label, false);
},
get: function() {
return this._label;
return this.vue.tab.labelFull;
}
},
......@@ -251,8 +307,9 @@ define([
* :param Bool isPath: Wether the label ist to be interpreted as a path.
*/
setLabel: function setLabel(label, isPath) {
this.vue.tab.labelFull = label;
var split = label.split("/");
var tooltip = label;
var path = label;
if (isPath && split.length>1 && this.isManaged()) {
var peers = this.master.instances;
......@@ -276,21 +333,7 @@ define([
}
this._label = label = path;
if (!this._$nodes) {
return this;
}
this._$nodes.tabLabel.render({
label: label
});
var showTooltip = tabLabel.next().hasClass("tooltip");
tabLabel.tooltip("hide").attr("title", tooltip).tooltip("fixTitle");
if (showTooltip) {
tabLabel.tooltip("show");
}
this.vue.tab.labelShort = label;
},
/** indent: 1
......@@ -304,12 +347,10 @@ define([
modified: {
descriptor: true,
set: function(modified) {
if (!this._$nodes) return;
this._$nodes.tabCrossWrapper.toggleClass("modified", modified);
this.vue.tab.closeIcon = modified ? "fa-pencil" : "";
},
get: function() {
if (!this._$nodes) return null;
return this._$nodes.tabCrossWrapper.hasClass("modified");
return !!~this.vue.tab.closeIcon.indexOf("fa-pencil");
}
},
......@@ -331,10 +372,10 @@ define([
delay = 0.25;
}
var wasLoading = this.isLoading();
var wasLoading = this.loading;
setLoading._super.call(this, loading);
loading = this.isLoading();
var loading = this.loading;
if (loading == wasLoading) return;
// show/hide the modals
......@@ -347,8 +388,7 @@ define([
this._loadingTimeout = null;
var action = function() {
self._$nodes.modal[fn]();
self._$nodes.content.toggleClass("vispa-blur", loading);
self.vue.node.loading = loading;
};
if (delay>0) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment