doc.addEventListener is not a function - javascript

On my page I'm rendering a tree based on jsTree angular directive. I'm trying to achieve a showing tooltip on hover for particularly node which has a description field. I have checked list of API for jsTree and have found on hover event listener hover_node, with help angular directive for jsTree I have setup my scope function to this listener
<js-tree
tree-data="scope"
tree-model="tree"
tree-events="hover_node:nodeHovered"
tree-core="tree_core"
></js-tree>
$scope.nodeHovered = function (e, data) {
var dataNode = data.node;
var original = dataNode.original;
if (typeof original.description !== 'undefined'){
var nodeDescription = original.description;
$(original).tooltip({
title: nodeDescription,
animation: true
});
}
};
My function works well when I hover on any node, I can see the object data in console, so I wrote a piece of code which allows to see the description in console if typeof node description is not an equal undefined. It works well for console but when I added function bootstrap tooltip for this node that to show the description as tooltip, I've got next error
Uncaught TypeError: doc.addEventListener is not a function
As I could understand from some topics here, the nature of this mistake is arrays don't have addEventListener function, but I'm working with an object which is already defined thru the library, so could anybody help to find what I'm missing? I appreciate any help.
Plunker
my full code
var treeFolders = [];
$scope.tree = [];
$http.get("folders.json")
.then(function (res) {
treeFolders = res.data;
angular.forEach(treeFolders, function(obj){
if(!("parent" in obj)){
obj.parent = "#";
}
})
})
$scope.load = function(){
$scope.tree = treeFolders
};
$scope.tree_core = {
multiple: false, // disable multiple node selection
check_callback: function (operation, node, node_parent, node_position, more) {
return true; // allow all other operations
},
themes : {
theme : "default",
dots : true,
icons : true
}
};
$scope.nodeHovered = function (e, data) {
var dataNode = data.node;
var original = dataNode.original;
if (typeof original.description !== 'undefined'){
var nodeDescription = original.description;
$(original).tooltip({
title: nodeDescription,
animation: true
});
}
};
html
<button class="btn btn-default" ng-click="load()">Load Tree</button>
<js-tree
tree-data="scope"
tree-model="tree"
tree-events="hover_node:nodeHovered"
tree-core="tree_core"
></js-tree>

This is because the original object that you are passing to jQuery in the following code is a jsTree node, not a DOM element:
$(original).tooltip({
title: nodeDescription,
animation: true
});
Instead use the get_node method of jsTree to retrieve the jQuery wrapped DOM element from the node:
var liElement = data.instance.get_node(data.node, true);
This will give you the entire li element, but you probably want the tooltip placed relative to the a element:
var aElement = liElement.children('a').first();
Then:
aElement.tooltip({
title: nodeDescription,
animation: true
}).tooltip('show');
Note that I have added an extra call to tooltip at the end. This is for the tooltip to be shown the first time the element is hovered. Without this the tooltip would be created on the first hover, then not shown until the next.
Demo: https://plnkr.co/edit/itMSrsroTVswD3RLbs7O?p=preview

Related

Having trouble getting a click event to run in aframe

I am trying to write an inventory system for a game using the AFrame library. I have a custom component that is set up to set the item i'm picking up to invisible and turn the in hand item visible. However when ever it runs it won't work.
Currently, i have a click eventlistener set up check when clicked. When clicked it is set to set the target item invisible (el) and the object in hand visible (handObj). It appears as tho the click function isn't evening running as I have a console.log set up to just check if the function ran or not.
Edit: I created a glitch with an example project
https://glitch.com/~tundra-ironclad
var hands = [null, null];
AFRAME.registerComponent('pickUp', {
schema: {
handObj: {type: 'selector', default: ''},
id: {type: 'string', default: ''}
},
init: function() {
var el = this.el;
var data = this.data;
el.addEventListener('click', function() {
//pickup="target= #right
console.log("hello");
if(hands[0] == null) hands[0] = data.id;
else if (hands[1] == null) hands[1] = data.id;
else break;
el.setAttribute('visible', 'false');
data.handObj.setAttribute('visible', 'true');
});
}
});
<a-box id="left1"
color="#AA0000" class="clickable"
position="8.000 0.200 7" depth = ".25" height = ".25" width = ".25"
event-set__enter="_event: mouseenter; material.color: #FF0000"
event-set__leave="_event: mouseleave; material.color: #AA0000"
pickUp="handObj: #left2; id: left"
>
I don't understand why the click function isn't working at all since i have copied the formatting from tutorials and those components work fine.
Your example freezes for me, but try pick-up instead of pickUp. HTML attributes are case-insensitive. We should add a warning for that.

CKEditor - Button to switch shown Toolbar

