How to create extension to curve texts in svg-edit? - javascript

I want to use svg-edit plugin in my project. Now I want to create extension to curve texts like:
svgEditor.addExtension("Curve text!", function() {'use strict';
return {
name: "Curve text",
svgicons: svgEditor.curConfig.extPath + "text_curve-icon.xml",
buttons: [{
id: "text_curve",
type: "mode",
title: "Curve the text",
events: {
'click': function() {
svgCanvas.setMode("text_curve");
var textElement = $(svgCanvas.getSelectedElems()[0]);
var textPath = '<text>' +
' <textPath xlink:href="#relativeCurve">' +
$(svgCanvas.getSelectedElems()[0]).text() +
' </textPath>' +
'</text>';
$('#svgcontent').prepend('<defs><path d="m0,350c100,-100 200,-200 300,-200c100,0 200,200 300,200c100,0 200,-200 300,-200" id="relativeCurve"/></defs>');
$(textElement).replaceWith(textPath);
}
}
}],
mouseDown: function() {
if(svgCanvas.getMode() == "text_curve") {
return {started: true};
}
},
mouseUp: function(opts) {
if(svgCanvas.getMode() == "text_curve") {
}
}
};
});
But it doesn't work, how can I create this?

Related

Is it possible to plot "live data" in R language?

We want to plot live data in this site https://www.highcharts.com/demo/live-data is it possible to plot it with Highcharter library in R language if not is there any another solution to do that with R language?
Here is JavaScript code:
var defaultData = 'https://demo-live-data.highcharts.com/time-data.csv';
var urlInput = document.getElementById('fetchURL');
var pollingCheckbox = document.getElementById('enablePolling');
var pollingInput = document.getElementById('pollingTime');
function createChart() {
Highcharts.chart('container', {
chart: {
type: 'spline'
},
title: {
text: 'Live Data'
},
accessibility: {
announceNewData: {
enabled: true,
minAnnounceInterval: 15000,
announcementFormatter: function (allSeries, newSeries, newPoint) {
if (newPoint) {
return 'New point added. Value: ' + newPoint.y;
}
return false;
}
}
},
data: {
csvURL: urlInput.value,
enablePolling: pollingCheckbox.checked === true,
dataRefreshRate: parseInt(pollingInput.value, 10)
}
});
if (pollingInput.value < 1 || !pollingInput.value) {
pollingInput.value = 1;
}
}
urlInput.value = defaultData;
// We recreate instead of using chart update to make sure the loaded CSV
// and such is completely gone.
pollingCheckbox.onchange = urlInput.onchange = pollingInput.onchange = createChart;
// Create the chart
createChart();

AngularJS image carousel with filter

