I'm trying to make an application where the user will be able to click and drag inside an area to create rectangles. The catch is that the area is a Marionette.CollectionView and the user by dragging and releasing the mouse button is creating a new Rectangle model, that gets added to the collection (which takes care of rendering it).
Here's the itemView's code
var RectangleView = Backbone.Marionette.ItemView.extend({
template: "<div> </div>",
className: "rectangle",
events: {},
initialize: function(){
this.$el.draggable({
containment: 'parent'
});
this.$el.resizable();
this.setCssStyle();
},
setCssStyle: function (options) {
that = this;
this.$el.css({
'width': that.options.width + 'px',
'height': that.options.height + 'px',
'top': that.options.top + 'px',
'left': that.options.left + 'px',
'border': '1px solid black',
'position': 'absolute'
});
}
});
Within the initialize method I set the view's element to be draggable and resizable. While draggable works fine, resizable doesn't work at all. (I am also including the necessary jquery-ui.css file)
The above ItemView gets appended as soon as I add the model to the CollectionView (which happens on a custom event of my CollectionView) here's the code for the CollectionView
var ScreenView = Backbone.Marionette.CollectionView.extend({
template: "<div> </div>",
className:"screen",
itemView: RectangleView,
events: {
'boxmakerstoppeddrawing' : 'drawingHandler'
},
initialize: function() {
this.$el.boxMaker();
},
itemViewOptions: function() {
return boxProperties;
},
drawingHandler: function() {
var rectangle = new Rectangle();
this.collection.add(rectangle);
}
});
Any ideas of what I could be doing wrong, causing the .resizable not to work?
Silly me!
As i was told by user seutje in the #jquery irc.freenode channel, I should attach the jquery-ui methods onRender instead of initialization
initialize: function(){
this.setCssStyle();
},
onRender: function(){
this.$el.draggable({
containment: 'parent'
});
this.$el.resizable();
}
Everything works now, but I would like feedback whether this is optimal.
Considering that I'm attaching methods onRender, during resize the ItemView gets re-rendered, therefore while onRender gets called whenever I resize the item and as a result re-attaches .draggable and .resizable?
Related
I have an ajax transition which is this:
function fadeTransition(href = window.location.href) {
$('.fader').css({
'position': 'fixed',
// 'height': h,
'height': '100vh',
'width': '0',
'left': '0',
'top': '0',
'color': 'black',
'background-color': 'black',
'z-index': '300'
}).animate({
'width': '100vw',
}, 400, function() {
$('.slider-transition').load(href + ' .slider-transition', function() {
// EXECUTES ON CALLBACK
// $('.slider-transition').children('.slider-transition').unwrap();
// h = $(document).height();
$('.fader').animate({
'left': '100vw'
}, 400, function() {
slideShowInit();
initParalax();
$('.woocommerce-product-gallery').each(function() {
$(this).wc_product_gallery();
});
$('.slider-transition').children('.slider-transition').unwrap();
// $('.slider-transition').parents('.slider-transition').unwrap();
});
});
});
}
It's a simple transition that loads the element from the next page into the element of the current page and by attaching all of the click events to the body as such:
$('body').on('click', '.main-menu li a, nav a, a.button, a.square, a.grow', function(event) {
event.preventDefault();
event.stopPropagation();
});
$("li").on("click", "a", function(event) {
var _href = $(this).attr("href");
history.pushState(null, null, _href);
fadeTransition(_href);
});
I've been able to circumnavigate the problem of click events being destroyed after the transition. The only problem that with the Woocommerce plugin in Wordpress, I can't possibly hope to traverse the entire assets folder of JS and replace
$('.a').on('click', function() {});
with
$('.body').on('click', 'a', function() {});
and attach all of the DOM events to the body like this and even then I'm only 70% sure this is the problem, does anyone know a way around this?
Remove an event handler with jQuery using off()
With jQuery to stop/remove existing "click" delegated event that interfere with your own custom click event, you could try to use off(), which is likely the contrary of on().
So with your code it should be:
jQuery(function($){
$(document.body).off('click', 'a');
$("li").on("click", "a", function(event) {
var _href = $(this).attr("href");
history.pushState(null, null, _href);
fadeTransition(_href);
});
});
It could solve your issue.
I am working on some kind of game that I can drag elements and on drag they have to move
left (plus or minus) depending on the drag direction.
I've tried like million ways of doing that.
The normal 'revert:true' is not working properly with horizontal elements, as the element
is reverted in a wrong position.
Finally, I worked it around with the animate() function in Jquery, And it really works
fine but it only drags the elements up and down, But left and right directions are not
working.
Here's my js script for doing that :
function setAllMatchesDraggable(){
$('.matches').not('.answer').draggable({
// Can't use revert, as we animate the original object
//revert: true,
helper: function(){
// Create an invisible div as the helper. It will move and
// follow the cursor as usual.
return $('<div></div>').css('opacity',0);
},
create: function(){
// When the draggable is created, save its starting
// position into a data attribute, so we know where we
// need to revert to.
var $this = $(this);
if(($this).hasClass("flip_left") || ($this).hasClass("flip_right"))
{
$this.data('top',$this.position().top - 29);
$this.data('left',$this.position().left);
}else{
$this.data('top',$this.position().top);
$this.data('left',$this.position().left);
}
},
stop: function(){
// When dragging stops, revert the draggable to its
// original starting position.
var $this = $(this);
$this.stop().animate({
"top": $this.data('top')
},200,'easeOutElastic',function(){
$(this).stop().animate({"left":$this.data('left')},200,'easeOutElastic');
});
},
drag: function(event, ui){
// During dragging, animate the original object to
// follow the invisible helper with custom easing.
$(this).stop().animate({
"top": ui.helper.position().top
},200,'easeOutElastic',function(){
$(this).stop().animate({"left":ui.helper.position().left},200,'easeOutElastic',function(){
console.log(ui.helper.position().left);
});
});
}
});
}
I wish You could help. Thanks in advance :)
Use top and left in same function
$this.stop().animate({
"top": $this.data('top'),
"left" : $this.data('left')
},200,'easeOutElastic') ;
Give this a try:
...
create: function(){
var $this = $(this);
$this.data({
'top': $this.position().top,
'left': $this.position().left
});
},
stop: function(){
var $this = $(this);
$this.stop().animate({
top: $this.data('top'),
left: $this.data('left')
},200,'easeOutElastic');
},
drag: function(event, ui){
$(this).stop().animate({
top: ui.helper.position().top,
left: ui.helper.position().left
},0,'easeOutElastic');
}
...
So I'm putting something together for work, I've got it working exactly how I want it to, except for one tiny thing. At the bottom of the page, I have 3 circles that work as links to change the slides on my slider, however when I click one it doesn't quite change the css property to change the color of the circle I click on. This might not make sense so I'm going to link my fiddle(http://jsfiddle.net/AMN6N/1/) I think it has something specifically to do with this line of code:
handleNavClick: function(event, el)
{
event.preventDefault();
var position = $(el).attr("href").split("-").pop();
this.el.slider.animate(
{
scrollLeft: position * this.slideWidth
},
this.timing);
this.changeActiveNav(el);
},
changeActiveNav: function(el)
{
this.el.allNavButtons.removeClass("active");
$(el).addClass("active");
}
};
slider.init();
Here is the temporary link for the webpage.
You will need to load just one SimplySliderTest.js file.
The elements are loading after the javascript is being executed so nothing is binding to them.
You have two options:
Load the JS inside SimplySliderTest.js when the page has loaded. i.e.
$(function(){
var slider =
{
el:
{
slider: $("#slider"),
allSlides: $(".slide"),
sliderNav: $(".slider-nav"),
allNavButtons: $(".slider-nav > a")
},
timing: 800,
slideWidth: 300,
init: function()
{
this.bindUIEvents();
},
bindUIEvents: function()
{
this.el.slider.on("scroll", function(event)
{
slider.moveSlidePosition(event);
});
this.el.sliderNav.on("click", "a", function(event)
{
slider.handleNavClick(event, this);
});
},
moveSlidePosition: function(event)
{
this.el.allSlides.css(
{
"background-position": $(event.target).scrollLeft()/6-100+ "px 0"
});
},
handleNavClick: function(event, el)
{
event.preventDefault();
var position = $(el).attr("href").split("-").pop();
this.el.slider.animate(
{
scrollLeft: position * this.slideWidth
},
this.timing);
this.changeActiveNav(el);
},
changeActiveNav: function(el)
{
this.el.allNavButtons.removeClass("active");
$(el).addClass("active");
}
};
slider.init();
});
Move you <script type="text/javascript" src="SimplySliderTest.js"></script> to the bottom of your page so it loads after the elements
I have a list of draggable objects and a droppable target. The view housing the droppable target gets created and rendered when dragging starts. I've attached some images highlighting the desired action to the bottom of the post.
The issue is that jQuery UI appears to have a bug. This post: Droppable items not displaying hoverClass if they are shown during drag operation seems to corroborate that belief.
I have this code which enables draggable-ness:
this.$el.find('.videoSearchResultItem ').draggable({
helper: function() {
var helper = $('<span>', {
text: VideoSearchResultItems.selected().length
});
return helper;
},
appendTo: 'body',
containment: 'DOM',
zIndex: 1500,
cursorAt: {
right: 20,
bottom: 30
},
start: function (event, ui) {
var draggedVideoId = $(this).data('videoid');
var draggedVideo = VideoSearchResultItems.get(draggedVideoId);
draggedVideo.set('selected', true);
$(ui.helper).addClass("ui-draggable-helper");
}
});
My program has an event listener for a video search result becoming selected. When one becomes selected, the 'AddItems' view renders itself and transitions in.
this.listenTo(VideoSearchResultItems, 'change:selected', function (changedItem, selected) {
if (selected && this.addItemsView === null) {
this.addItemsView = new AddItemsView();
this.$el.append(this.addItemsView.render().el);
this.addItemsView.show();
}
});
AddItemsView initializes droppable during render:
this.$el.find('i.droppable').droppable({
hoverClass: 'icon-drop-hover',
tolerance: 'pointer'
});
Unfortunately, if my draggable is already dragging when the view is rendered -- hoverClass fails as well as the 'over' event.'
I'm wondering if there's any workaround for this? I don't see one.
The solution to this was to set the draggable element's "refreshPositions" option to true. This causes it to inform the droppable even if the droppable is created late.
I am new to mootools. I have joomla site with MooSlider:
var MooSlider = new Class({
initialize: function(options) {
this.options = Object.extend({
container: null,
slides: null,
navs:null,
transition: Fx.Transitions.Sine.easeOut,
effectDuration: 500,
fromTop: 500,
topDist: 100,
slideDelay: 5000
}, options || {});
if(!$(this.options.container)) return;
this.start();
},
start: function(){
this.elements = $(this.options.container).getElements(this.options.slides);
this.navs = $(this.options.container).getElements(this.options.navs);
this.currentElement = 0;
this.elements.each(function(elem, i){
var nav = this.navs[i];
if(i==this.currentElement){
nav.addClass('selected');
}
elem.setStyles({
'position':'absolute',
'top':0,
'left':0,
'opacity':( i==this.currentElement ? 1 : 0 )
});
this.elements[i]['fx'] = new Fx.Styles(elem, {
duration:this.options.effectDuration,
wait:false,
transition:this.options.transition
});
this.elements[i]['nav'] = nav;
elem.addEvents({
'mouseenter': function(){
$clear(this.period);
}.bind(this),
'mouseleave': function(){
if( this.options.slideDelay )
this.period = this.rotate.periodical(this.options.slideDelay, this);
}.bind(this)
});
nav.addEvent('click', function(event){
if(this.currentElement==i) return;
new Event(event).stop();
$clear(this.period);
this.changeSlide(i);
if( this.options.slideDelay )
this.period = this.rotate.periodical(this.options.slideDelay, this);
}.bind(this));
}.bind(this));
if( this.options.slideDelay )
this.period = this.rotate.periodical(this.options.slideDelay, this);
},
rotate: function(){
var i = this.currentElement+1 < this.elements.length ? this.currentElement+1 : 0;
this.changeSlide(i);
},
changeSlide: function(i){
//$(this.options.navigationContainer).addClass('preload');
var cEl = this.currentElement;
this.elements[this.currentElement]['fx'].start({'opacity':0, 'left':1500});
this.elements[i]['fx'].set({'left':0});
this.elements[i]['fx'].start({'opacity':1, 'top':[500,0]}).chain(function(){
//$(this.options.navigationContainer).removeClass('preload');
}.bind(this));
this.elements[this.currentElement]['nav'].removeClass('selected');
this.elements[i]['nav'].addClass('selected');
this.currentElement = i;
}})
This is how it used on page:
<script language="javascript" type="text/javascript">
window.addEvent('domready', function(){
new MooSlider({
container:'topslider',
slides:'.slide',
navs:'.navigator ul li',
effectDuration: 1000,
fromTop:500,
topDist:500,
slideDelay: 3000 });
})
The page url is http://www.miltonwebsitedesign.ca
You can see slider on top of the page. Each slide consists of picture at the left and description at the right.
What I need is to make slides work the same way, but the left side picture must not appear current way, it needs to fade in, when the slide is loaded, not appear, but fade in.
Description text slides and then at the left picture appears.
The structure of each slide is:
<div class='slide'>
<div class="yjsquare">
<div class="yjsquare_in">
<img src='src here' alt=''/><h1>H1 text here</h1><p>description here</p>
</div>
</div>
</div>
Will be happy to hear solution. Thanks.
this class is not well written as in, it does not allow for events like onStart and onComplete to be passed. the logical approach would be to modify the changeSlide method to fire some events:
// add
var el = this.elements[i]['fx'];
this.fireEvent("start", el);
// use el as reference...
el.start({'opacity':1, 'top':[500,0]}).chain(function(){
//$(this.options.navigationContainer).removeClass('preload');
// add
this.fireEvent("complete", el);
}.bind(this));
Make sure that your class also implements Events (which in 1.12 is done like so, if memory serves):
MooSlider.implement(new Events);
you are using a mix of 1.12 and 1.2+ code which is odd. In any case, if you do have 1.2 (joomla usually is not prior to 1.6) then instead add this into the class declaration:
Implements: [Events],
this allows you to add some callback logic upon instigating the class:
new MooSlider({
container:'topslider',
slides:'.slide',
navs:'.navigator ul li',
effectDuration: 1000,
fromTop:500,
topDist:500,
slideDelay: 3000,
onStart: function(el) {
el.getElement("img").setOpacity(0); // hide it during animation
},
onComplete: function(el) {
el.fade(1); // fade it in when done
}
});
you should really implement Options too and use this.setOptions(options) instead of your current $extend.
p.s. the onStart and onComplete code callbacks are examples, you may need to tweak this to suit your html and UI preferences.