I'm trying to give a user the ability to swap around the toolbar between presets based on a button press. Ideally that button would be in the CKEditor screen, but I can play around with it.
I've found this SO Article in which I get the concept that you destroy your instance, and re-initialize it with a 'New Config'.
To follow suit I took one of the higher ranked responses, modified it to match my table, and threw it onto a button.
function toolbarSwap(){
var editor = CKEDITOR.instances.editor;
if (editor) { editor.destroy(true); }
CKEDITOR.config.toolbar_Basic = [['Bold','Italic','Underline',
'-','JustifyLeft','JustifyCenter','JustifyRight','-','Undo','Redo']];
CKEDITOR.config.toolbar = 'Basic';
CKEDITOR.config.width=400;
CKEDITOR.config.height=300;
CKEDITOR.replace('editor', CKEDITOR.config);
}
The replace command concerns me since I can't see it working, as to if the data within the editor will go away but either way nothing is happening when I click the button that runs this function.
Is this the best method, or is there a way I can do this within CKEditor directly?
Update
function toolbarSwap(){
var editor = CKEDITOR.instances['editor'];
if (editor) { editor.destroy(true); }
CKEDITOR.config.toolbar_Basic = [['Bold','Italic','Underline',
'-','JustifyLeft','JustifyCenter','JustifyRight','-','Undo','Redo']];
CKEDITOR.config.toolbar = 'Basic';
CKEDITOR.config.width=400;
CKEDITOR.config.height=300;
CKEDITOR.replace('editor', CKEDITOR.config);
}
It seems like modified the instantiation of editor with the ID resolves the issue of it finding it, but the Editor is being emptied every time I click it. Is there a way to reload the config, instead of destroying the instance?
Update 2
function changeToolBar() {
var expanded = true;
if (expanded === true) {
var myToolBar = [{ name: 'verticalCustomToolbar', groups: [ 'basicstyles'], items: [ 'Bold', 'Italic'] }];
var config = {};
config.toolbar = myToolBar;
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', config);
expanded = false;
} else {
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', {toolbar: 'Full'});
expanded = true;
console.log("Expand me")
};
}
Here is where I'm at so far. I am not losing the data during the re-init, but I am unable to ever get the 'else' statement to trigger.
My Function was correct, but the var being initialized -in- the function was resetting it's purpose everything. AKA It's -always- true on click
<button type="button" onclick="changeToolBar()">Swap It</button>
function changeToolBar() {
if (expanded === true) {
var myToolBar = [{ name: 'verticalCustomToolbar', groups: [ 'basicstyles'], items: [ 'Bold', 'Italic'] }]; //Generic placeholder
var config = {};
config.toolbar = myToolBar;
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', config);
console.log(expanded); // Logging to ensure change
expanded = false;
console.log(expanded); // Logging to ensure the change
} else {
CKEDITOR.instances.editor.destroy();//destroy the existing editor
CKEDITOR.replace('editor', {toolbar: 'Full'}); // Toolbar 'full' is a default one
expanded = true;
console.log("Expand me") // Logging if it works
};
}
Can also swap in Full with a predefined config for toolbars.

selection not working on WinJS ListView in click mode

