Firefox html5 drag and drop not working - html

I know there are a lot of similar questions on here, but, when putting them to action, I still resolve in the same problem.
I have 2 angular directives (drag and drop) and one angular factory (dndAPI). This is all based off of fisshy's Angular Drag and Drop on github.
I finally got firefox to accept and drag movement by adding data to the event, however I can't seem to keep it from doing it's default behavior (and loading that data as a url). I also apologize I couldn't get it to work at all on jsfiddle...at all. I'll try again if someone can't see if I'm doing something outrageously wrong.
angular.module('dragAndDrop', [])
.directive('drag',function (dndApi) {
var drags = [],
dragging = new RegExp('(\\s|^)dragging(\\s|$)');
return {
restrict: 'A',
scope: {
item: '=drag',
whenStart: '&',
whenEnd: '&',
dropzones: '='
},
link: function (scope, elem, attr, ctrl) {
elem.bind('dragstart', function (e) {
angular.element('query-tool-tip').removeClass('active');
//if ( drags.length === 0 ) {
drags = document.querySelectorAll('.drop');
//}
angular.forEach(drags, function (value, key) {
if (scope.dropzones.indexOf(value.getAttribute('drop')) >= 0) {
value.className = value.className + ' dragging';
}
});
elem.addClass('dragging');
dndApi.setData(scope.item, scope.dropzones);
e.originalEvent.dataTransfer.effectAllowed = 'move';
//KEEPS FIREFOX FROM CRAPPING OUT:
e.originalEvent.dataTransfer.setData( 'text/plain', 'stop' );
scope.$apply(function () {
scope.whenStart({ data: dndApi.getData() });
});
});
elem.bind('dragleave', function(e){});
elem.bind('dragend', function (e) {
elem.removeClass('dragging');
angular.forEach(drags, function (value, key) {
value.className = value.className.replace(dragging, '');
});
scope.$apply(function () {
scope.whenEnd({ data: dndApi.getData() });
});
dndApi.removeData();
e.preventDefault();
});
elem[0].draggable = true;
elem[0].className = elem[0].className + ' drag';
}
};
}).directive('drop',function (dndApi) {
var drags = [],
dragging = new RegExp('(\\s|^)dragging(\\s|$)');
return {
scope: {
drop: '=drop',
whenDrop: '&',
whenEnter: '&',
whenLeave: '&',
queryIndex: "=queryIndex",
hideElem: '='
},
link: function (scope, elem, attr, ctrl) {
var left = elem[0].offsetLeft,
right = left + elem[0].offsetWidth,
top = elem[0].offsetTop,
bottom = top + elem[0].offsetHeight;
elem.bind('drop', function (e) {
// e.originalEvent.preventDefault();
//if (e.stopPropagation()) {
// e.stopPropagation();
//e.originalEvent.stopPropagation();
//e.preventDefault();
//e.originalEvent.preventDefault();
//}
e.originalEvent.dataTransfer.clearData();
if (dndApi.getDropZones().indexOf(scope.drop) >= 0) {
scope.$apply(function () {
scope.whenDrop({ data: dndApi.getData(), queryI: scope.queryIndex });
});
}
if (drags.length === 0) {
drags = document.querySelectorAll('.drop');
}
angular.forEach(drags, function (value, key) {
value.className = value.className.replace(dragging, '');
});
dndApi.removeData();
e.stopPropagation();
e.originalEvent.stopPropagation();
e.preventDefault();
e.originalEvent.preventDefault();
});
elem.bind('dragenter', function (e) {
e.preventDefault();
e.originalEvent.preventDefault();
if (elem[0] == e.target) {
scope.$apply(function () {
scope.whenEnter({ data: dndApi.getData() });
});
}
return false;
});
elem.bind('dragleave', function (e) {
e.preventDefault();
e.originalEvent.preventDefault();
if ((e.x < left || e.x > right) ||
(e.y < top || e.y > bottom)) {
scope.$apply(function () {
scope.whenLeave({ data: dndApi.getData() });
});
}
return false;
});
elem.bind('dragover', function (e) {
//if (e.preventDefault) {
e.preventDefault();
e.originalEvent.preventDefault();
//}
return false;
});
elem[0].className = elem[0].className + ' drop';
scope.$watch('hideElem', function () {
if (scope.hideElem === true) {
elem.hide();
} else {
elem.show();
}
});
}
};
}).factory('dndApi', function () {
var dnd = {
dragObject: {},
dropzones: []
};
return {
setData: function (data, areas) {
dnd.dragObject = data;
dnd.dropzones = areas;
},
removeData: function () {
dnd.dragObject = null;
dnd.dropZones = [];
},
getData: function () {
return dnd.dragObject;
},
getDropZones: function () {
return dnd.dropzones;
}
};
});
I've done a lot of what's recommended on other questions. I've added event.preventDefault() to the dragenter and dragleave spots. And then when that didn't work I added them everywhere. I have a feeling it has to do with my drop method. If i put event.prevendDefault() at the beginning of the binding, the rest of my code isn't executed.
Any advice, even if it's something small that I might've overlooked, will be helpful.
Thanks!

