I'm trying to make a web-part which is basically a Kendo tabstrip . it has a simple ul on it's own and linking external html files to each relative li using a javascript code. it works fine so far.
but now I want to be able to call functions to add or remove whatever file I selected to my tabstrip and so far it's not working .
I've searched and found some functions to the job but this one is closer to what I had in mind .
when I use the add button the tabstrip is made but the contecturl link doesn't work and it's just an empty tab.
<------------------------ web-part ------------------------>
<div class="row">
<input type='text' id='tabname' name='tabname'>
<input type='text' id='tabLink' name='tabLink'>
<input type="button" value="Add Tab" onclick="AddTab()" />
<input type="button" value="Remove Tab" onclick="closeTab()" />
</div>
<div id="tabstrip">
<ul id="tabStripUL">
<li class="k-state-active">tab1</li>
<li>tab2</li>
<li>tab3</li>
</ul>
<------------------------ Javascript ------------------------>
$(document).ready(function () {
InitLoadTabstrip();
});
function InitLoadTabstrip() {
var ts = $("#tabstrip").kendoTabStrip({
animation: { open: { effects: "fadeIn" } },
select: function(element){selecttab(element)},
contentUrls: [
'Page1.html',
'Page2.html',
'Page3.html',
]
}).data('kendoTabStrip');
}
function selecttab(element) {
var tabStrip1 = $('#tabstrip').kendoTabStrip().data("kendoTabStrip");
var item = tabStrip1.element.find("li:contains("+$(element.item).text()+")"),
itemIdx = item.index();
$("#tabstrip").data("kendoTabStrip").select(itemIdx);
}
function AddTab() {
var title = jQuery("#tabname").val();
var Address = jQuery("#tabLink").val();
var tabStrip = $("#tabstrip").kendoTabStrip().data("kendoTabStrip");
tabStrip.append({
text: title,
contentUrl: Address
});
tabStrip.select((tabStrip.tabGroup.children("li").length - 1));
}
function closeTab() {
var tabStrip = $('#tabstrip').kendoTabStrip().data("kendoTabStrip");
tabStrip.remove(tabStrip.select());
tabStrip.select((tabStrip.tabGroup.children("li").length - 1));
}
It should get a name and an Address and add that tab to the tabstrip or remove it based on the button.
I'd really appreciate it if someone could help.
<---------------------------- A quick update ----------------------------->
I tried to remove the buttons and simply add a single parameter to the addTab function to add each page that the is called . something like this :
function addTab(tabName) {
var tabStrip = $("#tabstrip").kendoTabStrip().data("kendoTabStrip");
if (tabName == "name1") {
tabStrip.append({
text: "title1",
contentUrl: 'page1.html',
});
}
else if (tabName == "name2") {
tabStrip.append({
text: "title2",
contentUrl: 'page2.html',
});
}
tabStrip.select((tabStrip.tabGroup.children("li").length - 1));
}
and call them like this :
$(document).ready(function () {
InitLoadTabstrip();
});
function InitLoadTabstrip() {
var ts = $("#tabstrip").kendoTabStrip({
animation: { open: { effects: "fadeIn" } },
select: function(element){selecttab(element)},
contentUrls: [
]
}).data('kendoTabStrip');
addTab("name1");
addTab("name2");
}
right now the problem is when I try to add more than one tab , one after the other(like the code), tabstrip sets both list items as active and it breaks the tabstrip. I think it's probably because of the 'tabstrip.select' , but I don't really understand what went wrong .
So I managed to fix it on my own , thought it may help someone else later .
the problem was that after appending I had multiple list items with "k-state-active" class that broke my tabstrip . I used jquery to manually remove the active classes whereever they were and add it up to the first li .
also I used to create a new variable each time I called addTab() instead of working on the same variable which made the whole thing alot slower and didn't have animation and select. so I made 'ts' public to be used in all the functions.
so that final code is like this :
<---------------HTML------------------>
<div id="tabstrip" style="width: 100%">
<ul id="tabStripUL">
</ul>
</div>
<----------------Script--------------->
var ts;
$(document).ready(function () {
InitLoadTabstrip();
});
function InitLoadTabstrip() {
ts = $("#tabstrip").kendoTabStrip({
animation: { open: { duration: 150, effects:"fadeIn" }
},
select: function(element){selecttab(element)},
contentUrls: [
]
}).data('kendoTabStrip');
addTab("tab1");
addTab("tab2");
}
//ts couldn't work on selecttab because of call limited size (don't really know what it is)
function selecttab(element) {
var tabStrip1 = $('#tabstrip').kendoTabStrip().data("kendoTabStrip");
var item = tabStrip1.element.find("li:contains("+$(element.item).text()+")"),
itemIdx = item.index();
$("#tabstrip").data("kendoTabStrip").select(itemIdx);
}
function addTab(tabSelect) {
if (tabSelect == "tab1") {
ts.append({
text: "title1",
contentUrl: 'page1.html',
});
//sets an id to each tab
ts.tabGroup.children().last().attr("id", "tab1");
}
else if (tabSelect == "tab2") {
ts.append({
text: "title2",
contentUrl: 'page2',
});
ts.tabGroup.children().last().attr("id", "tab2");
}
ts.select((ts.tabGroup.children("li").length - 1));
$("#tabstrip li").find(".k-state-active").removeClass("k-state-active k-tab-on-top");
$("#tabstrip li:first").addClass("k-state-active k-tab-on-top");
}
// ClearTS: clears all the tabs and contents
function clearTS() {
$("#tabstrip li").remove();
$("#tabstrip .k-content").remove();
Hope it helps !
Related
I've just started to study bootstrap and I'd like to ask a question about it.
I'm using "bootstrap confirmation" referenced with URL below.
https://github.com/mistic100/Bootstrap-Confirmation/blob/master/example/index.html
I'm trying to use custom button of bootstrap confirmation
and i have a click function for this button as well.
but the problem is when i clicked the button it automatically show confirm box.
I wanted to show it when i call the function,
$("#button_id").confirmation("show");
as before I show confirm box i have to check the validation and get the result first...
Is there any way to do it? ..
ex)
$("#button_id").confirmation({
rootSelector: '',
container: 'body',
buttons: [
{
class: 'class',
value: 'YES',
label: 'YES',
onClick:function(){
}
}
]
});
HTML
<button id="bt1" class="btn btn-default" >Confirmation 1</button>
JS
$("#bt1").click(function() {
var test = prompt("test");
if( test == "test" )
{
$('#bt1').confirmation("show");
}
});
Hope this helps. :)
function validate() {
return true;
}
$('#id').click( function() {
var valid = validate();
if(valid) {
$('#id').modal('show');
}
});
I know the question is not so understandable and might also be duplicate but i cant find the specific solution of my problem so allow me to elaborate.
I am displaying lots of images using bootstrap in article thumbnails
I am using PHP to get the values from the database
I am using a foreach loop and adding elements dynamically
here's a snippet:
foreach ($cursor as $document)
{
foreach ($document["Pics"] as $photos)
{
echo "<article id='hasMenu' class='development design'>
<a href=".$photos["Photo"])." class='swipebox'>
<img src=".$photos["Photo"]." class='work img-responsive'>
</a>
</article>";
}
}
This code fetches all the images from the database and displays it on my page
Now this was the adding part i am having problem in deleting the specific image. I am using a right click context menu but i am not able to get a specific element which i want to delete as there is no id or class name because i dont know how much images will be added....
Here's my context menu snippet:
$(function() {
$.contextMenu({
selector: "#hasMenu",
callback: function(key, options) {
if (key == "delete") {
var m = "clicked: " + key;
window.console && console.log(m) || alert(m);
}
if (key == "open") {
var m = "clicked: " + key;
window.console && console.log(m) || alert(m);
}
},
items: {
"open": {
name: "Open",
icon: "edit"
},
"delete": {
name: "Delete",
icon: "delete"
},
}
});
$('.context-menu-one').on('click', function(e) {
console.log('clicked ', e);
})
});
By this I add a right click context menu that shows Delete and open option.
Now when i will click on delete i want to get the ID of that specific image(article) which i want to delete...
I hope my problem statement is clear...
Firstly, your PHP loop is generating a lot of HTML elements all with the same id of hasMenu, which is invalid. You should change that to a class.
You can then attach the context menu plugin to the elements with that class. Finally you can use the this keyword within each callback function placed on the buttons to reference the elements which triggered the menu to be shown in the first place. Try this:
$.contextMenu({
selector: ".hasMenu",
items: {
"open": {
name: "Open",
icon: "edit",
callback: function(key, opt) {
$(this).find('span').show();
}
},
"delete": {
name: "Delete",
icon: "delete",
callback: function(key, opt) {
$(this).remove();
}
},
}
});
.hasMenu span { display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.4.5/jquery.contextMenu.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.4.5/jquery.contextMenu.min.css" />
<div class="hasMenu">Right click me... #1 <span>Opened content...</span></div>
<div class="hasMenu">Right click me... #2 <span>Opened content...</span></div>
<div class="hasMenu">Right click me... #3 <span>Opened content...</span></div>
<div class="hasMenu">Right click me... #4 <span>Opened content...</span></div>
<div class="hasMenu">Right click me... #5 <span>Opened content...</span></div>
I have a plugin that im making use of called content.js http://innovastudio.com/content-builder.aspx
Im adding in dynamic divs to the page which I would like to have the content.js plugin assigned to it, so I can make use of its functionality.
On a single div, or already defined div within the page, I dont appear to have any issues with multiple divs.
However if I add in a div with the same class, I cant seem to bind the plugin to it.
Ive included the code for instantiating the div with the contentbuilder plugin, but I wondering if there is a way to bind it to new elements that are added to the page with the class of "letter". Or if there is a generic way of binding plugins to divs using jquery.
$('div.letter').contentbuilder({
enableZoom:false,
snippetOpen: true,
imageselect: 'images.html',
fileselect: 'images.html',
snippetFile: '/assets/templates/content-builder/default/snippets.html',
toolbar: 'left',
//sourceEditor: false,
onDrop:function(){
// function for when an item is dragged into the editable area
},
onRender: function () {
var coverLength = $("#coverpage div.row").length;
var mainContent = $("#maincontent div.row").length;
if(coverLength == 0)
{
$("#coverpage").html('<div class="no-content-on-page">Select your content from the right sidebar</div>')
}
else
{
$("#coverpage div.no-content-on-page").remove();
}
if(mainContent == 0)
{
$("#maincontent").html('<div class="no-content-on-page">Select your content from the right sidebar</div>')
}
else
{
$("#maincontent div.no-content-on-page").remove();
}
//custom script here
}
});
If you must add these divs in a dinamic way, i think that you should init the plugin for each time that you add a new div. To avoid init same div twice, use some class like in the following example:
function createLetter(){
$("body").append('<div class="letter mustBeActivated"></div>');
initContentBuilder();
}
function initContentBuilder(){
$('div.letter.mustBeActivated').contentbuilder({
enableZoom:false,
snippetOpen: true,
imageselect: 'images.html',
fileselect: 'images.html',
snippetFile: '/assets/templates/content-builder/default/snippets.html',
toolbar: 'left',
//sourceEditor: false,
onDrop:function(){
// function for when an item is dragged into the editable area
},
onRender: function () {
var coverLength = $("#coverpage div.row").length;
var mainContent = $("#maincontent div.row").length;
if(coverLength == 0)
{
$("#coverpage").html('<div class="no-content-on-page">Select your content from the right sidebar</div>')
}
else
{
$("#coverpage div.no-content-on-page").remove();
}
if(mainContent == 0)
{
$("#maincontent").html('<div class="no-content-on-page">Select your content from the right sidebar</div>')
}
else
{
$("#maincontent div.no-content-on-page").remove();
}
//custom script here
}
}).removeClass('mustBeActivated');
}
I have a jquery code that checks for the class .slide on pageload. I have .slide classes inside my templates that it doesn't find and I am trying to figure out a way to make them find it. (probably by making a directive?)
If anyone has any ideas, I'd greatly appreciate it.
The code is as follows:
var items = $('.slide');
var content = $('.content');
function open() {
$(items).removeClass('close').addClass('open');
}
function close() {
$(items).removeClass('open').addClass('close');
}
$('#navToggle').on(clickevent, function(event) {
event.stopPropagation();
event.preventDefault();
if (content.hasClass('open')) {
close();
} else {
open();
}
});
content.click(function() {
if (content.hasClass('open')) {
close();
}
});
You can create a directive with the same name as your class name:
Say you have two spans with one you need to distinguish using class 'myclass':
<div ng-app="ClassExample" ng-controller="someController">
<span class="myclass myotherclass">target span</span><br/>
<span class="myotherclass">other span</span>
</div>
Then the accompanying js code would include a directive definition using the name of the class 'myclass' and you can restrict this directive to classes using restrict:'C' :
angular.module('ClassExample',[]).directive('myclass', function() {
return {
template:'hello world',
restrict: 'C'
};
}).controller('someController',function() {
});
Here is the fiddle: https://jsfiddle.net/1L3h8y7s/1/
I'm building a mobile app which requires a bunch of open/close tab. I'm trying to find a way to use bindingHandlers to reduce the amount of code. But I seem to miss something. Here's my fiddle.
http://jsfiddle.net/noppanit/4zRrZ/
And this is what I have
<a href="javascript:void(0)" data-bind="click: expandCommentsRatings">Rating
<div style="display:none" data-bind="visible: productCommentsRatingsVisiblity">
<div class="rating" style="width: 85%">3.5 Stars Rating</div>
</div>
</a>
<br/>
<a href="javascript:void(0)" data-bind="click: expandsReviews">Reviews
<div style="display:none" data-bind="visible: productReviewsVisiblity">
<div class="reviews">Reviews</div>
</div>
</a>
var Model = function () {
var productCommentsRatingsVisiblity = ko.observable(false);
var productReviewsVisiblity = ko.observable(false);
var expandCommentsRatings = function (item, event) {
productCommentsRatingsVisiblity(!productCommentsRatingsVisiblity());
if (productCommentsRatingsVisiblity() === false) {
$(event.target).removeClass('expanded');
} else {
$(event.target).addClass('expanded');
}
};
var expandsReviews = function (item, event) {
productReviewsVisiblity(!productReviewsVisiblity());
if (productReviewsVisiblity() === false) {
$(event.target).removeClass('expanded');
} else {
$(event.target).addClass('expanded');
}
};
return {
productCommentsRatingsVisiblity: productCommentsRatingsVisiblity,
productReviewsVisiblity: productReviewsVisiblity,
expandCommentsRatings: expandCommentsRatings,
expandsReviews: expandsReviews
}
};
ko.applyBindings(Model());
How do I reduce the duplication so I can reuse this code to other ViewModel as well. The reason I'm struggling is because I don't know how to pass productCommentsRatingsVisiblity or productReviewsVisiblity to allBindings dynamically. You need to know the name in order to get it.
Thanks.
Sorry for the late reply on this, but I have a solution using bindingHandlers.
The fiddle is here: http://jsfiddle.net/u3m7m/1/
I followed a strategy of creating a toggle bindingHandler which adds the specified class if it's not present on the element, or removes the class if it is. The only state needed to make this happen is the class list on the element, meaning you can delete all those state tracking observables from the model. In fact, this was the model I used:
var Model = function () {
// stuff
};
ko.applyBindings(Model());
The toggle bindingHandler looks like this:
ko.bindingHandlers['toggle'] = {
init: function (element, valueAccessor) {
var value = ko.unwrap(valueAccessor()),
clickHandler = function (e) {
if (!e) {
e = window.event;
}
e.cancelBubble = true;
if (e.stopPropagation) {
e.stopPropagation();
}
var classes = (this.className||'').split(' '),
index = classes.indexOf(value);
if (index >= 0) {
classes.splice(index, 1);
} else {
classes.push(value);
}
element.className = classes.join(' ');
};
element.onclick = clickHandler;
if (element.captureEvents) {
element.captureEvents(Event.CLICK);
}
}
};
Which is hopefully not too complicated, the weird looking stuff with the e object is from here: http://www.quirksmode.org/js/introevents.html
Because I'm using the strategy of using classes only, I had to add to your CSS:
.expandable > div
{
display: none;
}
.expandable.expanded > div
{
display: block;
}
The state tracking is now removed from the html, and the data-bind is modified to use the toggle bindingHandler:
<a class="expandable" href="javascript:void(0)" data-bind="toggle: 'expanded'">Rating
<div>
<div class="rating" style="width: 85%">3.5 Stars Rating</div>
</div>
</a>
<br/>
<a class="expandable" href="javascript:void(0)" data-bind="toggle: 'expanded'">Reviews
<div>
<div class="reviews">Reviews</div>
</div>
</a>
Hopefully this is of some help to you.
I'm not sure this would help you,
I've reconstruct and optimize your code based on what you need.
This might give you some idea. You don't need custom binding handler to implement this.
here the working jsFiddle: http://jsfiddle.net/farizazmi/6E4Wz/2/
so, what do you need is to include property to control visibility of the item:
var data = [
{
'name' : 'test1',
'rateIsExpanded' : ko.observable(false),
'rating': 3.5,
'review': 'blabla1',
'reviewIsExpanded': ko.observable(false)
},
{
'name' : 'test2',
'rateIsExpanded' : ko.observable(false),
'rating': 1.5,
'review': 'blabla2',
'reviewIsExpanded': ko.observable(false)
}
];
and create a function will use to change state of visibility each data:
var Model = function () {
var self = this;
self.data = ko.observableArray(data);
self.expandRate = function(item)
{
console.log(ko.toJSON(item));
item.rateIsExpanded( ! item.rateIsExpanded() );
};
self.expandReview = function(item)
{
item.reviewIsExpanded( ! item.reviewIsExpanded() );
};
};
ko.applyBindings(Model());
You can do this simply by using an observableArray to hold your menu system, with properties for:
itemName - to hold top level menu items
expanded - to control the expansion of a submenu with child items
subMenu - to hold child items
On top of this, you need a simple function to toggle the visibility of each sub-menu when the parent is clicked. Then you can utilise the knockout visible attribute in your data-binding, which would be bound to the expanded property.
Here's a working JSFiddle and below is the code used:
JS view model:
var Model = function () {
var self = this;
self.tabs = ko.observableArray([
{ itemName: "Ratings",
expanded: ko.observable(false),
subMenu: ["option 1","option 2"]},
{ itemName: "Review",
expanded: ko.observable(false),
subMenu: ["option 1","option 2"]}
]);
self.toggleExpanded = function (item) {
item.expanded(!item.expanded());
}
};
ko.applyBindings(Model());
HTML Mark Up:
<ul data-bind="foreach: tabs">
<li><span data-bind="text: itemName, click: toggleExpanded"></span>:
<ul data-bind="foreach: subMenu">
<li data-bind="text: $data, visible: $parent.expanded">
</li>
</ul>
</li>
</ul>