Vis js timeline range element custom draw - vis.js

I have found vis.js extremely useful but now need to add custom 'symbols' (up indicator, down indicator, etc) to the edges (start / end) of a range element used in a timeline.
I can add separate elements to precede / succeed other elements but this involves quite a bit more effort and stacking is affected etc.
Or... I can place html text / symbols inside a table with css forcing it to the start / end of the element but this does not seem to display correctly always.
What would be the suggested approach to resolve this?

You should provide a template function in the options that will render your range item.
The content returned by your template function may be any valid HTML, so it's up to you to use a div, table, ... whatever to add and position your extra symbols.
Docs:
https://visjs.org/docs/timeline/#Templates
Timeline supports templates to format item contents. Any template engine (such as handlebars or mustache) can be used, and one can also manually build HTML. In the options, one can provide a template handler. This handler is a function accepting an item's data as the first argument, the item element as the second argument and the edited data as the third argument, and outputs formatted HTML.
Example:
var options = {
template: function (item, element, data) {
return '<h1>' + item.header + data.moving?' '+ data.start:'' + '</h1><p>' + item.description + '</p>';
},
onMoving: function (item, callback) {
item.moving = true;
}
};

Related

k6: How to create a Selection from an Element

Using Selection.each(fn) (see the k6 docs), the callback is passed an index and an Element. Element has a different API than Selection, and within the callback I’d like to use the Selection API on the passed Element so that I can operate on each Selection individually.
In jQuery, I’d often do this:
$('li').each(function (index, element) {
let container = $(element).closest('div.listContainer');
// now do something with the `container`
});
I’ve tried inside the callback to do things like $(element) or Selection(element) but it errors saying those are undefined. (Kind of stabbing in the dark, since I don’t see in the docs how to do this.)
My code looks like:
mySelection.each((index, element) => {
// here, I'd like to do element.closest('.someAncestorSelector') if element could be 'wrapped'
})
Is there a way in the jQuery-like Selection API in k6 to do this?
From the k6 docs on Selection.closest:
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree. [emphasis mine]
Which means that each is unnecessary and will be performed automatically (returning a new Selection instance with the closest elements).
const closestSelection = mySelection.closest('.someAncestorSelector');
closestSelection.each((index, closestElement) => {
// now, do something with closestElement.
});
or as a single chain of expressions:
mySelection.closest('.someAncestorSelector')
.each((index, closestElement) => {
// now, do something with closestElement.
});
Btw, even jQuery implicitly handles collections, so your jQuery code could be changed to:
const containers = $('li').closest('div.listContainer');
containers.each(function (index, container) {
container = $(container);
// now do something with the `container`
});

Include specific attribute or child-element text in breadcrumb rendering