I have taken about 6 runs at this and while I can get many PARTS of it working, I can't seem to get everything functioning like I want it to. This is the latest attempt. This was originally written with just JavaScript but as an exercise I am trying to change it to AngularJS.
Template normal.html:
<section id="container" class="container panels-backface-invisible" >
<div id="carousel" class="panels-backface-invisible 3rows">
<figure ng-repeat="movie in movies.data | filterMultiple:{genres:genList,wildcard:wcSearch}" class="folder figure"
style="transform: {{carousel.rotateFn}}({{carousel.theta*$index}}deg) translateZ({{carousel.radius}}px);" >
</figure></div>
</section>
<div class="searchbox"><label>Wildcard Title Search</label><input type="text" style="width: 100px;" ng-model="wcSearch">
</div>
<div style="display: inline-block;
position: absolute;
right: 8%;
bottom: 1px;
width: 15%;"
multi-select
input-model="genreList"
button-label="name"
item-label="icon"
tick-property="ticked"
selection-mode="multiple"
helper-elements=""
on-open="msOpen( data )"
on-close="msClose( data )"
on-item-click="msClick( data )"
>
</div>
app.js:
angular.module('MovieCarousel', ['ui.router','multi-select'])
.config(function config($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
$stateProvider.state("index",{
url:"",
controller:"MovieFlowCtrl",
templateUrl:"templates/normal.html",
resolve:{
movieData: function($http){
var promise = $http.get('moviedata.php').
success(function(data) {
var mData={};
mData.count = data.length*2;
mData.data = data;
return mData;
});
return promise;
}
}
})
$stateProvider.state("new",{
url:"/New",
controller:"MovieFlowCtrl",
templateUrl:"templates/New.html",
resolve:{
movieData: function($http){
var promise = $http.get('moviedata.php?type=N').
success(function(data) {
var mData={};
mData.count = data.length*2;
mData.data = data;
return mData;
});
return promise;
}
}
})
})
.controller('MovieFlowCtrl', function ($scope, $rootScope, movieData, $filter) {
$scope.carousel = {};
$scope.carousel.isHorizontal = true;
$scope.movies = movieData;
$scope.carousel.element = document.getElementById('carousel');
setTimeout( function(){
document.body.addClassName('ready');
}, 0);
$scope.clearSelection=function() {
$rootScope.genrefilter = [];
$('#selectable .ui-selected').removeClass('ui-selected');
}
$rootScope.genrefilter = [];
$scope.msClick = function(Data) {
console.log(Data);
var selectedind = $rootScope.genrefilter.indexOf(Data.name);
if(selectedind>=0){
$rootScope.genrefilter.splice(selectedind,1);
}
else{
$rootScope.genrefilter.push(Data.name);
}
$scope.carousel.filter();
// $filter('filterMultiple');
}
$rootScope.genreList = [
{ icon: "<img src=/img/Action.png />", name: "Action", ticked: false },
{ icon: "<img src=/img/Adventure.png>", name: "Adventure", ticked: false },
{ icon: "<img src=/img/Animation.png>", name: "Animation", ticked: false },
{ icon: "<img src=/img/Biography.png />", name: "Biography", ticked: false },
{ icon: "<img src=/img/Comedy.png />", name: "Comedy", ticked: false },
{ icon: "<img src=/img/Comic-Book.png />", name: "Comic-Book", ticked: false },
{ icon: "<img src=/img/Crime.png>", name: "Crime", ticked: false },
{ icon: "<img src=/img/Disaster.png />", name: "Disaster", ticked: false },
{ icon: "<img src=/img/Drama.png />", name: "Drama", ticked: false },
{ icon: "<img src=/img/Fantasy.png />", name: "Fantasy", ticked: false },
{ icon: "<img src=/img/History.png>", name: "History", ticked: false },
{ icon: "<img src=/img/Horror.png>", name: "Horror", ticked: false },
{ icon: "<img src=/img/Music.png />", name: "Music", ticked: false },
{ icon: "<img src=/img/Musical.png />", name: "Musical", ticked: false },
{ icon: "<img src=/img/Mystery.png />", name: "Mystery", ticked: false },
{ icon: "<img src=/img/Romance.png>", name: "Romance", ticked: false },
{ icon: "<img src=/img/Sci-Fi.png />", name: "Sci-Fi", ticked: false },
{ icon: "<img src=/img/Sport.png />", name: "Sport", ticked: false },
{ icon: "<img src=/img/Thriller.png />", name: "Thriller", ticked: false },
{ icon: "<img src=/img/War.png>", name: "War", ticked: false },
{ icon: "<img src=/img/Western.png />", name: "Western", ticked: false }
];
$scope.msOpen = function( data ) {
console.log("open");
draglock = 1;
}
$scope.msClose = function( data ) {
console.log("closed");
draglock = 0; }
$rootScope.modify = function(){
if(wheight>=930){
sz1=300;
sz2=2.4;
}
else if(wheight>700 && wheight<929) {
sz1=283;
sz2= 3;
}
else if(wheight>500 && wheight<699) {
sz1=221;
sz2= 3.8;
}
else if(wheight>400 && wheight<499) {
sz1=157;
sz2=5.2;
}
else{
sz1=125;
sz2=6.6;
}
console.log("Modify");
// sz1 = $(window).width()*0.19;
panelCount = $rootScope.panelCount;
$scope.carousel.sz1 = sz1;
$scope.carousel.panelSize = sz1;
// if(typeof $scope.carousel.element.children[0] != 'undefined'){$scope.carousel.panelSize = $scope.carousel.element.children[0].clientWidth;}
$scope.carousel.rotateFn = $scope.carousel.isHorizontal ? 'rotateY' : 'rotateX';
// console.log(panelCount);
$scope.carousel.theta = 359 / ((panelCount+mrows));
theta = $scope.carousel.theta;
rotateXY = $scope.carousel.rotateFn;
var sizeadj = 12;
if(mrows == 1){sizeadj = 0.8;}
if(mrows == 2){sizeadj = sz2;}
$scope.carousel.radius = ($scope.carousel.panelSize*(mrows+panelCount/mrows))/(2*Math.PI); //Math.round(( $scope.carousel.panelSize/sizeadj) / Math.tan( Math.PI / (($scope.carousel.panelCount+mrows)) ) );
radius = $scope.carousel.radius;
$scope.carousel.rotation = Math.round( $scope.carousel.rotation / $scope.carousel.theta ) * $scope.carousel.theta;
rotation = $scope.carousel.rotation;
$scope.carousel.rotation = -4;
$scope.carousel.element.style[ transformProp ] = 'translateZ(-' + radius + 'px) ' + rotateXY + '(' + rotation + 'deg)';
// if(typeof $scope.carousel.element.children[0] != 'undefined'){$scope.carousel.sz1 = $scope.carousel.element.children[0].clientWidth;}
}
$scope.doubleClick = function(movieName){
console.log("test");
jQuery.post("/processrequest.php",
{name: movieName },
function(response){
if(response.length>5){alert(response);}
});
}
$rootScope.toggleCarousel = function(toMod){
panelCount = $rootScope.panelCount;
console.log("toggleCarousel");
if(toMod){return;}
if(panelCount > 20){
$('#container').addClass('container');
$('figure').addClass('figure');
filtered = 0;
$rootScope.modify(panelCount);
}
else{
$('figure').attr('style', '');
$('#carousel').attr('style', 'transform: translate(0px,0px)');
$('#container').removeClass('container');
$('figure').removeClass('figure');
filtered = 1;
}
$scope.carousel.element.style[ transformProp ] = 'translateZ(-' + radius + 'px) ' + rotateXY + '(' + rotation + 'deg)';
}
})
.directive('myDraggable', ['$document', function($document) {
return function(scope, element, attr) {
var startX = 0, startY = 0, x = 0, y = 0;
element.css({
position: 'relative',
border: '1px solid red',
backgroundColor: 'lightgrey',
cursor: 'pointer'
});
element.on('mousedown', function(event) {
// Prevent default dragging of selected content
event.preventDefault();
startX = event.pageX - x;
startY = event.pageY - y;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
});
function mousemove(event) {
y = event.pageY - startY;
x = event.pageX - startX;
element.css({
top: y + 'px',
left: x + 'px'
});
}
function mouseup() {
$document.off('mousemove', mousemove);
$document.off('mouseup', mouseup);
}
};
}])
.filter('filterMultiple',["$rootScope", '$filter', function ($rootScope,$filter) {
return function (items, keyObj) {
var wcSearch = keyObj.wildcard;
var genres = keyObj.genres;
var filterObj=[];
for(var i=0;i<items.length;i++){
var filtered = true;
if(typeof wcSearch === 'undefined'){}
else if(wcSearch.length > 0){
if(wcSearch.toUpperCase().substring(0,wcSearch.length) != items[i].title.toUpperCase().substring(0,wcSearch.length) && wcSearch.toUpperCase().substring(0,wcSearch.length) != items[i].sortTitle.toUpperCase().substring(0,wcSearch.length)){filtered = false;}
}
if(filtered == true){
for(var x=0;x<$rootScope.genrefilter.length;x++){
if(items[i].genres.indexOf($rootScope.genrefilter[x])<0){filtered = false;}
}
}
if(filtered == true){
filterObj.push(items[i]);
}
}
*******Disabled due to infinite loop
// var ticked=[];
// var genreObj={};
// var $tempGenre=[];
// $tempGenre.genreList = $rootScope.genreList;
// for (var i=0;i<$tempGenre.genreList.length;i++){
// ticked[$tempGenre.genreList[i].name]=$tempGenre.genreList[i].ticked;
// }
// $tempGenre.genreList=[];
// if(typeof filterObj !== 'undefined'){
// for (var i=0;i<filterObj.length;i++){
// for (var z=0;z<filterObj[i].genres.length;z++){
// if($tempGenre.genreList.map(function(e) { return e.name; }).indexOf(filterObj[i].genres[z])==-1)
// {
// if(filterObj[i].genres[z] !=""){
// genreObj = {icon: "<img src=/img/"+filterObj[i].genres[z]+".png />", name: filterObj[i].genres[z], ticked: ticked[filterObj[i].genres[z]] };
// $tempGenre.genreList.push(genreObj);
// }
// }
// }
// }
// }
// $tempGenre.genreList.sort();
var toModify=false;
if($rootScope.panelCount == filterObj.length){toModify=true;}
console.log($rootScope.panelCount+","+filterObj.length);
$rootScope.panelCount = filterObj.length;
$rootScope.toggleCarousel(toModify);
$rootScope.genreList = $tempGenre;
return filterObj;
}
}])
.filter('unique', function() {
return function(input, key) {
var unique = {};
var uniqueList = [];
for(var i = 0; i < input.length; i++){
if(typeof unique[input[i][key]] == "undefined"){
unique[input[i][key]] = "";
uniqueList.push(input[i]);
}
}
return uniqueList;
};
})
.directive('resize', function($window) {
return function (scope, element, attr) {
var w = angular.element($window);
scope.$watch(function () {
return {
'h': w.height(),
'w': w.width()
};
}, function (newValue, oldValue) {
scope.windowHeight = newValue.h;
scope.windowWidth = newValue.w;
scope.resizeWithOffset = function (offsetH) {
scope.$eval(attr.notifier);
return {
'height': (newValue.h - offsetH) + 'px'
};
};
}, true);
w.bind('resize', function () {
scope.$apply();
});
}
})
Obviously I'm very new to AngularJS and am likely doing everything wrong. I have searched for similar solutions to learn from but can't find anything that is doing quite what I'm working on. The main issue I am having at this point is if I include the code that limits genres to only those available in the sub-set of movie results it loops infinitely, and no matter which angle I take I can't seem to get it all to work together. Some guidance would be greatly appreciated, even if its just to recommend a better structure, I'm sure I'm putting too much into the controller among other fails.
Other unfinished portions:
- views for each type of content
- re-size elements on window size
- Drag and scroll behavior

