From 8700a03cb622d8b458188b1d939686e05f325b11 Mon Sep 17 00:00:00 2001 From: exodus4d Date: Sun, 2 Nov 2014 23:24:11 +0100 Subject: [PATCH] multiple map instances support added --- .idea/jsLinters/jshint.xml | 68 +++++++ index.htm | 5 +- js/app/main.js | 83 ++++++-- js/app/map.js | 235 ++++++++++++----------- js/app/render.js | 3 + sass/_colors.scss | 4 +- sass/_variables.scss | 14 +- sass/bootstrap/_navs.scss | 1 - sass/layout/_main.scss | 5 +- sass/layout/_map.scss | 30 ++- sass/production.scss | 1 + sass/smartadmin/_component-jqueryui.scss | 2 +- sass/smartadmin/_main.scss | 27 +-- templates/modules/tabs.html | 11 ++ 14 files changed, 337 insertions(+), 152 deletions(-) create mode 100644 .idea/jsLinters/jshint.xml create mode 100644 templates/modules/tabs.html diff --git a/.idea/jsLinters/jshint.xml b/.idea/jsLinters/jshint.xml new file mode 100644 index 00000000..37cb5c1a --- /dev/null +++ b/.idea/jsLinters/jshint.xml @@ -0,0 +1,68 @@ + + + + + + diff --git a/index.htm b/index.htm index 7845490a..d8efbc78 100644 --- a/index.htm +++ b/index.htm @@ -15,12 +15,13 @@ -
+
-
+ +
diff --git a/js/app/main.js b/js/app/main.js index d4747a96..8b0e0ce3 100644 --- a/js/app/main.js +++ b/js/app/main.js @@ -1,19 +1,31 @@ -define(["jquery", "app/ccp", "app/map"], function($, CCP, Map) { +define(["jquery", "app/render", "app/ccp", "app/map"], function($, Render, CCP, Map) { "use strict"; + var config = { + mapModuleId: 'pf-map-module', + mapTabBarId: 'pf-map-tabs', + mapTabIdPrefix: 'pf-map-tab-' + }; + $(function() { //$('body').alpha().beta(); CCP.requestTrust(); + + + + + // Map init options - var mapOptions = { + var mapData =[{ map: {}, config: { name: 'WH Test', - id: 'pf-map-1', - scope: 'wormhole' + id: 1, + scope: 'wormhole', + icon: 'fa-desktop' }, data: { systems: [ @@ -69,16 +81,13 @@ define(["jquery", "app/ccp", "app/map"], function($, CCP, Map) { } - } - - Map.render(mapOptions); - - var mapOptions = { + },{ map: {}, config: { name: 'K-Space Test', - id: 'pf-map-2', - scope: 'wormhole' + id: 2, + scope: 'wormhole', + icon: 'fa-bookmark' }, data: { systems: [ @@ -107,12 +116,58 @@ define(["jquery", "app/ccp", "app/map"], function($, CCP, Map) { connections: [{ source: 50, target: 51, - type: 'wormhole' + type: 'wh' }] } - } + }]; - // Map.render(mapOptions); + + // load map navigation Bar and init map ========================================== + + var moduleConfig = { + name: 'modules/tabs', + position: $('#' + config.mapModuleId), + link: 'prepend', + functions: { + after: function(){ + // load first map i in first tab content container + var firstTabContentElement = $("div[data-map-tabs='" + config.mapTabBarId + "'] div:first-child"); + + firstTabContentElement.loadMap(mapData[0]); + + // load new map right after tab-change + $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { + var mapIndex = $(e.target).attr('data-map-index'); + var mapId = mapData[mapIndex].config.id; + $('#' + config.mapTabIdPrefix + mapId).loadMap(mapData[mapIndex]); + }); + } + } + }; + + var moduleData = { + id: config.mapTabBarId, + tabs: [] + }; + + // add new tab data for each map + $.each(mapData, function(i, data){ + + var active = false; + if(i === 0){ + active = true; + } + + moduleData.tabs.push({ + id: data.config.id, + index: i, + name: data.config.name, + icon: data.config.icon, + active: active + }); + }); + + Render.showModule(moduleConfig, moduleData); }); diff --git a/js/app/map.js b/js/app/map.js index eec8dbeb..767cae43 100644 --- a/js/app/map.js +++ b/js/app/map.js @@ -11,8 +11,8 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende y: 0 }, - containerMapWrapperId: 'pf-map-wrapper', // wrapper for maps - mapClass: 'pf-map', // class for a map + mapClass: 'pf-map', // class for all maps + mapIdPrefix: 'pf-map-', systemIdPrefix: 'pf-system-', // id prefix for a system systemClass: 'pf-system', systemActiveClass: 'pf-system-active', @@ -20,6 +20,10 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende systemBody: 'pf-system-body', dynamicElementWrapperId: 'pf-dialog-wrapper', // wrapper div for dynamic content (dialoges, context-menus,...) + // endpoint classes + endpointSourceClass: 'pf-map-endpoint-source', + endpointTargetClass: 'pf-map-endpoint-target', + // context menus connectionContextMenuId: 'pf-map-connection-contextmenu', systemContextMenuId: 'pf-map-system-contextmenu', @@ -72,23 +76,48 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende } }; + // active jsPlumb instances currently running + var activeInstances = {}; + // jsPlumb config var globalMapConfig = { source: { filter: '.' + config.systemHeadClass, - anchor: "Continuous", + anchor: 'Continuous', connector: [ "Bezier", { curviness: 40, cssClass: 'pf-map-connection-wh' } ], maxConnections: 5, allowLoopback:false, + cssClass: config.endpointSourceClass, onMaxConnections:function(info, e) { alert("Maximum connections (" + info.maxConnections + ") reached"); - } + }/*, + + overlays:[ + [ "Label", { + location:[0.5, 1.5], + label:"Drag", + cssClass:"endpointSourceLabel" + } ] + ] */ }, target: { filter: '.' + config.systemHeadClass, - anchor: "Continuous", - dropOptions:{ hoverClass: config.systemActiveClass }, + anchor: 'Continuous', allowLoopback:false, + cssClass: config.endpointTargetClass, + dropOptions: { + tolerance: 'touch', + hoverClass: config.systemActiveClass, + activeClass: 'dragActive' + }, + /*overlays:[ + [ "Label", { + location:[0.5, 1.5], + label:"Drag", + cssClass:"endpointSourceLabel" + } ] + ],*/ + beforeDrop: function(info){ // check function for new connection @@ -121,13 +150,13 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende } }; - var modulData = { + var moduleData = { id: config.errorConnectDialogId, titel: 'error: Loopback', content: 'Connection already exists.' }; - Render.showModule(moduleConfig, modulData); + Render.showModule(moduleConfig, moduleData); return false; @@ -280,7 +309,7 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende * draw a new map with all systems and connections * @param mapConfig */ - var drawMap = function(mapConfig){ + var drawMap = function(parentElement, mapConfig){ // create map body var mapWrapper = $('
', { @@ -288,13 +317,17 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende }); var mapContainer = $('
', { - id: mapConfig.config.id, + id: config.mapIdPrefix + mapConfig.config.id, class: config.mapClass }); mapWrapper.append(mapContainer); - $('#' + config.containerMapWrapperId).append(mapWrapper); + // append mapWrapper to parent element + $(parentElement).append(mapWrapper); + + // set main Container for current map -> the container exists now in DOM + mapConfig.map.setContainer($('#' + config.mapIdPrefix + mapConfig.config.id)); $.each(mapConfig.data.systems, function(i, data){ // draw a system to a map @@ -339,7 +372,7 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende */ var drawSystem = function(map, systemData, connectedSystems){ - var mapContainer = map.Defaults.Container; + var mapContainer = $(map.getContainer()); // TODO request missing system data if(!systemData.hasOwnProperty('id')){ @@ -355,9 +388,8 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende // get System Element by data var newSystem = getSystem(systemData); - var mapElement = $('#' + mapContainer); - mapElement.append(newSystem); + mapContainer.append(newSystem); // make new System dragable makeDraggable(map, newSystem); @@ -394,8 +426,10 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende */ var makeDraggable = function(map, systems){ + var mapContainer = $(map.getContainer()); + map.draggable(systems, { - containment: 'parent', + containment: mapContainer,// 'parent', zIndex: 2000, start: function(){ // drag start @@ -489,7 +523,7 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende setConnectionObserver(map, connection); return connection; - } + }; /** * load contextmenu template for connections @@ -551,10 +585,10 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende */ var setSystemObserver = function(map, systems){ - var mapContainer = map.Defaults.Container; + var mapContainer = $(map.getContainer()); // trigger context menu - $('#' + mapContainer).find(systems).on('contextmenu', function(e){ + $(mapContainer).find(systems).on('contextmenu', function(e){ $(e.target).trigger('pf:openContextMenu', [e, this]); e.preventDefault(); return false; @@ -628,14 +662,14 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende systemStatus.push(statusData); }) - var modulData = { + var moduleData = { id: config.systemDialogId, titel: 'Add new system', status: systemStatus, content: 'system dialog :)' }; - Render.showModule(moduleConfig, modulData); + Render.showModule(moduleConfig, moduleData); break; case 'info': console.log('info') break; @@ -672,6 +706,7 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende menuSelected: function (params){ var action = params.selectedMenu.attr('data-action'); + var activeConnection = params.component; switch(action){ case 'delete': @@ -701,37 +736,37 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende } }; - var modulData = { + var moduleData = { id: config.confirmDialogId, titel: 'Delete Connection', content: 'Is this connection really gone?' }; - Render.showModule(moduleConfig, modulData); + Render.showModule(moduleConfig, moduleData); break; case 'eol': // toggle eol-status of a connection - connection.toggleType('wh_eol'); + activeConnection.toggleType('wh_eol'); // for some reason a new observer is needed ?! - setConnectionObserver(map, connection); + setConnectionObserver(map, activeConnection); break; case 'status_fresh': - connection.removeType('wh_reduced'); - connection.removeType('wh_critical'); - setConnectionObserver(map, connection); + activeConnection.removeType('wh_reduced'); + activeConnection.removeType('wh_critical'); + setConnectionObserver(map, activeConnection); break; case 'status_reduced': - connection.removeType('wh_critical'); - connection.addType('wh_reduced'); - setConnectionObserver(map, connection); + activeConnection.removeType('wh_critical'); + activeConnection.addType('wh_reduced'); + setConnectionObserver(map, activeConnection); break; case 'status_critical': - connection.removeType('wh_reduced'); - connection.addType('wh_critical'); - setConnectionObserver(map, connection); + activeConnection.removeType('wh_reduced'); + activeConnection.addType('wh_critical'); + setConnectionObserver(map, activeConnection); break; case 'info': console.log('info'); @@ -747,96 +782,84 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende }); - } + }; - var render = function(mapConfig){ + var getMapInstance = function(mapId){ - // add context menues to dom + if(typeof activeInstances[mapId] !== 'object'){ + // create new instance + activeInstances[mapId] = jsPlumb.getInstance({ + Container: null, // will be set as soon as container is connected to DOM + PaintStyle:{ + lineWidth: 4, // width of a Connector's line. An integer. + strokeStyle: 'red', // color for a Connector + outlineColor: 'red', // color of the outline for an Endpoint or Connector. see fillStyle examples. + outlineWidth: 2 // width of the outline for an Endpoint or Connector. An integer. + }, + Connector:[ 'Bezier', { curviness: 40, cssClass: 'pf-map-connection-wh' } ], + Endpoint : ['Dot', {radius: 6}] + // Endpoint: 'Blank', // does not work... :( + // Scope: mapConfig.config.scope + }); + + console.log('new jsPlumbInstance: ' + mapId); + } + + + + return activeInstances[mapId]; + }; + + /** + * load system map into element + * @param mapConfig + */ + $.fn.loadMap = function(mapConfig){ + + // parent element where the map will be loaded + var parentElement = $(this); + + // add context menus to dom initConnectionContextMenu(); initSystemContextMenu(); - // init jsPlumb jsPlumb.ready(function() { - // get new map instance add to mapConfig - mapConfig.map = jsPlumb.getInstance({ - Container: mapConfig.config.id, - PaintStyle:{ - lineWidth: 5, // width of a Connector's line. An integer. - //fillStyle: "blue", // color for an Endpoint, eg. "blue", - strokeStyle: 'red', // color for a Connector - outlineColor: 'red', // color of the outline for an Endpoint or Connector. see fillStyle examples. - outlineWidth: 2 // width of the outline for an Endpoint or Connector. An integer. - //joinstyle:"round", - //dashstyle:"2 2", - }, - Connector:[ "Bezier", { curviness: 40, cssClass: 'pf-map-connection-wh' } ], - Anchor: "Continuous", - Endpoint: 'Blank', - Scope: mapConfig.config.scope - }); - // draw initial map - drawMap(mapConfig); + // get new map instance or load existing + mapConfig.map = getMapInstance(mapConfig.config.id); - //var systemElements = mapConfig.map.getSelector('.' + config.systemClass); + // check for map Container ( + if(mapConfig.map.getContainer() === undefined){ + // new map instance - var systemElements = $('#' + mapConfig.config.id).find('.' + config.systemClass); + // draw initial map and set container + drawMap(parentElement, mapConfig); - var dropOptions = { - tolerance:"touch", - hoverClass:"dropHover", - activeClass:"dragActive" - }; + // mapConfig.map.doWhileSuspended(function() { + // register all available connection types ============================= + mapConfig.map.registerConnectionTypes(globalMapConfig.connectionTypes); - // endpoint (system) config - var endpointConfig = { - endpoint: 'Blank', - //paintStyle:{ fillStyle: "blue", opacity: 0.5 }, - //Connector:[ "Bezier", { curviness: 40, cssClass: 'pf-map-connection-default' } ], - isSource: true, - scope: mapConfig.config.scope, - isTarget: true, - dropOptions : dropOptions - }; + // set up default connections + $.each(mapConfig.data.connections, function(i, connectionData){ + drawConnection(mapConfig.map, connectionData); + }); - // mapConfig.map.doWhileSuspended(function() { + mapConfig.map.fire("pf-map-loaded", mapConfig.map); - // register all available connection types ============================= - mapConfig.map.registerConnectionTypes(globalMapConfig.connectionTypes); + // }); - - // ======================================================== - - - var endpoints = mapConfig.map.addEndpoint(systemElements, { - }, endpointConfig); - - - // set up default connections - $.each(mapConfig.data.connections, function(i, connectionData){ - drawConnection(mapConfig.map, connectionData); + // global map observer for manual connections (drag & drop) + mapConfig.map.bind('connection', function(info, e) { + setConnectionObserver(mapConfig.map, info.connection); }); - // mapConfig.map.fire("pf-map-loaded", mapConfig.map); - - // }); - - // global map observer for manual connections (drag & drop) - mapConfig.map.bind('connection', function(info, e) { - - console.log('test') - - setConnectionObserver(mapConfig.map, info.connection); - }); - - // mapConfig.map.bind("beforeDrop", function(info) { - // manually connect - // }); - - + // mapConfig.map.bind("beforeDrop", function(info) { + // manually connect + // }); + } }); @@ -844,8 +867,4 @@ define(["jquery", "app/render", "jsPlumb", "app/contextmenu"], function($, Rende }; - - return { - render: render - }; }); \ No newline at end of file diff --git a/js/app/render.js b/js/app/render.js index fd0aadc3..baddd6c4 100644 --- a/js/app/render.js +++ b/js/app/render.js @@ -41,6 +41,9 @@ define(["jquery", "lib/mustache", "jqueryUI"], function($, Mustache) { // display module switch(config.link){ + case 'prepend': + config.position.prepend(content); + break; case 'after': config.position.after(content); break; diff --git a/sass/_colors.scss b/sass/_colors.scss index 2bbcef51..5afb2338 100644 --- a/sass/_colors.scss +++ b/sass/_colors.scss @@ -8,7 +8,7 @@ $gray-light: #63676a; $gray: #3c3f41; $gray-dark: #313335; $gray-darker: #2b2b2b; -$gray-daskest: #1d1d1d; +$gray-darkest: #1d1d1d; $gray-mid-light: lighten($black, 75%); @@ -45,7 +45,7 @@ $wh-color-redgiant: $red; $wh-color-pulsar: $blue; $wh-color-wolfryet: $orange; $wh-color-cataclysmic: $yellow-lighter; -$wh-color-blackhole: $gray-daskest; +$wh-color-blackhole: $gray-darkest; $brand-primary: #428bca !default; $brand-success: #5cb85c !default; diff --git a/sass/_variables.scss b/sass/_variables.scss index d3fe7755..2adffdb2 100644 --- a/sass/_variables.scss +++ b/sass/_variables.scss @@ -15,7 +15,7 @@ $bootstrap-sass-asset-helper: (twbs-font-path("") != unquote('twbs-font-path("") // ## Settings for some of the most global styles. //** Background color for ``. -$body-bg: #fff; +$body-bg: $gray-light; //** Global text color on ``. $text-color: $gray-dark; @@ -365,8 +365,8 @@ $navbar-inverse-toggle-border-color: #333; //## //=== Shared nav styles -$nav-link-padding: 9px 10px 10px; -$nav-link-hover-bg: $gray-lighter; +$nav-link-padding: 5px 6px 5px; +$nav-link-hover-bg: $gray-light; $nav-disabled-link-color: $gray-light; $nav-disabled-link-hover-color: $gray-light; @@ -374,13 +374,13 @@ $nav-disabled-link-hover-color: $gray-light; $nav-open-link-hover-color: #fff; //== Tabs -$nav-tabs-border-color: #ddd; +$nav-tabs-border-color: $gray-lighter; $nav-tabs-link-hover-border-color: $gray-lighter; -$nav-tabs-active-link-hover-bg: $body-bg; -$nav-tabs-active-link-hover-color: $gray; -$nav-tabs-active-link-hover-border-color: #ddd; +$nav-tabs-active-link-hover-bg: $gray-lighter; +$nav-tabs-active-link-hover-color: $gray-dark; //$gray-lighter; +$nav-tabs-active-link-hover-border-color: $gray-lighter; $nav-tabs-justified-link-border-color: #ddd; $nav-tabs-justified-active-link-border-color: $body-bg; diff --git a/sass/bootstrap/_navs.scss b/sass/bootstrap/_navs.scss index c690072b..820e116b 100644 --- a/sass/bootstrap/_navs.scss +++ b/sass/bootstrap/_navs.scss @@ -97,7 +97,6 @@ &:hover, &:focus { color: $nav-tabs-active-link-hover-color; - background-color: $nav-tabs-active-link-hover-bg; border: 1px solid $nav-tabs-active-link-hover-border-color; border-bottom-color: transparent; cursor: default; diff --git a/sass/layout/_main.scss b/sass/layout/_main.scss index ca468f49..9294e15e 100644 --- a/sass/layout/_main.scss +++ b/sass/layout/_main.scss @@ -2,5 +2,8 @@ body{ font-family: 'Oxygen Bold'; - color: $gray-lighter; +} + +#pf-map-module{ + margin: 10px; } \ No newline at end of file diff --git a/sass/layout/_map.scss b/sass/layout/_map.scss index de4afb1b..5bdb0492 100644 --- a/sass/layout/_map.scss +++ b/sass/layout/_map.scss @@ -2,10 +2,10 @@ background-color: $gray-darker; width: 1200px; height: 500px; - margin: 10px; position: relative; + overflow: hidden; - @include border-radius(5px); + @include border-bottom-radius(5px); border: { width: 1px; style: solid; @@ -30,6 +30,7 @@ .pf-system-head{ padding: 0px 3px 2px 3px; cursor: pointer; + color: $gray-lighter; } // System security ============================================= @@ -106,13 +107,11 @@ style: dashed; color: $gray-light; } - } } - } - .pf-system-active{ + .pf-system-active:not(.pf-map-endpoint-source):not(.pf-map-endpoint-target){ @include box-shadow($yellow-lighter 0px 0px 8px 1px); @include transition-duration(0.2s); } @@ -139,6 +138,27 @@ border-color: $teal; } + // Endpoints ==================================================== + .pf-map-endpoint-source, .pf-map-endpoint-target{ + + z-index: 50; + svg { + width: 10; + height: 10; + + *{ + stroke: $gray-light; + stroke-width: 2; // border width + fill: $gray; + cursor: pointer; + + &:hover{ + stroke: $gray-lightest; // hover style + } + } + + } + } // Connections ================================================== // default hover effect for all connections diff --git a/sass/production.scss b/sass/production.scss index 8c6f5a2e..42077d91 100644 --- a/sass/production.scss +++ b/sass/production.scss @@ -1,3 +1,4 @@ +@import "compass/css3/border-radius"; // Core variables and mixins @import "colors"; diff --git a/sass/smartadmin/_component-jqueryui.scss b/sass/smartadmin/_component-jqueryui.scss index 3a914151..08d6bc6e 100644 --- a/sass/smartadmin/_component-jqueryui.scss +++ b/sass/smartadmin/_component-jqueryui.scss @@ -440,7 +440,7 @@ margin-top: 13px; padding: 10px 10px 10px; text-align: right; - border-top: 1px solid $gray-daskest; + border-top: 1px solid $gray-darkest; background-color: $gray-light; } diff --git a/sass/smartadmin/_main.scss b/sass/smartadmin/_main.scss index 428f873c..5d8b0cb6 100644 --- a/sass/smartadmin/_main.scss +++ b/sass/smartadmin/_main.scss @@ -1836,6 +1836,10 @@ input[type="text"]:focus + .input-group-addon { /* * TABS */ +.nav-tabs{ + border-bottom: none; +} + .nav-tabs>li > a .badge { font-size: 11px; padding: 3px 5px 3px 5px; @@ -1844,9 +1848,7 @@ input[type="text"]:focus + .input-group-addon { min-width: 17px; font-weight: normal; } -.nav-tabs>li > a > .fa { - opacity: .5; -} + .tabs-left .nav-tabs>li > a .badge { margin-right:5px; margin-left:0px; @@ -1857,17 +1859,20 @@ input[type="text"]:focus + .input-group-addon { margin-left:5px; opacity: .5; } -.nav-tabs>li.active > a .badge, .nav-tabs>li.active > a .label, .nav-tabs>li.active > a > .fa{ - opacity: 1; -} + .nav-tabs>li>a { - border-radius:0px; - color:$gray-dark; + @include border-top-radius(5px); + color: $gray-lighter; + + &:hover{ + color: $gray-darkest; + } } .nav-tabs > li.active > a { - -webkit-box-shadow: 0 -2px 0 $blue; - -moz-box-shadow: 0 -2px 0 $blue; - box-shadow: 0 -2px 0 $blue; + @include box-shadow($orange 0 -2px 0); + + background-color: $gray-lighter; + color: $gray-darker; border-top-width: 0px !important; margin-top: 1px !important; font-weight:bold; diff --git a/templates/modules/tabs.html b/templates/modules/tabs.html new file mode 100644 index 00000000..c85a2eb8 --- /dev/null +++ b/templates/modules/tabs.html @@ -0,0 +1,11 @@ + + +
+ {{#tabs}} +
+ {{/tabs}} +
\ No newline at end of file