Within the author it displays a breadcrumb, and I know you can modify its display to either some other static text or localisation, but I'm wondering if it's possible to dynamically show an attribute, or execute some other context-specific xpath dynamically.
As a test I can change the breadcrumb using the localisation editor variable ${i18n()}.
cc_config.xml
<elementRenderings platform="webapp">
<render element="num" as="${i18n(test)}" annotation="${i18n(test)}"/>
translation-cc.xml
<key value="test">
<comment></comment>
<val lang="en_US">Year</val>
"Year" is actually a num element.
However, trying any other variable, even 'more static' ones like ${cf} or ${tp} simply render the variable text literally, instead of evaluating it.
cc_config.xml
<elementRenderings platform="webapp">
<render element="paragraph" as="${xpath_eval(./#eId)}" annotation="${xpath_eval(./#eId)}"/>
<render element="p" as="${tp}" annotation="${tp}"/>
(paragraphs do have an eId attribute)
As you can see, I tried using annotation; but these tooltips also simply display the variable literally.
I also fiddled and tried a bunch of xpath stuff, like #eId/.#eId//#eId, but I think there's some restriction in using the Content Completion Configuration File with respect to editor variables.
So is the thinking right but I am doing something wrong, or is it not the right way but there is some other way to affect the breadcrumb? Maybe with the schema?
The element display names in cc_config.xml file do not support most of the editor variables. Most of them, like ${cf} (current file) and ${tp} (total number of pages) don't make sense to be used when rendering the name of an element.
The xpath_eval would make sense - the display name of an element may depend on its attributes (e.g. the #id attribute), it's index in the document (e.g. 'Section 3'), etc. We have a feature request registered for this case and I added your vote to it.
As a partial workaround you can use a JS API to compute the display name of the element based on the element original name and its attributes:
goog.events.listen(workspace, sync.api.Workspace.EventType.BEFORE_EDITOR_LOADED, function(e) {
e.options.elementNameEnhancer = function(elemName, attrs) {
var displayString = elemName;
var attr = attrs['id'];
if (attr) {
displayString += ' (#' + attr.attributeValue + ')';
}
return displayString;
};
});

How make a dynamic value in MeteorJS

I need to set a variable or array in meteor JS which whenever changes. Wherever it is used on the page changes.
So far I have tried to set values in session.
let in = Session.get("in");
and this in HTML. The following works fine. This changes whenever it detects a change in array
{{#each in}}
<span class="selectable-tags"> {{this}} </span>
{{/each}}
But whenever I try to add these tags to other div using following. Then the ones added to other div does not change.
"click .selectable-tags"(e, t) {
// sets the tags inside the Method box on click
var el = e.target.cloneNode(true);
el.setAttribute('contenteditable', false);
document.querySelector('[contenteditable]').appendChild(el); },
using meteor with blaze UI. This can be used as reference link
Edit: Session.get or set is given for reference . This was to tell that these values are changing as they on any event triggered wherever set.
You need to add a helper that returns the session variable and show the helper in your html code :
Template.yourtemplate.helpers({
inHelper: ()=> {
return Session.get('in');
}
)}
And in html :
<div>{{inHelper}}</div>
Every modification on in by Session.set('in', newValue) will change your HTML.

How can I add a unique class and assign unique data to copies of the same template using Meteor, Blaze, Spacebars?

I'm trying to create a dynamic slider that can be reused with different images.
<div id="sly_container" class="sly">
<ul>
{{#each propertyImages}}
<li><img src="{{ImageURL}}"></li>
{{/each}}
</ul>
<button id="gallery_btn-prev"><img class="gallery_arrow"/>prev</button>
<span id="middleSpan"></span>
<button id="gallery_btn-next"><img class="gallery_arrow"/>next</button>
</div>
I populate propertyImages with an httpRequest (I make several of these):
(function(o){
HTTP.call( 'GET', 'https://api.rentcafe.com/rentcafeapi.aspx?requestType=images&type=propertyImages&companyCode=c00000084939&propertyCode='+v+'', {},
function( error, response ) {
if ( error ) {
console.log( error );
} else {
var content = JSON.parse(response["content"]);
obj[p] = content;
if( o == l){
CommunityImages.insert(obj)
Session.set('imagesLoaded',true);
}
}
console.log(v+ ' ' + p + ' ' + o + ' images delivered')
})
}(o++))
and then use this helper:
Template.sly.helpers({
propertyImages: function(){
if(Session.get('property') && CommunityImages.find().fetch()[0]){
return CommunityImages.find().fetch()[0][Session.get('property')]
}
})
After it renders I run some more logic on it to create the slider from the images. It works well when there is one slider per view, since it is dependent on the Session.set('property', 'whatever') but I want to have many on the same page each populated with different images. I can add keys and values to the image objects, so I suppose maybe I can do this with a Spacebars conditional? In the end I'd like to have something like this
<div id="summit-sly">{{> sly}}</div>
<div id="hillcroft-sly">{{> sly}}</div>
<div id="merrit_station-sly">{{> sly}}</div>
with each slider containing it's respective images, OR I'm now seeing that maybe partials could work somehow:
{{>sly summit}}
{{>sly hillcroft}}
{{>sly merrit_station}}
Each slider will basically need it's own class name, so that the logic that runs on render will target each one specifically and not all of them.
Indeed, you can use partials in Blaze spacebars with either:
A single argument that acts as the data context of the called template (as exemplified in Meteor Guide > View > User Interfaces > UI components > Smart components).
Named arguments (as shown in Meteor Guide > View > Blaze > Spacebars > Template inclusion), which are actually assembled into a data object (see below).
{{> subComponent arg1="value-of-arg1" arg2=helperThatReturnsValueOfArg2}}
Another tutorial: http://meteorcapture.com/spacebars/#template-inclusion-ex-2
Reference: Meteor API Docs > Packages > spacebars > Inclusion and Block Arguments
Inclusion tags ({{> foo}}) and block tags ({{#foo}}) take a single data argument, or no argument. Any other form of arguments will be interpreted as an object specification or a nested helper:
Object specification: If there are only keyword arguments, as in {{#with x=1 y=2}} or {{> prettyBox color=red}}, the keyword arguments will be assembled into a data object with properties named after the keywords.
Nested Helper: If there is a positional argument followed by other (positional or keyword arguments), the first argument is called on the others using the normal helper argument calling convention.
Then you retrieve the data context through the templateInstance.data property:
In an onCreated, onRendered or onDestroyed callback, the template instance is directly available in this.
In a helper or in the HTML part of the template, the data context is directly available in this (no need to look for its data child property). In a helper, you can also access the template through Template.instance().
In an event handler, the template instance is passed as the 2nd argument of the listener.

Subscribing to changes in a Collection but not in a template

I'm very new to meteor, so apologies if I'm missing something very basic here.
I thought it would be fun to create a very simple textpad style app to check out meteor. I took the todo app and changed the data structures to be 'folders' and 'docs' rather than 'lists' and 'todos', so I have a list of folders and when you click on the folder you get a list of the documents in that folder.
I've then added some code to show the 'content' attribute of a single 'doc' when one of the docs in the list is clicked.
I'm using ace to add some pretty print to the content of the doc (https://github.com/ajaxorg/ace). I've set ace up to work with a hidden textarea containing the plaintext version of my document, and the editor object takes this text and pretty prints it.
The problem with ace is that I don't want the template containing the ace editor to be replaced every time the contents of the doc changes (as it takes half a second to reinitialise, which is a crappy experience after every character is typed!). Instead, I want to update the textarea template and then use the ace API to tell the editor to update it's input based on what is in the textarea.
Now, this is probably the wrong way to approach the problem, but I've ended up using two templates. The first contains a textarea containing doc.contents, which is reactive to the underlying model:
<template name="doc_content">
<textarea name="editor">{{content}}</textarea>
</template>
The second one contains the 'editor' div which ace uses to display the pretty printed text.
<template name="doc_init">
<div id="editor"></div>
</template>
The idea is that the first template will update every time the user types (on all clients), and the second template is only ever re-loaded for each new doc we load.
Template.doc_content.content = function() {
var doc_id = Session.get('viewing_itemname');
if (!doc_id) {
return {};
}
var doc = Docs.findOne({_id:doc_id});
if (doc && doc.content) {
// #1 Later
var editor = Session.get('editor');
if (editor) {
editor.getSession().setValue(doc.content);
}
return doc.content;
} else {
return '';
}
};
When you enter text into the editor div I make a call to Docs.update(doc_id, {$set: {content: text}});, which updates the value in the textarea on each client. All good so far.
editor.getSession().on('change', function(){
var text = editor.getSession().getValue();
Docs.update(doc_id, {$set: {content: text}});
});
What I want to do, for all clients other than the client which made the change, is to subscribe to the change for that doc and call editor.getSession().setContent() with the text which has just been changed, taking the text from the textarea and using it to fill the editor.
I've tried to do this by making that call from the template containing the textarea (as this changes whenever the doc is updated - see #1 above). However, this puts the clients into an infinite loop because changing the value in the editor causes another call to Docs.update.
Obviously this doesn't happen when you render a template, so I'm assuming there's some magic in meteor which can prevent this happening, but I'm not sure how.
Any thoughts?
TIA!
There's a lot to absorb in your question, but if I understand correctly, you might simply be after Deps.autorun:
Deps.autorun(function () {
var doc_id = Session.get('viewing_itemname');
if (!doc_id) {
return {};
}
var doc = Docs.findOne({_id:doc_id});
// do stuff with doc
});
Deps.autorun is really useful in that it will get re-run if any of its
dependencies change. These dependencies are limited to those that are "reactive"
such as Collections and Sessions, or anything that implements the reactive API.
In your case, both Session.get and findOne are reactive so if their values
change at all, Deps.autorun will run the function again.

Resources