Below is my WinJS.UI.ListView definition. However, onselectionchanged is never called when right clicking or doing Ctrl+Click. I have setup my ListView identically to the samples(which work). Am I missing something? Or could something be interfering, just with the click selection?
this.m_listView = new WinJS.UI.ListView(this.domNode,
{
layout : {type: WinJS.UI.GridLayout},
itemTemplate : this.itemTemplate.bind(this),
selectionMode: 'multi',
tapBehavior: 'invokeOnly',
swipeBehavior: 'select'
});
this.m_listView.oniteminvoked = this.itemInvoked.bind(this);
this.m_listView.onselectionchanged = this.selectionChanged.bind(this);
EDIT: I Assign my datasource in a separate function with these lines
var itemList = new WinJS.Binding.List(this.m_nodes);
this.m_listView.itemDataSource = itemList.dataSource;
This ListView is wrapped in a javascript class. So my template function is a prototype of my EntriesList class. This is that function(I pulled out the real content for simplicity, I still have this issue with the content though):
EntriesList.prototype.itemTemplate = function(itemPromise)
{
return itemPromise.then
(
function (item)
{
var entry = document.createElement("div");
entry.className = "tile";
entry.style.height = "120px";
entry.style.width = "340px";
return entry;
}
);
The issue was something in our internal API was blocking pointer events. We were able to resolve the problem. The code/configuration in the question works.

Filtering Sigma.Js graph from external events

I have an instance of Sigma.Js 1.0.0 rendering a graph in my Canvas element. (The code is below, but you can simply scroll to Step 2 of Tutorial on the main sigmajs.org page.
As you can see from that code, when the node is clicked, clickNode event occurs, which then applies filtering to the graph, showing only the clicked node and its neighborhood and dimming the others. That's quite clear.
However, how would I make exactly the same thing happen from the outside? Suppose I have the graph rendered already and I have a Tag Cloud next to it. And I want that when I click on a #hashtag, only that node is shown in the graph and the rest are dimmed. How would I do that?
Thanks!
<div id="sigma-container"></div>
<script src="path/to/sigma.js"></script>
<script src="path/to/sigma.parsers.min.gexf.js"></script>
<script>
// Add a method to the graph model that returns an
// object with every neighbors of a node inside:
sigma.classes.graph.addMethod('neighbors', function(nodeId) {
var k,
neighbors = {},
index = this.allNeighborsIndex[nodeId] || {};
for (k in index)
neighbors[k] = this.nodesIndex[k];
return neighbors;
});
sigma.parsers.gexf(
'path/to/les-miserables.gexf',
{
container: 'sigma-container'
},
function(s) {
// We first need to save the original colors of our
// nodes and edges, like this:
s.graph.nodes().forEach(function(n) {
n.originalColor = n.color;
});
s.graph.edges().forEach(function(e) {
e.originalColor = e.color;
});
// When a node is clicked, we check for each node
// if it is a neighbor of the clicked one. If not,
// we set its color as grey, and else, it takes its
// original color.
// We do the same for the edges, and we only keep
// edges that have both extremities colored.
s.bind('clickNode', function(e) {
var nodeId = e.data.node.id,
toKeep = s.graph.neighbors(nodeId);
toKeep[nodeId] = e.data.node;
s.graph.nodes().forEach(function(n) {
if (toKeep[n.id])
n.color = n.originalColor;
else
n.color = '#eee';
});
s.graph.edges().forEach(function(e) {
if (toKeep[e.source] && toKeep[e.target])
e.color = e.originalColor;
else
e.color = '#eee';
});
// Since the data has been modified, we need to
// call the refresh method to make the colors
// update effective.
s.refresh();
});
// When the stage is clicked, we just color each
// node and edge with its original color.
s.bind('clickStage', function(e) {
s.graph.nodes().forEach(function(n) {
n.color = n.originalColor;
});
s.graph.edges().forEach(function(e) {
e.color = e.originalColor;
});
// Same as in the previous event:
s.refresh();
});
}
);
</script>
<!-- [...] -->
I hope this goes some way to answering your question.
You have a tagcloud full of words, and when a word is clicked, you want to trigger the neighbors method on your sigma instance, for which you need the node id.
Simply put, you need the function which is called when the #hashtag is clicked, to be in the same scope as the sigma instantiation.
s= new sigma({
settings: {...}
})
//more code instantiating methods etc
//let's assume your tags are in elements with class='tagword' and have the hashtag stored in a 'name' attribute
$('.tagword').on('click', function(){
var name = this.attr('name');
s.graph.nodes().forEach(function(n){
if (n.label == name){
//use the node to trigger an event in sigma
//i.e. s.graph.neighbors(n.id);
};
};
};

Kendo UI Web - MultiSelect: select an option more than once

I'm currently facing a problem with the Kendo UI MultiSelect widget for selecting an option more than once. For example, in the image below I want to select Schindler's List again after selecting The Dark Knight, but unfortunately the MultiSelect widget behaves more like a set than an ordered list, i.e. repetitive selection is not allowed. Is there actually a proper way to achieve this? Any workarounds?
That's the intended behavior of the multi-select control and there is no simple way to make it do what you want using the available configuration options. Possible workarounds are ...
Creating a custom multi-select widget
Something like this should work (note that I haven't tested this much - it lets you add multiples and keeps the filter intact though):
(function ($) {
var ui = kendo.ui,
MultiSelect = ui.MultiSelect;
var originalRender = MultiSelect.fn._render;
var originalSelected = MultiSelect.fn._selected;
var CustomMultiSelect = MultiSelect.extend({
init: function (element, options) {
var that = this;
MultiSelect.fn.init.call(that, element, options);
},
options: {
name: 'CustomMultiSelect'
},
_select: function (li) {
var that = this,
values = that._values,
dataItem,
idx;
if (!that._allowSelection()) {
return;
}
if (!isNaN(li)) {
idx = li;
} else {
idx = li.data("idx");
}
that.element[0].children[idx].selected = true;
dataItem = that.dataSource.view()[idx];
that.tagList.append(that.tagTemplate(dataItem));
that._dataItems.push(dataItem);
values.push(that._dataValue(dataItem));
that.currentTag(null);
that._placeholder();
if (that._state === "filter") {
that._state = "accept";
}
console.log(this.dataSource.view());
},
_render: function (data) {
// swapping out this._selected keeps filtering functional
this._selected = dummy;
return originalRender.call(this, data);
this._selected = originalSelected;
}
});
function dummy() { return null; }
ui.plugin(CustomMultiSelect);
})(jQuery);
Demo here.
Using a dropdown list
Use a simple dropdown list (or ComboBox) and bind the select event to append to your list (which you have to create manually).
For example:
var mySelectedList = [];
$("#dropdownlist").kendoDropDownList({
select: function (e) {
var item = e.item;
var text = item.text();
// store your selected item in the list
mySelectedList.push({
text: text
});
// update the displayed list
$("#myOrderedList").append("<li>" + text + "</li>");
}
});
Then you could bind clicks on those list elements to remove elements from the list. The disadvantage of that is that it requires more work to make it look "pretty" (you have to create and combine your own HTML, css, images etc.).

Categories

Resources