jsPlumb source connector does not move when source container is dragged

<div id="a"></div>
<div id="b"></div>
<div id="c"></div>
var conn = "";
var instance = "";
$(function(){
create_line("b");
$('#b').click(function(){
create_line("b");
});
$('#c').click(function(){
create_line("c");
});
});
function create_line(el){
jsPlumb.ready(function() {
if(conn!=""){
jsPlumb.detach(conn);
}
instance = jsPlumb.getInstance({
Anchors : [ "Center", "Center" ],
DragOptions : { cursor: 'pointer', zIndex:2000 },
EndpointStyles : [{ fillStyle:"red", outlineColor:"white", outlineWidth:10 }, { fillStyle:"red", outlineColor:"white", outlineWidth:10 }],
Endpoints : [ ["Dot", { radius:5 } ], [ "Dot", { radius:5 } ] ],
PaintStyle : {
strokeStyle:"red",
lineWidth:3
}
});
var a = jsPlumb.getSelector("#a");
instance.draggable(a);
conn = instance.connect({
source:a,
target:el,
connector:[ "Straight" ]
});
});
}
http://jsfiddle.net/wwc7G/5/
when windows load the line connector between #a and #b move, but when i click on #c the line connector between #a and #c does not move.
Please help and sorry for my english.
Removing parent from the makeSource call worked for me.
http://jsfiddle.net/wwc7G/27/
jsPlumb.ready(function() {
jsPlumb.Defaults.Container=$("#container");
jsPlumb.Defaults.PaintStyle = { strokeStyle:"#F09E30", lineWidth:2, dashstyle: '3 3', };
jsPlumb.Defaults.EndpointStyle = { radius:7, fillStyle:"#F09E30" };
jsPlumb.importDefaults({Connector : [ "Bezier", { curviness:50 } ]});
var i = 1;
$('#addproject').click(function(e) {
var newAgent = $('<div>').attr('id', 'project' + i).addClass('project');
newAgent.text('Project ' + i);
$('#container').append(newAgent);
jsPlumb.draggable(newAgent, {
containment: 'parent'
});
i++;
});
$("#container").on('click','.project',function(e) {
var newState = $('<div>').attr('id', 'state' + i).addClass('task');
var title = $('<div>').addClass('title').text('Task ' + i);
var connect = $('<div>').addClass('connect').text('click here to drag a bond');
newState.css({
'top': e.pageY,
'left': e.pageX
});
newState.append(title);
newState.append(connect);
$(this).append(newState);
jsPlumb.makeTarget(newState, {
anchor: 'Continuous'
});
jsPlumb.makeSource(connect, {
anchor: 'Continuous'
});
newState.dblclick(function(e) {
jsPlumb.detachAllConnections($(this));
$(this).remove();
e.stopPropagation();
});
i++;
});
});