You are calling e.originalEvent.dataTransfer.clearData(); in the drop event handler which will cause an exception to be thrown (you won't have permission to alter the original dataTransfer object). This is preventing e.originalEvent.preventDefault(); from being called.

Related

I want to use ng-contextmenu on my html page for providing different menu items. But my JS class is not getting called.

This is my html class, I have used one example from net for understanding how it's works.
<form>
<div ng-controller="ListController">
<div>
<strong>Gold: </strong>
{{player.gold}}
</div>
<div class="list-group">
<a href="#"
class="list-group-item"
ng-repeat="item in items"
context-menu="menuOptions">
<span class="badge">{{item.cost}}</span>
{{item.name}}
</a>
</div>
</div>
</form>
This is controller :
controller('ListController', ['$scope',
function ($scope) {
$scope.player = {
gold: 100
};
$scope.items = [
{ name: 'Small Health Potion', cost: 4 },
{ name: 'Small Mana Potion', cost: 5 },
{ name: 'Iron Short Sword', cost: 12 }
];
$scope.menuOptions = [
['Buy', function ($itemScope) {
$scope.player.gold -= $itemScope.item.cost;
}],
null,
['Sell', function ($itemScope) {
$scope.player.gold += $itemScope.item.cost;
}]
];
}
]);
This is my JS file, which is being used for contextmenu:
var app = angular.module("contextMenu",[]);
app.directive('contextMenu', function ($parse) {
var renderContextMenu = function ($scope, event, options) {
if (!$) { var $ = angular.element; }
$(event.currentTarget).addClass('context');
var $contextMenu = $('<div>');
$contextMenu.addClass('dropdown clearfix');
var $ul = $('<ul>');
$ul.addClass('dropdown-menu');
$ul.attr({ 'role': 'menu' });
$ul.css({
display: 'block',
position: 'absolute',
left: event.pageX + 'px',
top: event.pageY + 'px'
});
angular.forEach(options, function (item, i) {
var $li = $('<li>');
if (item === null) {
$li.addClass('divider');
} else {
$a = $('<a>');
$a.attr({ tabindex: '-1', href: '#' });
$a.text(typeof item[0] == 'string' ? item[0] : item[0].call($scope, $scope));
$li.append($a);
$li.on('click', function ($event) {
$event.preventDefault();
$scope.$apply(function () {
$(event.currentTarget).removeClass('context');
$contextMenu.remove();
item[1].call($scope, $scope);
});
});
}
$ul.append($li);
});
$contextMenu.append($ul);
var height = Math.max(
document.body.scrollHeight, document.documentElement.scrollHeight,
document.body.offsetHeight, document.documentElement.offsetHeight,
document.body.clientHeight, document.documentElement.clientHeight
);
$contextMenu.css({
width: '100%',
height: height + 'px',
position: 'absolute',
top: 0,
left: 0,
zIndex: 9999
});
$(document).find('body').append($contextMenu);
$contextMenu.on("mousedown", function (e) {
if ($(e.target).hasClass('dropdown')) {
$(event.currentTarget).removeClass('context');
$contextMenu.remove();
}
}).on('contextmenu', function (event) {
$(event.currentTarget).removeClass('context');
event.preventDefault();
$contextMenu.remove();
});
};
return function ($scope, element, attrs) {
element.on('contextmenu', function (event) {
$scope.$apply(function () {
event.preventDefault();
var options = $scope.$eval(attrs.contextMenu);
if (options instanceof Array) {
renderContextMenu($scope, event, options);
} else {
throw '"' + attrs.contextMenu + '" not an array';
}
});
});
};
});
But this code is not working for me. My debug point never comes on contextmenu js file. And I am getting default window menu on right click.
Can anyone please suggest what I am doing wrong or missing in this. It would be a great help.
First you have to create a master app.js file to define your modules something like below. The file needs to be loaded first.
(function () {
var module = angular.module('app', [
'contextMenu',
'menu'
]);
})();
Now the file which holds controller needs to be something like below.
(function () {
var module = angular.module('menu');
module.controller('ListController', [
'$scope'
function ($scope) {
//Your controller code goes here
}]);
})();
Your html needs to be something like below.
<body ng-app="app">
//Your html goes here
</body>
Your js files needs to be added in below order.
Angularjs
app.js
menu.js
That's all i can say for now.

Jquery UI autcomplete with Json data source

I am using jquery UI autocomple with json data source but it's not working but when I used same with fixed data it works. Below is my code.
$(document).ready(function () {
var codes = "";
Admin_BasicFeeSchedule.LoadCPTCodes().done(function (response) {
if (response.status != false) {
if (response.CPTCodeCount > 0) {
var CPTCodeLoadJSONData = JSON.parse(response.CPTCodeLoad_JSON);
$.each(CPTCodeLoadJSONData, function (i, item) {
codes = codes + "'" + item.ShortName + "'";
});
//codes = codes + "]";
alert(codes);
}
}
else {
utility.DisplayMessages(response.Message, 3);
}
});
$.widget("ui.autocomplete", $.ui.autocomplete, {
_renderMenu: function (ul, items) {
var that = this;
$.each(items, function (index, item) {
that._renderItemData(ul, item);
});
$(ul).wrap("<div></div>");
},
});
$("input#ddlCPTCode").autocomplete({
source: [codes],//['Tom', 'Alex', 'Patrick'],
});
});
Based on jQueryUI's API, the source option can either be an array or a String that points to an URL or a Function. Furthermore, your code needs to change few things so that the array is handled in appropriate fashion:
$(document).ready(function () {
var codes = []; // array is created
Admin_BasicFeeSchedule.LoadCPTCodes().done(function (response) {
//alert("LoadCPTCodes works") ;
if (response.status != false) {
//alert("response.status true") ;
if (response.CPTCodeCount > 0) {
//alert("CPTCodeCount > 0") ;
var CPTCodeLoadJSONData = JSON.parse(response.CPTCodeLoad_JSON);
$.each(CPTCodeLoadJSONData, function (i, item) {
codes.push(item.ShortName); //add item to an array
});
//codes = codes + "]";
alert(codes);
}
}
else {
utility.DisplayMessages(response.Message, 3);
}
});
$.widget("ui.autocomplete", $.ui.autocomplete, {
_renderMenu: function (ul, items) {
var that = this;
$.each(items, function (index, item) {
that._renderItemData(ul, item);
});
$(ul).wrap("<div></div>");
},
});
$("input#ddlCPTCode").autocomplete({
source: codes // pass an array (without a comma)
});
});
Finally, if those changes related to the array aren't enough to make it work, then I would check the JSON load part. I have added some alert calls that can be uncommented for JSON testing purposes. As I am not familiar with the details of the JSON load functionality that is used in the sample code, then I'm just going to mention that there are alternative ways of loading JSON data such as jQuery's getJSON method.

jquery sidebar putting next to each other

I have put together a sidebar with hover-delay animation, but I can't seem to exactly copy the column to place next to the first. This is my first problem.
The second is that I would like to use the jspanel plugin, so that a dragable window will pop up when I click on a sub-item in the sidebar.
I hope this can be brought to a working state.
Thank you very much for responses in advance!
Here's [a link] (http://jsfiddle.net/chrisoutwright/tc4d9t6d/)!
$('#categories').corner("top keep");
$(document).ready(function(){
$("#foo").click(function(){
$().jsPanel().show();
});
});
$( "#navigation ul.sub-level" ).corner("").css( "border", "3px double blue" );
jQuery.fn.hoverWithDelay = function(inCallback,outCallback,delay) {
this.each(function() {
var timer, $this = this;
$(this).hover(function(){
timer = setTimeout(function(){
timer = null;
inCallback.call($this);
}, delay);
},function() {
if (timer) {
clearTimeout(timer);
timer = null;
} else
outCallback.call($this);
});
});
};
var hovering = {mainMenu: false, categories: false};
function closeSubMenus() {
$('ul.sub-level').css('display', 'none');
}
closeSubMenus();
function closeMenuIfOut() {
setTimeout(function(){
if (!hovering.mainMenu && !hovering.categories) {
$('#navigation').fadeOut('fast',closeSubMenus);
}
},100);
}
$('ul.top-level li').hoverWithDelay(function() {
$(this).find('ul').show();
}, function() {
$(this).find('ul').fadeOut('fast', closeMenuIfOut);
}, 500);
$('#categories').hoverWithDelay(function() {
$('#navigation').show();
hovering.categories = true;
},
function(){
hovering.categories = false;
closeMenuIfOut();
},500);
$('#navigation').hover(function() {
hovering.mainMenu = true;
}, function() {
hovering.mainMenu = false;
});
I can see at least one error in line 4 where you try to generate/open the jsPanel.
Which jsPanel version do you use? Version 1.x or Version 2.x? The two versions differ on how to use the jsPanel() command.
version 1.x: $( selector ).jsPanel( config );
version 2.x: $.jsPanel( config );
Do you get any error messages?

Update JSON with refreshInterval

I want to update every 10 seconds json data.
With this function crashes the script.
Is there a better way?
$(function refreshUsers() {
$.getJSON('/api/TrainlocationList/', function (loadscale) {
$(loadscale).each(function (i, item) {
$(item).each(function (i, Type) {
$('#LabelID').html(Type.TrainLocationName);
var refreshInterval = setInterval(refreshUsers, 10 * 1000);
});
});
});
});
Try this...
setInterval(function() {
$.getJSON('/api/TrainlocationList/', function (loadscale) {
$(loadscale).each(function (i, item) {
$(item).each(function (i, Type) {
$('#LabelID').html(Type.TrainLocationName);
});
});
});
}, 10000)

jquery toggle function and set a cookie

I have the following function which toggles mouseenter and mouseleave on click:
var flag = true;
$('.aaa').mouseenter(function () {
if(flag) {
$(this).css('background', '#aaaaaa');
}
$(this).css('border', 'solid 1px red');
});
$('.aaa').mouseleave(function () {
if(flag) {
$(this).css('background','blue');
}
$(this).css('border', 'solid transparent 1px');
});
$('#tog').click(function () {
flag = !flag;
});
http://jsfiddle.net/z8KuE/15/
How can chosen preference be "remembered" and loaded on the next page load?
edit: in case that the solution from bellow doesn't work on the site for some reason, just put it here:
(function($){
$(document).ready(function(){
//Scripts go in here!
});
})(jQuery);
I would use the jQuery cookie plugin:
var storedFlag = $.cookie('userSelection'); // read cookie
var flag = 1; //default value
if(storedFlag != undefined){ // some flag was stored
flag = storedFlag;
}
$('.aaa').mouseenter(function () {
if(flag > 0) {
$(this).css('background', '#aaaaaa');
}
$(this).css('border', 'solid 1px red');
});
$('.aaa').mouseleave(function () {
if(flag > 0) {
$(this).css('background','blue');
}
$(this).css('border', 'solid transparent 1px');
});
$('#tog').click(function () {
flag = 1 - flag;
$.cookie('userSelection', flag, { expires: 30 }); // store cookie
});
The problem is that the boolean values are stored as strings, and the string 'false' is a true value, thus i resorted to using numbers and >0 comparison.
See updated fiddle