diff --git a/js/components/ComponentFactory.js b/js/components/ComponentFactory.js index dd080068e..4b2ad9369 100644 --- a/js/components/ComponentFactory.js +++ b/js/components/ComponentFactory.js @@ -30,7 +30,7 @@ define(function (require) { 'SHARE': 'interface/share/Share', 'INFOMODAL': 'controls/modals/InfoModal', 'MDMODAL': 'controls/modals/MarkDownModal', - 'QUERY': 'interface/query/query', + 'QUERY': 'interface/query/queryBuilder', 'TUTORIAL': 'interface/tutorial/Tutorial', 'PYTHONCONSOLE': 'interface/pythonConsole/PythonConsole', 'DICOMVIEWER': 'interface/dicomViewer/DicomViewer', @@ -200,7 +200,7 @@ define(function (require) { case 'SHARE': require(['./interface/share/Share'],cb); break; case 'INFOMODAL': require(['./controls/modals/InfoModal'],cb); break; case 'MDMODAL': require(['./controls/modals/MarkDownModal'],cb); break; - case 'QUERY': require(['./interface/query/query'],cb); break; + case 'QUERY': require(['./interface/query/queryBuilder'],cb); break; case 'TUTORIAL': require(['./interface/tutorial/Tutorial'],cb); break; case 'PYTHONCONSOLE': require(['./interface/pythonConsole/PythonConsole'],cb); break; case 'DICOMVIEWER': require(['./interface/dicomViewer/DicomViewer'],cb); break; diff --git a/js/components/interface/3dCanvas/ThreeDEngine.js b/js/components/interface/3dCanvas/ThreeDEngine.js index 3620f1ad3..106038877 100644 --- a/js/components/interface/3dCanvas/ThreeDEngine.js +++ b/js/components/interface/3dCanvas/ThreeDEngine.js @@ -28,11 +28,11 @@ define(['jquery'], function () { THREE.FilmPass = require('imports-loader?THREE=three!exports-loader?THREE.FilmPass!three\/examples\/js\/postprocessing\/FilmPass'); class ThreeDEngine { - constructor (container, viewerId) { + constructor(container, viewerId) { this.container = container; this.colorController = new (require('./ColorController'))(this); this.viewerId = viewerId; - // Engine components + //Engine components this.scene = new THREE.Scene(); this.camera = null; this.controls = null; @@ -42,16 +42,16 @@ define(['jquery'], function () { this.sceneCenter = new THREE.Vector3(); this.cameraPosition = new THREE.Vector3(); this.mouse = { x: 0, y: 0 }; - // The content of the scene + //The content of the scene this.meshes = {}; this.splitMeshes = {}; this.connectionLines = {}; this.visualModelMap = {}; this.complexity = 0; - this.sceneMaxRadius = 0; // maximum radius of bounding sphere in scene - this.linePrecisionMinRadius = 300; // Default expected minimum radius - this.minAllowedLinePrecision = 1; // default line precision, can't go lower than this - // Settings + this.sceneMaxRadius = 0; //maximum radius of bounding sphere in scene + this.linePrecisionMinRadius = 300; //Default expected minimum radius + this.minAllowedLinePrecision = 1; //default line precision, can't go lower than this + //Settings this.linesThreshold = 2000; this.baseZoom = 1; this.aboveLinesThreshold = false; @@ -64,7 +64,7 @@ define(['jquery'], function () { this.linesUserPreference = undefined; this.hoverListeners = undefined; this.THREE = THREE; - // Initialisation + //Initialisation this.setupCamera(); this.setupRenderer(); this.setupLights(); @@ -114,10 +114,8 @@ define(['jquery'], function () { * Set up the WebGL Renderer */ setupRenderer: function () { - /* - * Reuse a single WebGL renderer. - * NOTE: Recreating the renderer causes camera displacement on Chrome OSX. - */ + // Reuse a single WebGL renderer. + // NOTE: Recreating the renderer causes camera displacement on Chrome OSX. if (!this.canvasCreated) { this.renderer = new THREE.WebGLRenderer({ antialias: true, @@ -155,14 +153,14 @@ define(['jquery'], function () { var y = event.clientY; // If the mouse moved since the mousedown then don't consider this a selection - if (x != clientX || y != clientY) { + if (typeof clientX === 'undefined' || typeof clientY === 'undefined' || x != clientX || y != clientY) return; - } that.mouse.y = -((event.clientY - (that.renderer.domElement.getBoundingClientRect().top)) / that.renderer.domElement.getBoundingClientRect().height) * 2 + 1; that.mouse.x = ((event.clientX - (that.renderer.domElement.getBoundingClientRect().left)) / that.renderer.domElement.getBoundingClientRect().width) * 2 - 1; - // only for left click - if (event.button == 0) { + + if (event.button == 0) //only for left click + { if (that.pickingEnabled) { var intersects = that.getIntersectedObjects(); @@ -172,12 +170,10 @@ define(['jquery'], function () { // sort intersects var compare = function (a, b) { - if (a.distance < b.distance) { + if (a.distance < b.distance) return -1; - } - if (a.distance > b.distance) { + if (a.distance > b.distance) return 1; - } return 0; }; @@ -192,34 +188,30 @@ define(['jquery'], function () { instancePath = intersects[i].object.instancePath; geometryIdentifier = intersects[i].object.geometryIdentifier; } else { - // weak assumption: if the object doesn't have an instancePath its parent will + //weak assumption: if the object doesn't have an instancePath its parent will instancePath = intersects[i].object.parent.instancePath; geometryIdentifier = intersects[i].object.parent.geometryIdentifier; } if (instancePath != null || undefined) { var visible = eval(instancePath + '.visible'); if (intersects.length == 1 || i == intersects.length) { - // if there's only one element intersected we select it regardless of its opacity + //if there's only one element intersected we select it regardless of its opacity if (visible) { selected = instancePath; selectedIntersect = intersects[i]; break; } } else { - /* - *if there are more than one element intersected and opacity of the current one is less than 1 - *we skip it to realize a "pick through" - */ + //if there are more than one element intersected and opacity of the current one is less than 1 + //we skip it to realize a "pick through" var opacity = that.meshes[instancePath].defaultOpacity; if ((opacity == 1 && visible) || GEPPETTO.isKeyPressed("ctrl")) { selected = instancePath; selectedIntersect = intersects[i]; break; } else if (visible && opacity < 1 && opacity > 0) { - /* - *if only transparent objects intersected select first or the next down if - *one is already selected in order to enable "burrow through" sample. - */ + //if only transparent objects intersected select first or the next down if + //one is already selected in order to enable "burrow through" sample. if (selected == "" && !eval(instancePath + '.selected')) { selected = instancePath; selectedIntersect = intersects[i]; @@ -301,7 +293,7 @@ define(['jquery'], function () { } var color = new THREE.Color(this.backgroundColor); - // this.renderer.setClearColor(color, 1); + //this.renderer.setClearColor(color, 1); this.renderer.setPixelRatio(window.devicePixelRatio); this.renderer.autoClear = false; @@ -326,7 +318,7 @@ define(['jquery'], function () { this.composer.addPass(effectFilm); this.composer.addPass(effectFocus); } else { - // standard + //standard renderModel.renderToScreen = true; this.composer.addPass(renderModel); } @@ -365,15 +357,15 @@ define(['jquery'], function () { var bb = child.geometry.boundingBox; bb.translate(child.localToWorld(new THREE.Vector3())); - /* - * If min and max vectors are null, first values become - * default min and max - */ + // If min and max vectors are null, first values become + // default min and max if (aabbMin == null && aabbMax == null) { aabbMin = bb.min; aabbMax = bb.max; - } else { - // Compare other meshes, particles BB's to find min and max + } + + // Compare other meshes, particles BB's to find min and max + else { aabbMin.x = Math.min(aabbMin.x, bb.min.x); aabbMin.y = Math.min(aabbMin.y, bb.min.y); aabbMin.z = Math.min(aabbMin.z, bb.min.z); @@ -423,16 +415,17 @@ define(['jquery'], function () { * @param {WIDGET_EVENT_TYPE} event - Event that tells widgets what to do */ update: function (event, parameters) { - // reset plot's datasets + //reset plot's datasets if (event == GEPPETTO.WidgetsListener.WIDGET_EVENT_TYPE.RESET_DATA) { - } else if (event == GEPPETTO.Events.Experiment_update) { + } + else if (event == GEPPETTO.Events.Experiment_update) { this.scene.traverse(function (child) { if (child instanceof THREE.Points) { var instance = Instances.getInstance(child.instancePath); if (instance.getTimeSeries() != undefined && instance.getTimeSeries()[parameters.step] != undefined) { - // if we have recorded this object we'll have a timeseries + //if we have recorded this object we'll have a timeseries var particles = instance.getTimeSeries()[parameters.step].particles; for (var p = 0; p < particles.length; p++) { child.geometry.vertices[p].x = particles[p].x; @@ -548,9 +541,8 @@ define(['jquery'], function () { this.axis = new THREE.AxisHelper(200); this.scene.add(this.axis); } - } else { + } else this.scene.remove(this.axis); - } }, /** @@ -595,14 +587,14 @@ define(['jquery'], function () { getDefaultGeometryType: function () { // Unless it's being forced we use a threshold to decide whether to use lines or cylinders if (!this.aboveLinesThreshold) { - // Unless we are already above the threshold... + //Unless we are already above the threshold... this.aboveLinesThreshold = this.complexity > this.linesThreshold; if (this.aboveLinesThreshold) { if (this.linesUserInput && this.linesUserPreference == undefined) { - // we need to ask the user + //we need to ask the user this.linesUserPreference = confirm("The model you are loading has a complex morphology, would you like to render it using lines instead of 3D shapes? Be careful, choosing to use 3D shapes might crash your browser!"); } } @@ -610,7 +602,8 @@ define(['jquery'], function () { if (this.aboveLinesThreshold && this.linesUserInput) { geometry = this.linesUserPreference ? 'lines' : 'cylinders'; - } else { + } + else { geometry = this.aboveLinesThreshold ? 'lines' : 'cylinders'; } @@ -679,7 +672,7 @@ define(['jquery'], function () { checkVisualInstance: function (instance, lines, thickness) { var traversedInstances = []; if (instance.hasCapability(GEPPETTO.Resources.VISUAL_CAPABILITY)) { - // since the visualcapability propagates up through the parents we can avoid visiting things that don't have it + //since the visualcapability propagates up through the parents we can avoid visiting things that don't have it if ((instance.getType().getMetaType() != GEPPETTO.Resources.ARRAY_TYPE_NODE) && instance.getVisualType()) { this.buildVisualInstance(instance, lines, thickness); } @@ -736,13 +729,13 @@ define(['jquery'], function () { this.meshes[instancePath].input = false; this.meshes[instancePath].output = false; - // Split anything that was splitted before + //Split anything that was splitted before if (instancePath in this.splitMeshes) { var splitMeshes = this.splitMeshes; var elements = {}; for (var splitMesh in splitMeshes) { if (splitMeshes[splitMesh].instancePath == instancePath && splitMesh != instancePath) { - const visualObject = splitMesh.substring(instancePath.length + 1); + visualObject = splitMesh.substring(instancePath.length + 1); elements[visualObject] = ""; } } @@ -767,24 +760,22 @@ define(['jquery'], function () { var color = undefined; if (previous3DObject) { color = previous3DObject.material.defaultColor; - /* - * if an object already exists for this aspect we remove it. This could happen in case we are changing how an aspect - * is visualized, e.g. lines over tubes representation - */ + // if an object already exists for this aspect we remove it. This could happen in case we are changing how an aspect + // is visualized, e.g. lines over tubes representation this.scene.remove(previous3DObject); var splitMeshes = this.splitMeshes; for (var m in splitMeshes) { if (m.indexOf(instance.getInstancePath()) != -1) { this.scene.remove(splitMeshes[m]); - // splitMeshes[m] = null; + //splitMeshes[m] = null; } } } var that = this; - // TODO This can be optimised, no need to create both - var materials - = { + //TODO This can be optimised, no need to create both + var materials = + { "mesh": that.getMeshPhongMaterial(color), "line": that.getLineMaterial(thickness, color) }; @@ -804,7 +795,8 @@ define(['jquery'], function () { instanceObjects.push(threeDeeObjList[obj]); } } - } else if (threeDeeObjList.length == 1) { + } + else if (threeDeeObjList.length == 1) { // only one object in list, add it to local array and set instanceObjects.push(threeDeeObjList[0]); instanceObjects[0].instancePath = instance.getInstancePath(); @@ -826,9 +818,10 @@ define(['jquery'], function () { var visualType = instance.getVisualType(); if (visualType == undefined) { return threeDeeObjList; - } else { + } + else { if ($.isArray(visualType)) { - // TODO if there is more than one visual type we need to display all of them + //TODO if there is more than one visual type we need to display all of them visualType = visualType[0]; } } @@ -840,7 +833,8 @@ define(['jquery'], function () { threeDeeObjList.push(threeDeeObj); } } - } else if (visualType.getMetaType() == GEPPETTO.Resources.VISUAL_TYPE_NODE && visualType.getId() == "particles") { + } + else if (visualType.getMetaType() == GEPPETTO.Resources.VISUAL_TYPE_NODE && visualType.getId() == "particles") { var visualValue = instance.getVariable().getWrappedObj().initialValues[0].value; threeDeeObj = this.create3DObjectFromInstance(instance, visualValue, instance.getVariable().getId(), materials, lines); if (threeDeeObj) { @@ -876,14 +870,17 @@ define(['jquery'], function () { } mergedLines.vertices.push(obj.geometry.vertices[0]); mergedLines.vertices.push(obj.geometry.vertices[1]); - } else if (obj.geometry.type == "Geometry") { + } + else if (obj.geometry.type == "Geometry") { // This catches both Collada an OBJ if (objArray.length > 1) { throw Error("Merging of multiple OBJs or Colladas not supported"); - } else { + } + else { ret = obj; } - } else { + } + else { if (mergedMeshes === undefined) { mergedMeshes = new THREE.Geometry() } @@ -897,10 +894,8 @@ define(['jquery'], function () { }); if (mergedLines === undefined) { - /* - * There are no line geometries, we just create a mesh for the merge of the solid geometries - * and apply the mesh material - */ + // There are no line geometries, we just create a mesh for the merge of the solid geometries + // and apply the mesh material ret = new THREE.Mesh(mergedMeshes, materials["mesh"]); } else { ret = new THREE.LineSegments(mergedLines, materials["line"]); @@ -933,41 +928,41 @@ define(['jquery'], function () { var threeObject = null; if (lines === undefined) { - lines = this.getDefaultGeometryType() == 'lines'; + lines = this.getDefaultGeometryType() == 'lines' ? true : false; } var material = lines ? materials["line"] : materials["mesh"]; switch (node.eClass) { - case GEPPETTO.Resources.PARTICLES: - threeObject = this.createParticles(node); - break; + case GEPPETTO.Resources.PARTICLES: + threeObject = this.createParticles(node); + break; - case GEPPETTO.Resources.CYLINDER: - if (lines) { - threeObject = this.create3DLineFromNode(node, material); - } else { - threeObject = this.create3DCylinderFromNode(node, material); - } - this.complexity++; - break; + case GEPPETTO.Resources.CYLINDER: + if (lines) { + threeObject = this.create3DLineFromNode(node, material); + } else { + threeObject = this.create3DCylinderFromNode(node, material); + } + this.complexity++; + break; - case GEPPETTO.Resources.SPHERE: - if (lines) { - threeObject = this.create3DLineFromNode(node, material); - } else { - threeObject = this.create3DSphereFromNode(node, material); - } - this.complexity++; - break; - case GEPPETTO.Resources.COLLADA: - threeObject = this.loadColladaModelFromNode(node); - this.complexity++; - break; - case GEPPETTO.Resources.OBJ: - threeObject = this.loadThreeOBJModelFromNode(node); - this.complexity++; - break; + case GEPPETTO.Resources.SPHERE: + if (lines) { + threeObject = this.create3DLineFromNode(node, material); + } else { + threeObject = this.create3DSphereFromNode(node, material); + } + this.complexity++; + break; + case GEPPETTO.Resources.COLLADA: + threeObject = this.loadColladaModelFromNode(node); + this.complexity++; + break; + case GEPPETTO.Resources.OBJ: + threeObject = this.loadThreeOBJModelFromNode(node); + this.complexity++; + break; } if (threeObject) { threeObject.visible = true; @@ -1152,10 +1147,8 @@ define(['jquery'], function () { * @returns {THREE.Mesh} */ modify3DSphere: function (object, x, y, z, radius, material) { - /* - * Impossible to change the radius of a Sphere. - * Removing old object and creating a new one - */ + // Impossible to change the radius of a Sphere. + // Removing old object and creating a new one this.scene.remove(object); var mesh = this.add3DSphere(x, y, z, radius, material); mesh.instancePath = object.instancePath; @@ -1197,14 +1190,14 @@ define(['jquery'], function () { var geometry = new THREE.Geometry(); geometry.vertices.push( - new THREE.Vector3(x1, y1, z1),// vertex0 - new THREE.Vector3(x2, y2, z2),// 1 - new THREE.Vector3(x3, y3, z3),// 2 - new THREE.Vector3(x4, y4, z4)// 3 + new THREE.Vector3(x1, y1, z1),//vertex0 + new THREE.Vector3(x2, y2, z2),//1 + new THREE.Vector3(x3, y3, z3),//2 + new THREE.Vector3(x4, y4, z4)//3 ); geometry.faces.push( - new THREE.Face3(2, 1, 0),// use vertices of rank 2,1,0 - new THREE.Face3(3, 1, 2)// vertices[3],1,2... + new THREE.Face3(2, 1, 0),//use vertices of rank 2,1,0 + new THREE.Face3(3, 1, 2)//vertices[3],1,2... ); geometry.computeBoundingBox(); @@ -1241,7 +1234,7 @@ define(['jquery'], function () { textureURL, // Function when resource is loaded function (texture) { - // texture.minFilter = THREE.LinearFilter; + //texture.minFilter = THREE.LinearFilter; material.map = texture; texture.flipY = false; material.opacity = 0.3; @@ -1259,7 +1252,8 @@ define(['jquery'], function () { } ); - } else { + } + else { material.opacity = 0.3; material.transparent = true; material.color.setHex("0xb0b0b0"); @@ -1510,7 +1504,8 @@ define(['jquery'], function () { this.rotate = setInterval(function () { that.incrementCameraRotate(0.01, 0) }, 100); - } else { + } + else { this.movieMode(false); clearInterval(this.rotate); this.rotate = null; @@ -1559,7 +1554,8 @@ define(['jquery'], function () { } } - } else { + } + else { if (instancePath in this.meshes) { meshes.push(this.meshes[instancePath]); } @@ -1608,7 +1604,7 @@ define(['jquery'], function () { mesh.material.opacity = Math.max(0.5, mesh.material.defaultOpacity); if (GEPPETTO.isKeyPressed('c')) { mesh.geometry.computeBoundingBox(); - // let's set the center of rotation to the selected mesh + //let's set the center of rotation to the selected mesh this.controls.target.copy(mesh.position); this.controls.target.add(mesh.geometry.boundingBox.getCenter()); } @@ -1640,12 +1636,14 @@ define(['jquery'], function () { for (var i in meshes) { delete allOtherMeshes[meshes[i]]; } - } else if (G.getSelectionOptions().show_inputs) { + } + else if (G.getSelectionOptions().show_inputs) { var inputs = this.highlightInstances(true, GEPPETTO.Resources.INPUT); for (var i in inputs) { delete allOtherMeshes[inputs[i]]; } - } else if (G.getSelectionOptions().show_outputs) { + } + else if (G.getSelectionOptions().show_outputs) { var outputs = this.highlightInstances(true, GEPPETTO.Resources.OUTPUT); for (var o in outputs) { delete allOtherMeshes[outputs[o]]; @@ -1701,9 +1699,11 @@ define(['jquery'], function () { if (G.getSelectionOptions().show_inputs && G.getSelectionOptions().show_outputs) { this.highlightInstances(instancePath, false); - } else if (G.getSelectionOptions().show_inputs) { + } + else if (G.getSelectionOptions().show_inputs) { this.highlightInstances(instancePath, false, GEPPETTO.Resources.INPUT); - } else if (G.getSelectionOptions().show_outputs) { + } + else if (G.getSelectionOptions().show_outputs) { this.highlightInstances(instancePath, false, GEPPETTO.Resources.OUTPUT); } @@ -1734,7 +1734,7 @@ define(['jquery'], function () { /** * Show output connections for this object. - * + * @command AVisualCapability.highlightInstances() * @param {boolean} mode - Show or hide output connections */ @@ -1744,10 +1744,11 @@ define(['jquery'], function () { } var entity = eval(path); if (entity instanceof Instance || entity instanceof ArrayInstance) { - // show/hide connections + //show/hide connections if (mode) { this.highlightConnectedInstances(entity, type); - } else { + } + else { this.restoreConnectedInstancesColour(entity); } } else if (entity instanceof Type || entity instanceof Variable) { @@ -1787,12 +1788,10 @@ define(['jquery'], function () { * @param {boolean} * apply - Turn on or off the transparency */ - /* - * unselectedTransparent: function (apply) { - * GEPPETTO.SceneController.unselectedTransparent(this.meshes, apply); - * GEPPETTO.SceneController.unselectedTransparent(this.splitMeshes, apply); - * }, - */ + unselectedTransparent: function (apply) { + GEPPETTO.SceneController.unselectedTransparent(this.meshes, apply); + GEPPETTO.SceneController.unselectedTransparent(this.splitMeshes, apply); + }, /** * Make unselected instances transparent or not @@ -1917,9 +1916,8 @@ define(['jquery'], function () { if (!this.hasInstance(instancePath)) { return; } - if (typeof color === 'string') { + if (typeof color === 'string') color = color.replace(/0X/i, "#"); - } var meshes = this.getRealMeshesForInstancePath(instancePath); if (meshes.length > 0) { for (var i = 0; i < meshes.length; i++) { @@ -1945,7 +1943,7 @@ define(['jquery'], function () { getColor: function (instance) { var color = ""; if (typeof instance.getChildren === "function") { - // this is a an array, it will contain children + //this is a an array, it will contain children var children = instance.getChildren(); var color = ""; @@ -1954,7 +1952,8 @@ define(['jquery'], function () { var newColor = children[i].getColor(); if (color == "") { color = newColor; - } else if (color != newColor) { + } + else if (color != newColor) { return ""; } } @@ -1970,7 +1969,8 @@ define(['jquery'], function () { if (object.hasOwnProperty("material")) { if (color == "") { color = object.material.defaultColor; - } else if (color != object.material.defaultColor) { + } + else if (color != object.material.defaultColor) { return ""; } } @@ -2179,7 +2179,8 @@ define(['jquery'], function () { that.addMeshToZoomParameters(object, zoomParameters); } }); - } else { + } + else { zoomParameters = this.zoomIterator(instances[i].getChildren(), zoomParameters); } @@ -2209,31 +2210,33 @@ define(['jquery'], function () { for (var c = 0; c < connections.length; c++) { var connection = connections[c]; - var otherEndPath = connection.getA().getPath() == instance.getInstancePath() - ? connection.getB().getPath() - : connection.getA().getPath(); + var otherEndPath = connection.getA().getPath() == instance.getInstancePath() ? + connection.getB().getPath() : + connection.getA().getPath(); - var connectionType = connection.getA().getPath() == instance.getInstancePath() - ? GEPPETTO.Resources.OUTPUT - : GEPPETTO.Resources.INPUT; + var connectionType = connection.getA().getPath() == instance.getInstancePath() ? + GEPPETTO.Resources.OUTPUT : + GEPPETTO.Resources.INPUT; // determine whether connection is input or output if (connectionType == GEPPETTO.Resources.INPUT) { - // I want to change the colour the instances that are an input to the instance passed as a parameter - var mesh = this.meshes[connection.getA().getPath()]; // this is the instance input to the current one + //I want to change the colour the instances that are an input to the instance passed as a parameter + var mesh = this.meshes[connection.getA().getPath()]; //this is the instance input to the current one if (outputs[otherEndPath]) { this.setThreeColor(mesh.material.color, GEPPETTO.Resources.COLORS.INPUT_AND_OUTPUT); - } else { + } + else { this.setThreeColor(mesh.material.color, GEPPETTO.Resources.COLORS.INPUT_TO_SELECTED); } inputs[otherEndPath] = connection.getInstancePath(); } else if (connectionType == GEPPETTO.Resources.OUTPUT) { - // I want to change the colour the instances that are an output of the instance passed as a parameter - var mesh = this.meshes[connection.getB().getPath()]; // this is the instance output of the current on + //I want to change the colour the instances that are an output of the instance passed as a parameter + var mesh = this.meshes[connection.getB().getPath()]; //this is the instance output of the current on if (inputs[otherEndPath]) { this.setThreeColor(mesh.material.color, GEPPETTO.Resources.COLORS.INPUT_AND_OUTPUT); - } else { + } + else { this.setThreeColor(mesh.material.color, GEPPETTO.Resources.COLORS.OUTPUT_TO_SELECTED); } outputs[otherEndPath] = connection.getInstancePath(); @@ -2270,17 +2273,15 @@ define(['jquery'], function () { for (var c = 0; c < connections.length; c++) { var connection = connections[c]; - var mesh = connection.getA().getPath() == instance.getInstancePath() - ? this.meshes[connection.getB().getPath()] - : this.meshes[connection.getA().getPath()]; + var mesh = connection.getA().getPath() == instance.getInstancePath() ? + this.meshes[connection.getB().getPath()] : + this.meshes[connection.getA().getPath()]; // if mesh is not selected, give it ghost or default color and opacity if (!mesh.selected) { - /* - * if there are nodes still selected, give it a ghost effect. If not nodes are - * selected, give the meshes old default color - */ + // if there are nodes still selected, give it a ghost effect. If not nodes are + // selected, give the meshes old default color if (G.getSelectionOptions().unselected_transparent) { mesh.material.transparent = true; mesh.material.opacity = GEPPETTO.Resources.OPACITY.GHOST; @@ -2288,8 +2289,9 @@ define(['jquery'], function () { } this.setThreeColor(mesh.material.color, mesh.material.defaultColor); - } else { - // if mesh is selected, make it look like so + } + // if mesh is selected, make it look like so + else { this.setThreeColor(mesh.material.color, GEPPETTO.Resources.COLORS.SELECTED); mesh.material.transparent = true; mesh.material.opacity = GEPPETTO.Resources.OPACITY.DEFAULT; @@ -2301,7 +2303,7 @@ define(['jquery'], function () { /** * Show connection lines for this instance. - * + * @command AVisualCapability.showConnectionLines() * @param {boolean} mode - Show or hide connection lines * @param instancePath @@ -2312,10 +2314,11 @@ define(['jquery'], function () { } var entity = eval(instancePath); if (entity instanceof Instance || entity instanceof ArrayInstance) { - // show or hide connection lines + //show or hide connection lines if (mode) { this.showConnectionLinesForInstance(entity); - } else { + } + else { this.removeConnectionLines(entity); } } else if (entity instanceof Type || entity instanceof Variable) { @@ -2346,9 +2349,9 @@ define(['jquery'], function () { for (var c = 0; c < connections.length; c++) { var connection = connections[c]; - var type = connection.getA().getPath() == instance.getInstancePath() - ? GEPPETTO.Resources.OUTPUT - : GEPPETTO.Resources.INPUT; + var type = connection.getA().getPath() == instance.getInstancePath() ? + GEPPETTO.Resources.OUTPUT : + GEPPETTO.Resources.INPUT; var thisEnd = connection.getA().getPath() == instance.getInstancePath() ? connection.getA() : connection.getB(); var otherEnd = connection.getA().getPath() == instance.getInstancePath() ? connection.getB() : connection.getA(); @@ -2360,19 +2363,21 @@ define(['jquery'], function () { var origin; if (thisEnd.getPoint() == undefined) { - // same as before + //same as before origin = defaultOrigin; - } else { - // the specified coordinate + } + else { + //the specified coordinate var p = thisEnd.getPoint(); origin = new THREE.Vector3(p.x + mesh.position.x, p.y + mesh.position.y, p.z + mesh.position.z); } if (otherEnd.getPoint() == undefined) { - // same as before + //same as before destination = otherEndMesh.position.clone(); - } else { - // the specified coordinate + } + else { + //the specified coordinate var p = otherEnd.getPoint(); destination = new THREE.Vector3(p.x + otherEndMesh.position.x, p.y + otherEndMesh.position.y, p.z + otherEndMesh.position.z); } @@ -2397,11 +2402,14 @@ define(['jquery'], function () { if (inputs[otherEndPath]) { inputs[otherEndPath].push(connection.getInstancePath()); - } else { + } + else { inputs[otherEndPath] = []; inputs[otherEndPath].push(connection.getInstancePath()); } - } else if (type == GEPPETTO.Resources.OUTPUT) { + } + + else if (type == GEPPETTO.Resources.OUTPUT) { colour = GEPPETTO.Resources.COLORS.OUTPUT_TO_SELECTED; // figure out if connection is both, input and output @@ -2411,7 +2419,8 @@ define(['jquery'], function () { if (outputs[otherEndPath]) { outputs[otherEndPath].push(connection.getInstancePath()); - } else { + } + else { outputs[otherEndPath] = []; outputs[otherEndPath].push(connection.getInstancePath()); } @@ -2472,7 +2481,7 @@ define(['jquery'], function () { */ splitHighlightedMesh: function (targetObjects, aspects) { var groups = {}; - for (let a in aspects) { + for (a in aspects) { // create object to hold geometries used for merging objects in groups var geometryGroups = {}; @@ -2494,7 +2503,7 @@ define(['jquery'], function () { * loop through individual meshes, add them to group, set * new material to them */ - for (let v in map) { + for (v in map) { var m = this.visualModelMap[map[v]]; if (m.instancePath in targetObjects) { // merged mesh into corresponding geometry @@ -2530,7 +2539,7 @@ define(['jquery'], function () { highlight: function (targetObjects, aspects, mode) { var splitHighlightedGroups = this.splitHighlightedMesh(targetObjects, aspects); - for (let groupName in splitHighlightedGroups) { + for (groupName in splitHighlightedGroups) { // get group mesh var groupMesh = this.splitMeshes[groupName]; @@ -2621,10 +2630,8 @@ define(['jquery'], function () { } } - /* - * if visual object didn't belong to group, add it to mesh - * with remainder of them - */ + // if visual object didn't belong to group, add it to mesh + // with remainder of them if (!added) { var geometry = geometryGroups[instancePath]; if (m instanceof THREE.Line) { @@ -2693,7 +2700,7 @@ define(['jquery'], function () { mergedMesh.visible = false; this.scene.remove(mergedMesh); - for (let g in groups) { + for (g in groups) { var groupName = g; if (groupName.indexOf(instancePath) <= -1) { groupName = instancePath + "." + g; @@ -2811,7 +2818,7 @@ define(['jquery'], function () { */ showVisualGroupsRaw: function (visualGroups, instance, meshesContainer) { var instancePath = instance.getInstancePath(); - for (let g in visualGroups) { + for (g in visualGroups) { // retrieve visual group object var visualGroup = visualGroups[g]; @@ -2843,7 +2850,7 @@ define(['jquery'], function () { if (mode) { var mergedMesh = this.meshes[instancePath]; var map = mergedMesh.mergedMeshesPaths; - // no mergedMeshesPaths means object hasn't been merged, single object + //no mergedMeshesPaths means object hasn't been merged, single object if (map != undefined || null) { this.splitGroups(instance, visualGroups); this.showVisualGroupsRaw(visualGroups, instance, this.splitMeshes); @@ -2932,7 +2939,7 @@ define(['jquery'], function () { * Traverse through THREE object to calculate that maximun radius based * on bounding sphere of visible objects */ - calculateSceneMaxRadius (object) { + calculateSceneMaxRadius(object) { var currentRadius = 0; if (object.children.length > 0) { for (var i = 0; i < object.children.length; i++) { @@ -2956,7 +2963,7 @@ define(['jquery'], function () { /** * Calculates linePrecision used by raycaster when picking objects. */ - getLinePrecision () { + getLinePrecision() { this.rayCasterLinePrecision = this.sceneMaxRadius / this.linePrecisionMinRadius; if (this.rayCasterLinePrecision < this.minAllowedLinePrecision) { this.rayCasterLinePrecision = this.minAllowedLinePrecision; @@ -2967,7 +2974,7 @@ define(['jquery'], function () { } } - ; + ; return ThreeDEngine; -}); \ No newline at end of file +}); diff --git a/js/components/interface/query/customComponents/queryLinkComponent.js b/js/components/interface/query/customComponents/queryLinkComponent.js new file mode 100644 index 000000000..c879e05b4 --- /dev/null +++ b/js/components/interface/query/customComponents/queryLinkComponent.js @@ -0,0 +1,38 @@ +define(function (require) { + + require("../query.less"); + require("../react-simpletabs.less"); + + var React = require('react'); + var GEPPETTO = require('geppetto'); + + class QueryLinkComponent extends React.Component { + constructor (props) { + super(props); + } + + render () { + + var displayText = this.props.data; + var path = this.props.rowData.id; + var that = this; + + var action = function (e) { + e.preventDefault(); + e.nativeEvent.stopImmediatePropagation(); + var actionStr = that.props.metadata.actions; + actionStr = actionStr.replace(/\$entity\$/gi, path); + GEPPETTO.CommandController.execute(actionStr); + that.props.metadata.queryBuilder.close(); + }; + + return ( +
+ {displayText} +
+ ) + } + } + + return QueryLinkComponent; +}); \ No newline at end of file diff --git a/js/components/interface/query/customComponents/queryResultsControlsComponent.js b/js/components/interface/query/customComponents/queryResultsControlsComponent.js new file mode 100644 index 000000000..31f04bb84 --- /dev/null +++ b/js/components/interface/query/customComponents/queryResultsControlsComponent.js @@ -0,0 +1,132 @@ +define(function (require) { + + require("../query.less"); + require("../react-simpletabs.less"); + + var React = require('react'); + var GEPPETTO = require('geppetto'); + + class QueryResultsControlsComponent extends React.Component { + constructor (props) { + super(props); + + } + + replaceTokensWithPath (inputStr, path) { + return inputStr.replace(/\$ID\$/gi, path); + } + + getActionString (control, path) { + var actionStr = ''; + + if (control.actions.length > 0) { + for (var i = 0; i < control.actions.length; i++) { + actionStr += ((i != 0) ? ";" : "") + this.replaceTokensWithPath(control.actions[i], path); + } + } + + return actionStr; + } + + resolveCondition (control, path, negateCondition) { + if (negateCondition == undefined) { + negateCondition = false; + } + + var resolvedConfig = control; + + if (resolvedConfig.hasOwnProperty('condition')) { + // evaluate condition and reassign control depending on results + var conditionStr = this.replaceTokensWithPath(control.condition, path); + if (eval(conditionStr)) { + resolvedConfig = negateCondition ? resolvedConfig.false : resolvedConfig.true; + } else { + resolvedConfig = negateCondition ? resolvedConfig.true : resolvedConfig.false; + } + } + + return resolvedConfig; + } + + render () { + // TODO: would be nicer to pass controls and config straight from the parent component rather than assume + var config = this.props.metadata.queryBuilder.state.resultsControlsConfig; + var resultItemId = this.props.rowData.id; + var ctrlButtons = []; + + // Add common control buttons to list + for (var control in config.Common) { + var add = true; + + // check show condition + if (config.Common[control].showCondition != undefined) { + var condition = this.replaceTokensWithPath(config.Common[control].showCondition, resultItemId); + add = eval(condition); + } + + if (add) { + ctrlButtons.push(config.Common[control]); + } + } + + var that = this; + + return ( +
+ {ctrlButtons.map(function (control, id) { + // grab attributes to init button attributes + var controlConfig = that.resolveCondition(control, resultItemId); + var idVal = resultItemId.replace(/\./g, '_').replace(/\[/g, '_').replace(/\]/g, '_') + "_" + controlConfig.id + "_queryResults_btn"; + var tooltip = controlConfig.tooltip; + var classVal = "btn queryresults-button fa " + controlConfig.icon; + var styleVal = {}; + + // define action function + var actionFn = function (param) { + // NOTE: there is a closure on 'control' so it's always the right one + var controlConfig = that.resolveCondition(control, resultItemId); + + // take out action string + var actionStr = that.getActionString(controlConfig, resultItemId); + + if (param != undefined) { + actionStr = actionStr.replace(/\$param\$/gi, param); + } + + // run action + if (actionStr != '' && actionStr != undefined) { + GEPPETTO.CommandController.execute(actionStr); + // check custom action to run after configured command + if (that.props.metadata.action != '' && that.props.metadata.action != undefined) { + // straight up eval as we don't want this to show on the geppetto console + eval(that.props.metadata.action.replace(/\$ID\$/gi, resultItemId)); + } + } + + // if conditional, swap icon with the other condition outcome + if (control.hasOwnProperty('condition')) { + var otherConfig = that.resolveCondition(control, path); + var element = $('#' + idVal); + element.removeClass(); + element.addClass("btn queryresults-button fa " + otherConfig.icon); + } + }; + + return ( + + + + ) + })} +
+ ) + } + } + + return QueryResultsControlsComponent; +}); \ No newline at end of file diff --git a/js/components/interface/query/customComponents/slideshowImageComponent.js b/js/components/interface/query/customComponents/slideshowImageComponent.js new file mode 100644 index 000000000..d089e9236 --- /dev/null +++ b/js/components/interface/query/customComponents/slideshowImageComponent.js @@ -0,0 +1,138 @@ +define(function (require) { + + require("../query.less"); + require("../react-simpletabs.less"); + + var React = require('react'); + var GEPPETTO = require('geppetto'); + var slick = require('slick-carousel'); + + class SlideshowImageComponent extends React.Component { + constructor (props) { + super(props); + + this.state = { carouselFullyLoaded: false }; + + this.isCarousel = false; + this.imageContainerId = ''; + this.fullyLoaded = false; + } + + getImageClickAction (path) { + var that = this; + + var action = function (e) { + e.preventDefault(); + e.nativeEvent.stopImmediatePropagation(); + var actionStr = that.props.metadata.actions; + actionStr = actionStr.replace(/\$entity\$/gi, path); + GEPPETTO.CommandController.execute(actionStr); + that.props.metadata.queryBuilder.close(); + }; + + return action; + } + + componentDidMount () { + // apply carousel + if (this.isCarousel) { + var slickDivElement = $('#' + this.imageContainerId + '.slickdiv'); + slickDivElement.slick(); + var that = this; + + // reload slick carousel if it's first time clicking on arrow in any direction + slickDivElement.find(".slick-arrow").on("click", function () { + if (!that.fullyLoaded) { + that.setState({ carouselFullyLoaded: true }); + that.fullyLoaded = true; + } + }, { passive: true }); + } + } + + componentDidUpdate () { + // on component refresh, update slick carousel + $('#' + this.imageContainerId + '.slickdiv').slick('unslick').slick(); + } + + buildImage (thumbImage, imageContainerId) { + var action = this.getImageClickAction(thumbImage.reference); + const imgElement =
+ + + +
+ return imgElement; + } + + buildCarousel () { + var jsonImageVariable = JSON.parse(this.props.data); + var imgElement = ""; + + if (jsonImageVariable.initialValues[0] != undefined) { + var imageContainerId = this.props.rowData.id + '-image-container'; + this.imageContainerId = imageContainerId; + + var value = jsonImageVariable.initialValues[0].value; + if (value.eClass == GEPPETTO.Resources.ARRAY_VALUE) { + if (value.elements.length > 1) { + this.isCarousel = true; + var imagesToLoad = 2; + if (this.state.carouselFullyLoaded) { + imagesToLoad = value.elements.length; + } + + // set flag to fully loaded if total length of images to render is less or equal to 2 + if (value.elements.length <= 2) { + this.fullyLoaded = true; + } + + var that = this; + // if it's an array, create a carousel (relies on slick) + var elements = value.elements.map(function (item, key) { + if (key < imagesToLoad) { + var image = item.initialValue; + var action = that.getImageClickAction(image.reference); + return
{image.name} + + + +
+ } + }); + + elements = elements.slice(0, imagesToLoad); + + imgElement =
+ {elements} +
+ } else { + imgElement = this.buildImage(value.elements[0].initialValue, imageContainerId); + } + } else if (value.eClass == GEPPETTO.Resources.IMAGE) { + // otherwise we just show an image + imgElement = this.buildImage(value, imageContainerId); + } + } + + return imgElement; + } + + + render () { + var imgElement = ""; + if (this.props.data != "" && this.props.data != undefined) { + imgElement = this.buildCarousel(); + } + + return ( +
+ {imgElement} +
+ ) + } + } + + return SlideshowImageComponent; +}); diff --git a/js/components/interface/query/query.js b/js/components/interface/query/queryBuilder.js similarity index 60% rename from js/components/interface/query/query.js rename to js/components/interface/query/queryBuilder.js index 4a9906c42..2d1c23452 100644 --- a/js/components/interface/query/query.js +++ b/js/components/interface/query/queryBuilder.js @@ -3,20 +3,16 @@ define(function (require) { require("./query.less"); require("./react-simpletabs.less"); - var CreateClass = require('create-react-class'), $ = require('jquery'); var React = require('react'); - var AppBar = require('@material-ui/core/AppBar').default; - var Tab = require('@material-ui/core/Tab').default; - var Tabs = require('@material-ui/core/Tabs').default; - var Typography = require('@material-ui/core/Typography').default; + var GEPPETTO = require('geppetto'); + var Handlebars = require('handlebars'); var Griddle = require('griddle-0.6-fork'); - var typeahead = require("typeahead.js/dist/typeahead.jquery.min.js"); + var QueryItem = require('./queryItem.js'); + var QueryFooter = require('./queryFooter.js'); var Bloodhound = require("typeahead.js/dist/bloodhound.min.js"); - var Handlebars = require('handlebars'); - var GEPPETTO = require('geppetto'); - var slick = require('slick-carousel'); - + var Typography = require('@material-ui/core/Typography').default; var MenuButton = require('../../controls/menuButton/MenuButton'); + var typeahead = require("typeahead.js/dist/typeahead.jquery.min.js"); var resultsViewState = false; @@ -24,6 +20,7 @@ define(function (require) { var queryBuilderModel = { // list of change handlers called on change onChangeHandlers: [], + handlerContext: [], // query items present in the query builder items: [], // fetched results @@ -32,18 +29,20 @@ define(function (require) { count: 0, // subscribe to model change notifications - subscribe: function (callback) { + subscribe (callback, context) { this.onChangeHandlers.push(callback); + this.handlerContext.push(context); }, // notify to all listeners that the model has changed - notifyChange: function () { + notifyChange () { this.onChangeHandlers.forEach(function (cb) { - cb(); - }); + let boundCallback = cb.bind(this); + boundCallback(); + }.bind(this.handlerContext[0])); }, - itemSelectionChanged: function (item, selection, callback) { + itemSelectionChanged (item, selection, callback) { for (var i = 0; i < this.items.length; i++) { if (item.id == this.items[i].id) { this.items[i].selection = selection; @@ -56,7 +55,7 @@ define(function (require) { }, // add query item to model - addItem: function (item, callback) { + addItem (item, callback) { this.items.push(item); // get count triggers notify change once results are fetched @@ -64,7 +63,7 @@ define(function (require) { }, // delete single query item from model - deleteItem: function (item, callback) { + deleteItem (item, callback) { for (var i = 0; i < this.items.length; i++) { if (item.id == this.items[i].id) { this.items.splice(i, 1); @@ -81,14 +80,14 @@ define(function (require) { }, // clear all query items from model - clearItems: function () { + clearItems () { this.items = []; this.count = 0; this.notifyChange(); }, // Asynchronous call to the server to get the results count for the given query items - getCount: function (callback) { + getCount (callback) { var queryDTOs = []; for (var i = 0; i < this.items.length; i++) { @@ -110,13 +109,13 @@ define(function (require) { GEPPETTO.QueriesController.getQueriesCount(queryDTOs, getCountDoneCallback.bind(this)); }, - setCount: function (count, callback) { + setCount (count, callback) { this.count = count; callback(); this.notifyChange(); }, - addResults: function (results) { + addResults (results) { // loop results and unselect all for (var i = 0; i < this.results.length; i++) { this.results[i].selected = false; @@ -127,7 +126,7 @@ define(function (require) { this.notifyChange(); }, - deleteResults: function (results) { + deleteResults (results) { GEPPETTO.CommandController.log("delete results", true); for (var i = 0; i < this.results.length; i++) { if (results.id == this.results[i].id) { @@ -138,7 +137,7 @@ define(function (require) { this.notifyChange(); }, - resultSelectionChanged: function (resultsSetId) { + resultSelectionChanged (resultsSetId) { // loop results and change selection for (var i = 0; i < this.results.length; i++) { if (this.results[i].id == resultsSetId) { @@ -156,521 +155,236 @@ define(function (require) { } }; - GEPPETTO.QueryLinkComponent = CreateClass({ - render: function () { - - var displayText = this.props.data; - var path = this.props.rowData.id; - var that = this; - - var action = function (e) { - e.preventDefault(); - e.nativeEvent.stopImmediatePropagation(); - var actionStr = that.props.metadata.actions; - actionStr = actionStr.replace(/\$entity\$/gi, path); - GEPPETTO.CommandController.execute(actionStr); - $("#querybuilder").hide(); - }; - - return ( -
- {displayText} -
- ) - } - }); - - GEPPETTO.SlideshowImageComponent = CreateClass({ - isCarousel: false, - - imageContainerId: '', - fullyLoaded: false, - - getImageClickAction: function (path) { - var that = this; - - var action = function (e) { - e.preventDefault(); - e.nativeEvent.stopImmediatePropagation(); - var actionStr = that.props.metadata.actions; - actionStr = actionStr.replace(/\$entity\$/gi, path); - GEPPETTO.CommandController.execute(actionStr); - $("#querybuilder").hide(); - }; - - return action; - }, - - getInitialState: function () { - return { carouselFullyLoaded: false, }; - }, - - componentDidMount: function () { - // apply carousel - if (this.isCarousel) { - var slickDivElement = $('#' + this.imageContainerId + '.slickdiv'); - slickDivElement.slick(); - var that = this; - - // reload slick carousel if it's first time clicking on arrow in any direction - slickDivElement.find(".slick-arrow").on("click", function () { - if (!that.fullyLoaded) { - that.setState({ carouselFullyLoaded: true }); - that.fullyLoaded = true; - } - }, { passive: true }); - } - }, - - componentDidUpdate: function () { - // on component refresh, update slick carousel - $('#' + this.imageContainerId + '.slickdiv').slick('unslick').slick(); - }, - - buildImage: function (thumbImage, imageContainerId) { - var action = this.getImageClickAction(thumbImage.reference); - const imgElement =
- - - -
- return imgElement; - }, - - buildCarousel: function () { - var jsonImageVariable = JSON.parse(this.props.data); - var imgElement = ""; - - if (jsonImageVariable.initialValues[0] != undefined) { - var imageContainerId = this.props.rowData.id + '-image-container'; - this.imageContainerId = imageContainerId; - - var value = jsonImageVariable.initialValues[0].value; - if (value.eClass == GEPPETTO.Resources.ARRAY_VALUE) { - if (value.elements.length > 1) { - this.isCarousel = true; - var imagesToLoad = 2; - if (this.state.carouselFullyLoaded) { - imagesToLoad = value.elements.length; - } - - // set flag to fully loaded if total length of images to render is less or equal to 2 - if (value.elements.length <= 2) { - this.fullyLoaded = true; - } - - var that = this; - // if it's an array, create a carousel (relies on slick) - var elements = value.elements.map(function (item, key) { - if (key < imagesToLoad) { - var image = item.initialValue; - var action = that.getImageClickAction(image.reference); - return
{image.name} - - - -
- } - }); - - elements = elements.slice(0, imagesToLoad); - - imgElement =
- {elements} -
- } else { - imgElement = this.buildImage(value.elements[0].initialValue, imageContainerId); - } - } else if (value.eClass == GEPPETTO.Resources.IMAGE) { - // otherwise we just show an image - imgElement = this.buildImage(value, imageContainerId); - } - } + class QueryBuilder extends React.Component { + constructor (props) { + super(props); - return imgElement; - }, - - - render: function () { - var imgElement = ""; - if (this.props.data != "" && this.props.data != undefined) { - imgElement = this.buildCarousel(); + this.state = { + resultsView: false, + errorMsg: '', + showSpinner: false, + resultsColumns: null, + resultsColumnMeta: null, + resultsControlsConfig: null, + infiniteScroll: undefined, + resultsPerPate: undefined, + refreshTrigger: false, + value: 0, + display: false, + allColumnsToShow: null, } - return ( -
- {imgElement} -
- ) + this.displayName = 'QueryBuilder'; + this.dataSourceResults = {}; + this.updateResults = false; + this.initTypeAheadCreated = false; + this.configuration = { DataSources: {} }; + this.mixins = [ + require('../../controls/mixins/bootstrap/modal.js') + ]; + this.escape = 27; + this.qKey = 81; + + this.open = this.open.bind(this); + this.close = this.close.bind(this); + this.runQuery = this.runQuery.bind(this); + this.switchView = this.switchView.bind(this); + this.initTypeahead = this.initTypeahead.bind(this); + this.setWrapperRef = this.setWrapperRef.bind(this); + this.keyOpenHandler = this.keyOpenHandler.bind(this); + this.setErrorMessage = this.setErrorMessage.bind(this); + this.keyCloseHandler = this.keyCloseHandler.bind(this); + this.queryItemDeleted = this.queryItemDeleted.bind(this); + this.clearErrorMessage = this.clearErrorMessage.bind(this); + this.defaultDataSources = this.defaultDataSources.bind(this); + this.queryResultDeleted = this.queryResultDeleted.bind(this); + this.handleClickOutside = this.handleClickOutside.bind(this); + this.downloadQueryResults = this.downloadQueryResults.bind(this); + this.resultSetSelectionChange = this.resultSetSelectionChange.bind(this); + this.queryOptionSelected = this.queryOptionSelected.bind(this); } - }); - - GEPPETTO.QueryResultsControlsComponent = CreateClass({ - - replaceTokensWithPath: function (inputStr, path) { - return inputStr.replace(/\$ID\$/gi, path); - }, - getActionString: function (control, path) { - var actionStr = ''; - - if (control.actions.length > 0) { - for (var i = 0; i < control.actions.length; i++) { - actionStr += ((i != 0) ? ";" : "") + this.replaceTokensWithPath(control.actions[i], path); - } + keyCloseHandler (event){ + if (event.keyCode === this.escape) { + this.close(); + GEPPETTO.trigger("query_closed"); } + } - return actionStr; - }, - - resolveCondition: function (control, path, negateCondition) { - if (negateCondition == undefined) { - negateCondition = false; - } - - var resolvedConfig = control; - - if (resolvedConfig.hasOwnProperty('condition')) { - // evaluate condition and reassign control depending on results - var conditionStr = this.replaceTokensWithPath(control.condition, path); - if (eval(conditionStr)) { - resolvedConfig = negateCondition ? resolvedConfig.false : resolvedConfig.true; + keyOpenHandler (event) { + if (event.keyCode === this.qKey && GEPPETTO.isKeyPressed("ctrl")) { + if (this.state.display) { + this.close(); } else { - resolvedConfig = negateCondition ? resolvedConfig.true : resolvedConfig.false; - } - } - - return resolvedConfig; - }, - - render: function () { - // TODO: would be nicer to pass controls and config straight from the parent component rather than assume - var config = GEPPETTO.QueryBuilder.state.resultsControlsConfig; - var resultItemId = this.props.rowData.id; - var ctrlButtons = []; - - // Add common control buttons to list - for (var control in config.Common) { - var add = true; - - // check show condition - if (config.Common[control].showCondition != undefined) { - var condition = this.replaceTokensWithPath(config.Common[control].showCondition, resultItemId); - add = eval(condition); - } - - if (add) { - ctrlButtons.push(config.Common[control]); + this.open(); } } - - var that = this; - - return ( -
- {ctrlButtons.map(function (control, id) { - // grab attributes to init button attributes - var controlConfig = that.resolveCondition(control, resultItemId); - var idVal = resultItemId.replace(/\./g, '_').replace(/\[/g, '_').replace(/\]/g, '_') + "_" + controlConfig.id + "_queryResults_btn"; - var tooltip = controlConfig.tooltip; - var classVal = "btn queryresults-button fa " + controlConfig.icon; - var styleVal = {}; - - // define action function - var actionFn = function (param) { - // NOTE: there is a closure on 'control' so it's always the right one - var controlConfig = that.resolveCondition(control, resultItemId); - - // take out action string - var actionStr = that.getActionString(controlConfig, resultItemId); - - if (param != undefined) { - actionStr = actionStr.replace(/\$param\$/gi, param); - } - - // run action - if (actionStr != '' && actionStr != undefined) { - GEPPETTO.CommandController.execute(actionStr); - // check custom action to run after configured command - if (that.props.metadata.action != '' && that.props.metadata.action != undefined) { - // straight up eval as we don't want this to show on the geppetto console - eval(that.props.metadata.action.replace(/\$ID\$/gi, resultItemId)); - } - } - - // if conditional, swap icon with the other condition outcome - if (control.hasOwnProperty('condition')) { - var otherConfig = that.resolveCondition(control, path); - var element = $('#' + idVal); - element.removeClass(); - element.addClass("btn queryresults-button fa " + otherConfig.icon); - } - }; - - return ( - - - - ) - })} -
- ) } - }); - - var QueryItem = CreateClass({ - displayName: 'QueryItem', - - getDefaultProps: function () { - return { - "item": null, - "options": [], - "onSelectOption": undefined, - "onDeleteItem": undefined, - }; - }, - getInitialState: function () { - return {}; // TODO: add if any - }, - - render: function () { - var createItem = function (item, key) { - return ; - }; - - var that = this; - var onSelection = function (e) { - var val = parseInt(e.target.value); - that.props.onSelectOption(that.props.item, val); - }; - - var containerId = "queryitem-" + this.props.item.id; - - return ( -
-
- ); + setWrapperRef (node) { + this.wrapperRef = node; } - }); - - var QueryFooter = CreateClass({ - displayName: 'QueryFooter', - - getDefaultProps: function () { - return { - "count": 0, - "onRun": undefined, - "containerClass": '' - }; - }, - render: function () { - return ( - - ); + handleClickOutside (event) { + if (this.wrapperRef && !this.wrapperRef.contains(event.target)) { + this.close(); + GEPPETTO.trigger("query_closed"); + } } - }); - - var QueryBuilder = CreateClass({ - displayName: 'QueryBuilder', - dataSourceResults: {}, - updateResults: false, - initTypeAheadCreated: false, - configuration: { DataSources: {} }, - mixins: [ - require('../../controls/mixins/bootstrap/modal.js') - ], - - defaultDataSources: function (q, sync) { + + defaultDataSources (q, sync) { if (q === '') { sync(this.dataSourceResults.index.all()); } else { this.dataSourceResults.search(q, sync); } - }, - - getInitialState: function () { - return { - resultsView: false, - errorMsg: '', - showSpinner: false, - resultsColumns: null, - resultsColumnMeta: null, - resultsControlsConfig: null, - infiniteScroll: undefined, - resultsPerPate: undefined, - refreshTrigger: false, - value: 0, - }; - }, - - getDefaultProps: function () { - return { model: queryBuilderModel }; - }, + } - componentWillMount: function () { + componentWillMount () { // this.clearErrorMessage(); GEPPETTO.QueryBuilder = this; - }, + this.props.resultsColMeta.map(item => { + if (item["customComponent"] !== undefined) { + item["queryBuilder"] = this; + } + }); + this.setResultsColumnMeta(this.props.resultsColMeta); + this.setResultsColumns(this.props.resultsColumns); + this.setResultsControlsConfig(this.props.resultsControlConfig); + this.addDataSource(this.props.datasourceConfig); + } + + componentWillUnmount () { + document.removeEventListener('mousedown', this.handleClickOutside); + document.removeEventListener("keydown", this.keyOpenHandler, false); + document.removeEventListener("keydown", this.keyCloseHandler, false); + } - switchView: function (resultsView, clearQueryItems) { + switchView (resultsView, clearQueryItems) { if (clearQueryItems == true) { this.clearAllQueryItems(); } this.setState({ resultsView: resultsView }); - }, + } - showBrentSpiner: function (spin) { + showBrentSpiner (spin) { this.setState({ showSpinner: spin }); - }, + } - open: function () { - // show query builder - $("#querybuilder").show(); - var typeAhead = $("#query-typeahead"); - typeAhead.focus(); - }, + open () { + /* + * show query builder + */ + this.setState({ display: true }, () => { + var typeAhead = $("#query-typeahead"); + typeAhead.focus(); + }); + } - close: function () { - // hide query builder - $("#querybuilder").hide(); - }, + close () { + /* + * hide query builder + */ + this.setState({ display: false }); + } - setResultsControlsConfig: function (controlsConfig) { + setResultsControlsConfig (controlsConfig) { this.setState({ resultsControlsConfig: controlsConfig }); - }, + } - setResultsColumns: function (columns) { - this.setState({ resultsColumns: columns }); - }, + setResultsColumns (columns) { + this.setState({ + resultsColumns: columns, + allColumnsToShow: columns + }); + } - setResultsColumnMeta: function (colMeta) { + setResultsColumnMeta (colMeta) { this.setState({ resultsColumnMeta: colMeta }); - }, - - initTypeahead: function () { - if (!this.initTypeAheadCreated) { - var that = this; + } - $("#query-typeahead").unbind('keydown'); - $("#query-typeahead").keydown(this, function (e) { - if (e.which == 9 || e.keyCode == 9) { - e.preventDefault(); - } - }); + initTypeahead () { - var queryTypeAheadElem = $("#query-typeahead"); + var that = this; - queryTypeAheadElem.unbind('keydown'); - queryTypeAheadElem.keydown(this, function (e) { - if (e.which == 9 || e.keyCode == 9) { - e.preventDefault(); - } - }); + $("#query-typeahead").unbind('keydown'); + $("#query-typeahead").keydown(this, function (e) { + if (e.which == 9 || e.keyCode == 9) { + e.preventDefault(); + } + }); - queryTypeAheadElem.unbind('keypress'); - queryTypeAheadElem.keypress(this, function (e) { - if (e.which == 13 || e.keyCode == 13) { - that.confirmed($("#query-typeahead").val()); - } - if (this.searchTimeOut !== null) { - clearTimeout(this.searchTimeOut); - } - this.searchTimeOut = setTimeout(function () { - for (var key in that.configuration.DataSources) { - if (that.configuration.DataSources.hasOwnProperty(key)) { - var dataSource = that.configuration.DataSources[key]; - var searchQuery = $("#query-typeahead").val(); - var url = dataSource.url.replace(/\$SEARCH_TERM\$/g, searchQuery); - that.updateResults = true; - that.requestDataSourceResults(key, url, dataSource.crossDomain); - } - } - }, 150); - }); + var queryTypeAheadElem = $("#query-typeahead"); - // fire key event on paste - queryTypeAheadElem.off("paste"); - queryTypeAheadElem.on("paste", function () { - $(this).trigger("keypress", { keyCode: 13 }); - }); + queryTypeAheadElem.unbind('keydown'); + queryTypeAheadElem.keydown(this, function (e) { + if (e.which == 9 || e.keyCode == 9) { + e.preventDefault(); + } + }); - queryTypeAheadElem.unbind('typeahead:selected'); - queryTypeAheadElem.bind('typeahead:selected', function (obj, datum, name) { - if (datum.hasOwnProperty("label")) { - that.confirmed(datum.label); + queryTypeAheadElem.unbind('keypress'); + queryTypeAheadElem.keypress(this, function (e) { + if (e.which == 13 || e.keyCode == 13) { + that.confirmed($("#query-typeahead").val()); + } + if (this.searchTimeOut !== null) { + clearTimeout(this.searchTimeOut); + } + this.searchTimeOut = setTimeout(function () { + for (var key in that.configuration.DataSources) { + if (that.configuration.DataSources.hasOwnProperty(key)) { + var dataSource = that.configuration.DataSources[key]; + var searchQuery = $("#query-typeahead").val(); + var url = dataSource.url.replace("$SEARCH_TERM$", searchQuery); + that.updateResults = true; + that.requestDataSourceResults(key, url, dataSource.crossDomain); + } } - }); + }, 150); + }); - queryTypeAheadElem.typeahead({ - hint: true, - highlight: true, - minLength: 1 - }, - { - name: 'dataSourceResults', - source: this.defaultDataSources, - limit: 50, - display: 'label', - templates: { suggestion: Handlebars.compile('
{{geticon icon}} {{label}}
') } + // fire key event on paste + queryTypeAheadElem.off("paste"); + queryTypeAheadElem.on("paste", function () { + $(this).trigger("keypress", { keyCode: 13 }); + }); + + queryTypeAheadElem.unbind('typeahead:selected'); + queryTypeAheadElem.bind('typeahead:selected', function (obj, datum, name) { + if (datum.hasOwnProperty("label")) { + that.confirmed(datum.label); } - ); - that.initTypeAheadCreated = true; - } - }, + }); - shouldComponentUpdate: function () { - if ($("#querybuilder").is(":visible")) { - return true; - } else { - return false; + queryTypeAheadElem.typeahead({ + hint: true, + highlight: true, + minLength: 1 + }, + { + name: 'dataSourceResults', + source: this.defaultDataSources, + limit: 50, + display: 'label', + templates: { suggestion: Handlebars.compile('
{{geticon icon}} {{label}}
') } } - }, + ); + that.initTypeAheadCreated = true; - componentDidMount: function () { - queryBuilderModel.subscribe(this.refresh); + } + componentDidMount () { var escape = 27; var qKey = 81; var that = this; + queryBuilderModel.subscribe(this.refresh, that); - $(document).keydown(function (e) { - if (GEPPETTO.isKeyPressed("ctrl") && e.keyCode == qKey) { - // show query builder - $("#querybuilder").show(); - } - }); - - $(document).keydown(function (e) { - if ($("#querybuilder").is(':visible') && e.keyCode == escape) { - that.close(); - } - }); - - $("#querybuilder").click(function (e) { - if (e.target == e.delegateTarget) { - // we want this only to happen if we clicked on the div directly and not on anything therein contained - that.close(); - GEPPETTO.trigger("query_closed"); - } - }); + document.addEventListener('mousedown', this.handleClickOutside); + document.addEventListener("keydown", this.keyCloseHandler, false); + document.addEventListener("keydown", this.keyOpenHandler, false); Handlebars.registerHelper('geticon', function (icon) { if (icon) { @@ -687,16 +401,24 @@ define(function (require) { if (GEPPETTO.ForegroundControls != undefined) { GEPPETTO.ForegroundControls.refresh(); } - }, + } - componentDidUpdate: function () { + componentDidUpdate () { if (!this.state.resultsView) { // re-init the search box on query builder this.initTypeahead(); } - }, - initDataSourceResults: function (datumToken, queryToken, sorter) { + if (!this.state.display) { + document.removeEventListener('mousedown', this.handleClickOutside); + document.removeEventListener("keydown", this.keyCloseHandler, false); + } else { + document.addEventListener('mousedown', this.handleClickOutside); + document.addEventListener("keydown", this.keyCloseHandler, false); + } + } + + initDataSourceResults (datumToken, queryToken, sorter) { this.dataSourceResults = new Bloodhound({ datumTokenizer: (datumToken != undefined) ? datumToken : Bloodhound.tokenizers.obj.whitespace('label'), queryTokenizer: (queryToken != undefined) ? queryToken : Bloodhound.tokenizers.whitespace, @@ -705,13 +427,12 @@ define(function (require) { }, sorter: sorter }); - }, + } /** * Requests external data sources. - * */ - addDataSource: function (sources) { + addDataSource (sources) { try { for (var key in sources) { if (sources.hasOwnProperty(key)) { @@ -731,12 +452,12 @@ define(function (require) { } catch (err) { throw ("Error parsing data sources " + err); } - }, + } /** * Figure out if data source of same name is already in there. If it is create a new key for it. */ - generateDataSourceKey: function (key, index) { + generateDataSourceKey (key, index) { var dataSource = this.configuration.DataSources[key] if (dataSource != null || dataSource != undefined) { key = key.concat(index); @@ -744,7 +465,7 @@ define(function (require) { } return key; - }, + } /** * Requests results for an external data source @@ -753,7 +474,7 @@ define(function (require) { * @param data_source_url : URL used to request data source results * @param crossDomain : URL allows cross domain */ - requestDataSourceResults: function (data_source_name, data_source_url, crossDomain) { + requestDataSourceResults (data_source_name, data_source_url, crossDomain) { var that = this; // not cross domain, get results via java servlet code if (!crossDomain) { @@ -775,7 +496,7 @@ define(function (require) { } }); } - }, + } /** * Update the datasource results with results that come back @@ -783,7 +504,7 @@ define(function (require) { * @param data_source_name * @param results */ - updateDataSourceResults: function (data_source_name, results) { + updateDataSourceResults (data_source_name, results) { var that = this; var responses = results.response.docs; responses.forEach(function (response) { @@ -797,12 +518,12 @@ define(function (require) { queryTypeAheadElem.typeahead('val', "init"); // this is required to make sure the query changes otherwise typeahead won't update queryTypeAheadElem.typeahead('val', value); } - }, + } /** * Format incoming data source results into specified format in configuration script */ - formatDataSourceResult: function (data_source_name, response) { + formatDataSourceResult (data_source_name, response) { // create searchable result for main label var labelTerm = this.configuration.DataSources[data_source_name].label.field; var idTerm = this.configuration.DataSources[data_source_name].id; @@ -843,12 +564,12 @@ define(function (require) { } } } - }, + } /** * Creates a searchable result from external data source response */ - createDataSourceResult: function (data_source_name, response, formattedLabel, id) { + createDataSourceResult (data_source_name, response, formattedLabel, id) { var typeName = response.type; var obj = {}; @@ -864,9 +585,9 @@ define(function (require) { obj["actions"] = newActions; obj["icon"] = this.configuration.DataSources[data_source_name].type[typeName].icon; this.dataSourceResults.add(obj); - }, + } - confirmed: function (item) { + confirmed (item) { if (item && item != "") { if (this.dataSourceResults.get(item)) { var found = this.dataSourceResults.get(item); @@ -879,9 +600,9 @@ define(function (require) { } } } - }, + } - queryOptionSelected: function (item, value, cb) { + queryOptionSelected (item, value, cb) { this.clearErrorMessage(); var that = this; @@ -899,9 +620,9 @@ define(function (require) { // Option has been selected this.props.model.itemSelectionChanged(item, value, callback.bind(this)); - }, + } - queryItemDeleted: function (item) { + queryItemDeleted (item) { this.clearErrorMessage(); var callback = function () { @@ -912,21 +633,21 @@ define(function (require) { this.showBrentSpiner(true); this.props.model.deleteItem(item, callback.bind(this)); - }, + } /** * Clears all query items from the query builder */ - clearAllQueryItems: function () { + clearAllQueryItems () { this.clearErrorMessage(); this.props.model.clearItems(); - }, + } - queryResultDeleted: function (resultsItem) { + queryResultDeleted (resultsItem) { this.props.model.deleteResults(resultsItem); - }, + } - getCompoundQueryId: function (queryItems) { + getCompoundQueryId (queryItems) { var id = ""; for (var i = 0; i < queryItems.length; i++) { @@ -934,9 +655,9 @@ define(function (require) { } return id; - }, + } - runQuery: function () { + runQuery () { this.clearErrorMessage(); if (this.props.model.items.length > 0) { @@ -988,27 +709,40 @@ define(function (require) { var verboseLabelPlain = ""; for (var i = 0; i < that.props.model.items.length; i++) { queryLabel += ((i != 0) ? "/" : "") - + that.props.model.items[i].term; + + that.props.model.items[i].term; verboseLabel += ((i != 0) ? " AND " : "") - + that.props.model.items[i].options[that.props.model.items[i].selection + 1].name; + + that.props.model.items[i].options[that.props.model.items[i].selection + 1].name; verboseLabelPlain += ((i != 0) ? " AND " : "") - + that.props.model.items[i].options[that.props.model.items[i].selection + 1].name; + + that.props.model.items[i].options[that.props.model.items[i].selection + 1].name; } // NOTE: assumption we only have one datasource configured var datasourceConfig = that.configuration.DataSources[Object.keys(that.configuration.DataSources)[0]]; var headersDatasourceFormat = datasourceConfig.resultsFilters.getHeaders(JSON.parse(jsonResults)); + var columnsPresent = headersDatasourceFormat.map(header => { + for (var counter = 0; counter < that.state.resultsColumnMeta.length; counter++) { + if (that.state.resultsColumnMeta[counter].displayName == header) { + return that.state.resultsColumnMeta[counter].columnName; + } + } + }); var recordsDatasourceFormat = datasourceConfig.resultsFilters.getRecords(JSON.parse(jsonResults)); var formattedRecords = recordsDatasourceFormat.map(function (record) { - return { - id: datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, "ID"), - name: datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, "Name"), - description: datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, "Definition"), - type: datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, "Type"), - images: datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, "Images"), - controls: '', - score: datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, "Score") + var instance = new Object(); + for (var counter = 0; counter < columnsPresent.length; counter++) { + instance[columnsPresent[counter]] = datasourceConfig.resultsFilters.getItem(record, headersDatasourceFormat, headersDatasourceFormat[counter]); + } + instance["controls"] = ''; + return instance; + }); + + var columnsToShow = that.state.allColumnsToShow.filter(item => { + for (var counter = 0; counter < columnsPresent.length; counter++) { + if (item == columnsPresent[counter]) { + return true; + } } + return false; }); that.props.model.addResults({ @@ -1018,7 +752,10 @@ define(function (require) { verboseLabel: '' + formattedRecords.length.toString() + ' ' + verboseLabel, verboseLabelPLain: formattedRecords.length.toString() + ' ' + verboseLabelPlain, records: formattedRecords, - selected: true + selected: true, + columnsToShow: columnsToShow, + columnsPresent: columnsPresent, + headersColumns: headersDatasourceFormat }); // stop showing spinner @@ -1057,7 +794,7 @@ define(function (require) { // show error message for empty query this.setErrorMessage('Please add query items to run a query.'); } - }, + } /** * Add a query item @@ -1065,7 +802,7 @@ define(function (require) { * @param queryItem - Object with term and variable id properties * @param cb - optional callback function */ - addQueryItem: function (queryItemParam, cb) { + addQueryItem (queryItemParam, cb) { this.clearErrorMessage(); // grab datasource configuration (assumption we only have one datasource) @@ -1160,26 +897,26 @@ define(function (require) { */ this.dataSourceResults.clear(); // } - }, + } - setErrorMessage: function (message) { + setErrorMessage (message) { this.setState({ errorMsg: message }); - }, + } - clearErrorMessage: function () { + clearErrorMessage () { this.setErrorMessage(''); - }, + } - resultSetSelectionChange: function (val) { + resultSetSelectionChange (val) { this.props.model.resultSelectionChanged(val); this.props.model.results.map((resultItem, index) => { if (val === resultItem.label) { this.setState({ value: index }); } }); - }, + } - downloadQueryResults: function (resultsItem) { + downloadQueryResults (resultsItem) { var convertArrayOfObjectsToCSV = function (args) { var result, ctr, keys, columnDelimiter, lineDelimiter, data; @@ -1216,7 +953,18 @@ define(function (require) { var downloadCSV = function (args) { var data, filename, link, extension; - var csv = convertArrayOfObjectsToCSV({ data: args.data }); + var records = args.data.map(function (record) { + var instance = new Object(); + for (var counter = 0; counter < args.columnsPresent.length; counter++) { + if (args.columnsPresent[counter] == "controls" || args.columnsPresent[counter] == "images") { + continue; + } + instance[args.columnsPresent[counter]] = record[args.columnsPresent[counter]]; + } + return instance; + }); + + var csv = convertArrayOfObjectsToCSV({ data: records }); if (csv == null) { return; } @@ -1240,25 +988,25 @@ define(function (require) { }; downloadCSV({ - filename: 'query-results', - data: resultsItem.records.map(function (record) { - return { - id: record.id, - name: record.name, - description: record.description.replace(/,/g, ' ') - } - } - ) + filename: resultsItem.verboseLabelPLain.replace(/ /g, '_'), + data: resultsItem.records, + columnsPresent: resultsItem.columnsPresent, + headersColumns: resultsItem.headersColumns, + datasourceConfig: this.configuration.DataSources[Object.keys(this.configuration.DataSources)[0]], }); - }, + } - refresh: function () { + refresh () { this.setState({ refreshTrigger: !this.state.refreshTrigger }); - }, + } - render: function () { + render () { const { value } = this.state; var markup = null; + + if (this.state.display === false) { + return markup; + } // once off figure out if we are to use infinite scrolling for results and store in state if (this.state.infiniteScroll === undefined) { this.state.infiniteScroll = !(this.props.enablePagination != undefined && this.props.enablePagination === true); @@ -1288,14 +1036,21 @@ define(function (require) { return { __html: resultsItem.verboseLabel }; }; - return (value === index - && -
-
- -
+ return (focusTabIndex === index + && +
+
+ +
); }, this); @@ -1332,7 +1087,7 @@ define(function (require) { this.initTypeAheadCreated = false; markup = ( -
+
{tabs}
+ ); + } + } + + QueryFooter.defaultProps = { + "count": 0, + "onRun": undefined, + "containerClass": '' + }; + + return QueryFooter; + }); \ No newline at end of file diff --git a/js/components/interface/query/queryItem.js b/js/components/interface/query/queryItem.js new file mode 100644 index 000000000..de7d3e9bb --- /dev/null +++ b/js/components/interface/query/queryItem.js @@ -0,0 +1,48 @@ +define(function (require) { + + require("./query.less"); + require("./react-simpletabs.less"); + + var React = require('react'); + + class QueryItem extends React.Component { + constructor (props) { + super(props); + + this.displayName = 'QueryItem'; + } + + render () { + var createItem = function (item, key) { + return ; + }; + + var that = this; + var onSelection = function (e) { + var val = parseInt(e.target.value); + that.props.onSelectOption(that.props.item, val); + }; + + var containerId = "queryitem-" + this.props.item.id; + + return ( +
+
+ ); + } + } + + QueryItem.defaultProps = { + "item": null, + "options": [], + "onSelectOption": undefined, + "onDeleteItem": undefined, + }; + + return QueryItem; +}); \ No newline at end of file diff --git a/js/components/interface/spotlight/spotlight.js b/js/components/interface/spotlight/spotlight.js index aac5f57ef..cefc14abf 100644 --- a/js/components/interface/spotlight/spotlight.js +++ b/js/components/interface/spotlight/spotlight.js @@ -158,7 +158,9 @@ define(function (require) { } }); - this.initDataSourceResults(); + if (this.props.spotlightDataSourceConfig === undefined) { + this.initDataSourceResults(); + } Handlebars.registerHelper('geticonFromMetaType', function (metaType) { if (metaType) {