Kendo TreeView Search with Highlight

I have a KendoTreeview with spriteclass. I want to highlight the nodes (root as well as child nodes) with my search term. I have implemented the search functionality. But the issue when i search it is highlighting the term in the nodes but missing the SpriteClass in the nodes after first search. Any idea ?
jsFiddle code
$('#search-term').on('keyup', function () {
$('span.k-in > span.highlight').each(function () {
$(this).parent().text($(this).parent().text());
});
// ignore if no search term
if ($.trim($(this).val()) == '') {
return;
}
var term = this.value.toUpperCase();
var tlen = term.length;
$('#treeview-sprites span.k-in').each(function (index) {
var text = $(this).text();
var html = '';
var q = 0;
while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
html += text.substring(q, p) + '<span class="highlight">' + text.substr(p, tlen) + '</span>';
q = p + tlen;
}
if (q > 0) {
html += text.substring(q);
$(this).html(html);
$(this).parentsUntil('.k-treeview').filter('.k-item').each(
function (index, element) {
$('#treeview-sprites').data('kendoTreeView').expand($(this));
$(this).data('search-term', term);
});
}
});
$("#treeview-sprites").kendoTreeView({
dataSource: [{
text: "My Documents",
expanded: true,
spriteCssClass: "rootfolder",
items: [{
text: "Kendo UI Project",
expanded: true,
spriteCssClass: "folder",
items: [{
text: "about.html",
spriteCssClass: "html"
}, {
text: "index.html",
spriteCssClass: "html"
}, {
text: "logo.png",
spriteCssClass: "image"
}]
}, {
text: "New Web Site",
expanded: true,
spriteCssClass: "folder",
items: [{
text: "mockup.jpg",
spriteCssClass: "image"
}, {
text: "Research.pdf",
spriteCssClass: "pdf"
}, ]
}, {
text: "Reports",
expanded: true,
spriteCssClass: "folder",
items: [{
text: "February.pdf",
spriteCssClass: "pdf"
}, {
text: "March.pdf",
spriteCssClass: "pdf"
}, {
text: "April.pdf",
spriteCssClass: "pdf"
}]
}]
}]
})
;
Kendo's tree view widget doesn't like it if you muck around in its HTML, so I suggest modifying the data source instead (this will require the encoded option for all items in the DS).
In the keyup handler, you reset the DS whenever you search to clear highlighting, then instead of replacing the element's HTML directly, you set the model's text property:
$('#search-term').on('keyup', function () {
var treeView = $("#treeview-sprites").getKendoTreeView();
treeView.dataSource.data(pristine);
// ignore if no search term
if ($.trim($(this).val()) == '') {
return;
}
var term = this.value.toUpperCase();
var tlen = term.length;
$('#treeview-sprites span.k-in').each(function (index) {
var text = $(this).text();
var html = '';
var q = 0;
while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
html += text.substring(q, p) + '<span class="highlight">' + text.substr(p, tlen) + '</span>';
q = p + tlen;
}
if (q > 0) {
html += text.substring(q);
var dataItem = treeView.dataItem($(this));
dataItem.set("text", html);
$(this).parentsUntil('.k-treeview').filter('.k-item').each(
function (index, element) {
$('#treeview-sprites').data('kendoTreeView').expand($(this));
$(this).data('search-term', term);
});
}
});
$('#treeview-sprites .k-item').each(function () {
if ($(this).data('search-term') != term) {
$('#treeview-sprites').data('kendoTreeView').collapse($(this));
}
});
});
The tree definition needs the encoded option for this to work:
var pristine = [{
encoded: false,
text: "Kendo UI Project",
expanded: true,
spriteCssClass: "folder",
items: [{
encoded: false,
text: "about.html",
spriteCssClass: "html"
}, {
encoded: false,
text: "index.html",
spriteCssClass: "html"
}, {
encoded: false,
text: "logo.png",
spriteCssClass: "image"
}]
}, {
encoded: false,
text: "New Web Site",
expanded: true,
spriteCssClass: "folder",
items: [{
encoded: false,
text: "mockup.jpg",
spriteCssClass: "image"
}, {
encoded: false,
text: "Research.pdf",
spriteCssClass: "pdf"
}, ]
}, {
encoded: false,
text: "Reports",
expanded: true,
spriteCssClass: "folder",
items: [{
encoded: false,
text: "February.pdf",
spriteCssClass: "pdf"
}, {
encoded: false,
text: "March.pdf",
spriteCssClass: "pdf"
}, {
encoded: false,
text: "April.pdf",
spriteCssClass: "pdf"
}]
}];
$("#treeview-sprites").kendoTreeView({
dataSource: [{
text: "My Documents",
expanded: true,
spriteCssClass: "rootfolder",
items: pristine
}]
});
(demo)
Good job guys, just what I neeeded!
Using your code I did a small tweak (actually added just two lines of jquery filtering), so that now when searching for a keyword, the treeview shows only the branches that contain highlighted texts. Easy peasy! :)
Other branches are hidden if they do not contain the higlighted text. Simple as that.
This means we now have a VisualStudio-like treeview search (see the Visual Studio Solution Explorer Search and Filter: http://goo.gl/qr7yVb).
Here's my code and demo on jsfiddle: http://jsfiddle.net/ComboFusion/d0qespaz/2/
HTML:
<input id="treeViewSearchInput"></input>
<ul id="treeview">
<li data-expanded="true">My Web Site
<ul>
<li data-expanded="true">images
<ul>
<li>logo.png</li>
<li>body-back.png</li>
<li>my-photo.jpg</li>
</ul>
</li>
<li data-expanded="true">resources
<ul>
<li data-expanded="true">pdf
<ul>
<li>brochure.pdf</li>
<li>prices.pdf</li>
</ul>
</li>
<li>zip</li>
</ul>
</li>
<li>about.html</li>
<li>contacts.html</li>
<li>index.html</li>
<li>portfolio.html</li>
</ul>
</li>
<li>Another Root</li>
</ul>
CSS
span.k-in > span.highlight {
background: #7EA700;
color: #ffffff;
border: 1px solid green;
padding: 1px;
}
JAVASCRIPT
function InitSearch(treeViewId, searchInputId) {
var tv = $(treeViewId).data('kendoTreeView');
$(searchInputId).on('keyup', function () {
$(treeViewId + ' li.k-item').show();
$('span.k-in > span.highlight').each(function () {
$(this).parent().text($(this).parent().text());
});
// ignore if no search term
if ($.trim($(this).val()) === '') {
return;
}
var term = this.value.toUpperCase();
var tlen = term.length;
$(treeViewId + ' span.k-in').each(function (index) {
var text = $(this).text();
var html = '';
var q = 0;
var p;
while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
html += text.substring(q, p) + '<span class="highlight">' + text.substr(p, tlen) + '</span>';
q = p + tlen;
}
if (q > 0) {
html += text.substring(q);
$(this).html(html);
$(this).parentsUntil('.k-treeview').filter('.k-item').each(function (index, element) {
tv.expand($(this));
$(this).data('SearchTerm', term);
});
}
});
$(treeViewId + ' li.k-item:not(:has(".highlight"))').hide();
$(treeViewId + ' li.k-item').expand(".k-item");
});
}
var $tv = $("#treeview").kendoTreeView();
InitSearch("#treeview", "#treeViewSearchInput");
Another tweak from me :)
What I did was change the highlight code in order to preserve anything else that might exist in the node html (such as sprite span for example).
I also implemented it as a TypeScript class wrapper around the TreeView.
If you don't want TypeScript stuff just copy the code out and it should work fine :)
export class SearchableTreeView {
TreeView: kendo.ui.TreeView;
emphasisClass: string;
constructor(treeView: kendo.ui.TreeView) {
this.TreeView = treeView;
this.emphasisClass = "bg-warning";
}
search(term: string): void {
var treeElement: JQuery = this.TreeView.element;
var tv: kendo.ui.TreeView = this.TreeView;
var emphClass = this.emphasisClass;
this.resetHighlights();
// ignore if no search term
if ($.trim(term) === '') { return; }
var term = term.toUpperCase();
var tlen = term.length;
$('span.k-in', treeElement).each(function (index) {
// find all corresponding nodes
var node = $(this);
var htmlContent = node.html();
var text = node.text();
var searchPosition = text.toUpperCase().indexOf(term);
if (searchPosition === -1) {
// continue
return true;
}
var generatedHtml = '<span class="highlight-container">' + text.substr(0, searchPosition) + '<span class="' + emphClass + '">' + text.substr(searchPosition, tlen) + '</span>' + text.substr(searchPosition + tlen) + '</span>';
htmlContent = htmlContent.replace(text, generatedHtml);
node.html(htmlContent);
node.parentsUntil('.k-treeview').filter('.k-item').each(
function (index, element) {
tv.expand($(this));
$(this).data('search-term', term);
}
);
});
$('.k-item', treeElement).each(function () {
if ($(this).data('search-term') != term) {
tv.collapse($(this));
}
});
}
resetHighlights(): void {
this.TreeView.element.find("span.k-in:has('." + this.emphasisClass + "')")
.each(function () {
var node = $(this);
var text = node.text();
$(".highlight-container", node).remove();
node.append(text);
});
}
}
$("#textBox").on("input", function () {
var query = this.value.toLowerCase();
var dataSource = $("#Treeview").data("kendoTreeView").dataSource;
filter(dataSource, query);
});
function filter(dataSource, query) {
var uidData = [];
var data = dataSource instanceof kendo.data.DataSource && dataSource.data();
for (var i = 0; i < data.length; i++) {
var item = data[i];
var text = item.text.toLowerCase();
var isChecked = item.checked;
var itemVisible =
query === true
|| query === ""
|| text.indexOf(query) >= 0;
uidData.push({ UID: item.uid, Visible: itemVisible });
}
if (query != "") {
$.each(uidData, function (index, datavalue) {
if (datavalue.Visible) {
$("li[data-uid='" + datavalue.UID + "']").addClass("highlight");
}
else {
$("li[data-uid='" + datavalue.UID + "']").removeClass("highlight");
}
});
}
else {
$.each(uidData, function (index, datavalue) {
$("li[data-uid='" + datavalue.UID + "']").removeClass("highlight");
});
}
}
CSS :
.highlight {
background:#0fa1ba;
color:white;
}
For Angular 2+ you need to create a pipe for this feature.
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
import { NGXLogger } from 'ngx-logger';
#Pipe({
name: 'highlight'
})
export class TypeaheadHighlight implements PipeTransform {
constructor(private readonly _sanitizer: DomSanitizer, private readonly logger: NGXLogger) { }
transform(matchItem: any, query: any): string {
let matchedItem: any;
if (matchItem) {
matchedItem = matchItem.toString();
}
if (this.containsHtml(matchedItem)) {
this.logger.warn('Unsafe use of typeahead please use ngSanitize');
}
matchedItem = query ? ('' + matchedItem).replace(new RegExp(this.escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchedItem; // Replaces the capture string with a the same string inside of a "strong" tag
if (!this._sanitizer) {
matchedItem = this._sanitizer.bypassSecurityTrustHtml(matchedItem);
}
return matchedItem;
}
escapeRegexp = (queryToEscape) => queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
containsHtml = (matchItem) => /<.*>/g.test(matchItem);
}
Use of this pipe in html template....
<input name="searchTerm" type="text" [(ngModel)]="searchTerm" (keyup)='onkeyup(searchTerm)'
/>
</div>
<div style="height: 70vh;overflow: auto">
<kendo-treeview style="margin-top: 50px" id="availableColumns" [nodes]="availableColumns"
textField="displayName" kendoTreeViewExpandable kendoTreeViewFlatDataBinding idField="id"
parentIdField="parentId">
<ng-template kendoTreeViewNodeTemplate let-dataItem>
<span [tooltip]="dataItem.columnDescription"
[innerHtml]="dataItem.displayName | highlight:searchTerm "></span>
</ng-template>
</kendo-treeview>
</div>

Developing custom kendo ui widget

How can I develop a custom widget behaving like this sample:
http://jsfiddle.net/anilca/u2HF7/
Here is my kickstart reading, but I could not find out how to define the templates of dropdownlists and link them together by change events.
(function($) {
var kendo = window.kendo,
ui = kendo.ui,
Widget = ui.Widget;
var Editable = Widget.extend({
init: function(element, options) {
var that = this;
Widget.fn.init.call(this, element, options);
that._create();
},
options: {
name: "Editable",
value: " ",
editable: false
},
_create: function() {
var that = this;
// create dropdowns from templates and append them to DOM
},
_templates: {
dropDown: "?"
}
});
ui.plugin(Editable);
})(jQuery);
Following the blog you linked, simply do what he did - define your templates then create the drop-downs in your _create() function. It is not necessary to use the kendo.template() function on each drop down list, as it does not bind objects as well as you think it would. Instead, the key is to use kendo.bind() and pass in the options as your view model.
Here is a JsBin working example.
// listen for doc ready because this is js bin and my code is not really "in" the HTML
// where I can control it.
$(function() {
// wrap the widget in a closure. Not necessary in doc ready, but a good practice
(function($) {
var kendo = window.kendo,
ui = kendo.ui,
Widget = ui.Widget,
periods = [{ text: "PERIOD: YEAR", value: "YEAR" }, { text: "PERIOD: QUARTER", value: "QUARTER" }],
quarters = [{ text: "1. Quarter", value: 1 }, { text: "2. Quarter", value: 2 }, { text: "3. Quarter", value: 3 }, { text: "4. Quarter", value: 4 }],
years = [2011, 2012, 2013, 2014];
var LinkedDropDowns = Widget.extend({
init: function(element, options) {
var that = this;
Widget.fn.init.call(that, element, options);
that._create();
},
options: {
name: "LinkedDropDowns",
period: "YEAR",
periods: periods,
year: 2011,
years: years,
yearVisible: true,
quarter: 1,
quarters: quarters,
quarterVisible: false,
onPeriodChange: function(e) {
switch(e.sender.value()) {
case "YEAR":
this.set("yearVisible", true);
this.set("quarterVisible", false);
break;
case "QUARTER":
this.set("yearVisible", true);
this.set("quarterVisible", true);
break;
default:
break;
}
},
onYearChange: function(e) {
alert(e.sender.value());
},
onQuarterChange: function(e) {
alert(e.sender.value());
}
},
_create: function() {
var that = this;
// create dropdowns from templates and append them to DOM
that.periodDropDown = $(that._templates.periodDropDown);
that.yearDropDown = $(that._templates.yearDropDown);
that.quarterDropDown = $(that._templates.quarterDropDown);
// append all elements to the DOM
that.element.append(that.periodDropDown)
.append(that.yearDropDown)
.append(that.quarterDropDown);
kendo.bind(that.element, that.options);
},
_templates: {
periodDropDown: "<input id='period' data-role='dropdownlist' data-text-field='text' data-value-field='value' data-bind='value: period, source: periods, events: { change: onPeriodChange }' />",
yearDropDown: "<input id='year' data-role='dropdownlist' data-bind='visible: yearVisible, value: year, source: years, events: { change: onYearChange }' style='width: 90px' />",
quarterDropDown: "<input id='quarter' data-role='dropdownlist' data-text-field='text' data-value-field='value' data-bind='visible: quarterVisible, value: quarter, source: quarters, events: { change: onQuarterChange }' style='width: 110px' />"
}
});
ui.plugin(LinkedDropDowns);
})(jQuery);
$('#dropdowns').kendoLinkedDropDowns();
});

Categories