I'm using simple HTML code to work on a drag and drop function as part of my IOS app. This piece of code works perfectly in the browser however when I copy it into my xcode file the image won't drag.
<!DOCTYPE HTML>
<html>
<head>
<style type="text/css">
#div1 {width:350px;height:70px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev)
{
ev.preventDefault();
}
function drag(ev)
{
ev.dataTransfer.setData("Text",ev.target.id);
}
function drop(ev)
{
ev.preventDefault();
var data=ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
<p>Drag the image into the rectangle:</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img id="drag1" src="images/face.png" draggable="true" ondragstart="drag(event)" width="336" height="69">
</body>
</html>
Reading over Apple's webview capabilities document states that you have to set a CSS property for this to work.
From the docs:
Making an Element Draggable
WebKit provides automatic support to let users drag common items, such as images, links
and selected text. You can extend this support to include specific elements on an HTML
page. For example, you could mark a particular div or span tag as draggable.
To mark an arbitrary element as draggable, add the -webkit-user-drag attribute
(previously -khtml-user-drag) to the style definition of the element. Because it is a
cascading style sheet (CSS) attribute, you can include it as part of a style definition
or as an inline style attribute on the element tag. The values for this attribute are
listed in Table 1.
So standard draggables will work out of the box, but other elements like div or span require the -webkit-user-drag attribute to be appended.
Example:
#drag1 { -webkit-user-drag: element; }
Source: https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/DragAndDrop.html
This code is what worked in the end.
<script>
var nodeList = document.getElementsByClassName('contents');
for(var i=0;i<nodeList.length;i++) {
var obj = nodeList[i];
obj.addEventListener('touchmove', function(event) {
var touch = event.targetTouches[0];
// Place element where the finger is
event.target.style.left = touch.pageX + 'px';
event.target.style.top = touch.pageY + 'px';
event.preventDefault();
});
}
</script>
Related
I am implementing a drawing app on my site and trying to prevent overscroll while the user draws on the canvas. Despite trying several reported solutions, I cannot disable Chrome's pull-to-refresh.
According to https://developers.google.com/web/updates/2017/11/overscroll-behavior, the following one line of css should do the trick..yet pull-to-refresh and an annoying user experience persists. Any ideas?
<!DOCTYPE html>
<html>
<style type="text/css">
body {
/* Disables pull-to-refresh but allows overscroll glow effects. */
overscroll-behavior-y: contain;
}
</style>
<body>
<h1>Simple Site</h1>
</body>
<script type="text/javascript">
</script>
</html>
I had the same problem. I found that CSS property only works on chrome-android.
Finally, I successfully prevent pull-to-refresh on chrome-ios through the following:
<script>
function preventPullToRefresh(element) {
var prevent = false;
document.querySelector(element).addEventListener('touchstart', function(e){
if (e.touches.length !== 1) { return; }
var scrollY = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
prevent = (scrollY === 0);
});
document.querySelector(element).addEventListener('touchmove', function(e){
if (prevent) {
prevent = false;
e.preventDefault();
}
});
}
preventPullToRefresh('#id') // pass #id or html tag into the method
</script>
For newer version of Chrome v75.0.3770.103 on IOS
preventDefault()
does no longer disable pull-to-refresh.
Instead, you can add in
{passive:false}
as additional option into the event listener.
E.g.
window.addEventListener("touchstart", eventListener, {passive:false});
In newer version of chrome in IOS preventDefault(); is no longer disables pull to refresh.
For latest, you can just add inobounce js cdn to your header of the page you want to disable pull to refresh. This will do the magic.
<script src="https://cdnjs.cloudflare.com/ajax/libs/inobounce/0.2.0/inobounce.js"></script>
The only thing that worked for me was iNoBounce.
Example React snippet:
import 'inobounce'
...
<div style={{
height: windowHeight,
WebkitOverflowScrolling: 'touch',
overflowY: 'auto' }}
>Content goes here</div>
I do not understand, why eventlistener (copied from demo) does not work, If I add an bitmap to stage. It seems that bitmap causes problem, because if I add another circle etc. the click works fine.
See example:
<!DOCTYPE html>
<html>
<head>
<title>EaselJS demo: Simple animation</title>
<link href="../_shared/demo.css" rel="stylesheet" type="text/css">
<script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
<script>
var stage, circle;
var counter = 0;
var ticounter = 0
var images = []
var mytext = 'kk';
var lepakko;
var mx = 0;
function init() {
stage = new createjs.Stage("demoCanvas");
var circle = new createjs.Shape();
circle.graphics.beginFill("red").drawCircle(0, 0, 50);
circle.x = 500;
circle.y = 500;
stage.addChild(circle);
stage.update();
lepakko = new createjs.Bitmap("halloween-bat.png");
//Click works, if line below is commented out, why?
//stage.addChild(lepakko);
circle.addEventListener("click",circle_event);
stage.update();
}
function circle_event(event) {
alert("clicked");
};
</script>
</head>
<body onLoad="init();">
<canvas id="demoCanvas" width="700" height="700">
alternate content
</canvas>
</body>
</html>
The click should not work by default. EaselJS library needs explicit enabling of the mouseover event. You need to add:
stage.enableMouseOver(20);
after creating the stage. To change the cursor to a pointer when it's over the object there is a property in EaselJS called cursor:
// doesn't work, even if a function is decleared outside
// circle.addEventListener("mouseover", function() { document.body.style.cursor = "pointer"; });
// this works
circle.cursor = "pointer";
Method enableMouseOver is documented on EaselJS website. Do note that listening to mouseover and other events in EaselJS is a lot more demanding for a web browser.
I am using iScroll on my mobile enable website (using iPhone here) to scroll inside a div.
In this this div, I have an iframe with a fixed height like this:
<body>
<div id="iscroller">
<iframe id="theIframe"></iframe>
Other stuff
</div>
</body>
Now, while scrolling within the div, everything works as expected but I cannot scroll when the scrolling gesture begins on the iframe.
The problem is described here pretty well: https://github.com/cubiq/iscroll/issues/41
So, I used the css workaround from that post by applying pointer-events:none to the iframe.
Now scrolling works perfectly but I cannot click any links which are defined within the iframe because all click/touch events on the iframe seems to be blocked due to pointer-events: none.
So, I thought:
"Ok, while the user scrolls, I need pointer-events:none. If he is
not scrolling (and instead clicking), I must set pointer-events:auto
in order to let the click/touch events pass."
So I did this:
CSS
#theIframe{pointer-events:none}
JavaScript
$("#theIframe").bind("touchstart", function(){
// Enable click before click is triggered
$(this).css("pointer-events", "auto");
});
$("#theIframe").bind("touchmove", function(){
// Disable click/touch events while scrolling
$(this).css("pointer-events", "none");
});
Even adding this doesn't work:
$("#theIframe").bind("touchend", function(){
// Re-enable click/touch events after releasing
$(this).css("pointer-events", "auto");
});
No matter what I do: Either scrolling doesn't work or clicking the link inside the iframe doesn't work.
Doesn't work. Any ideas?
I found the perfect solution. Works great on iOS and Android.
The basic idea is to put a div layer on top of that iframe. This way scrolling works smoothly.
If the user wants to tap/click on an element on that iframe I simply catch that click on the layer, save the x and y coordinates and trigger a click event on the iframe's content at these coordinates:
HTML:
<div id="wrapper">
<div id="layer"></div>
<iframe id="theIframe"></iframe>
</div>
Other stuff
CSS:
#layer{
position:absolute;
opacity:0;
width:100%;
height:100%;
top:0;
left:0;
right:0;
bottom:0;
z-index:2
}
JavaScript:
$('#layer').click(function(event){
var iframe = $('#theIframe').get(0);
var iframeDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
// Find click position (coordinates)
var x = event.offsetX;
var y = event.offsetY;
// Trigger click inside iframe
var link = iframeDoc.elementFromPoint(x, y);
var newEvent = iframeDoc.createEvent('HTMLEvents');
newEvent.initEvent('click', true, true);
link.dispatchEvent(newEvent);
});
I found a solution for this, it happens to be close to what other guys already mentioned on github but this may be useful for whoever wants to find a fast working resolution for this problem.
I'm assuming a few things, like there's only one iscroll container, here represented as ID. This is not properly tested and needs refactor. It's working in my project, but I changed it here slightly for the example but I guess you'll easily understand what you need to do:
var $iscroll = $('#iscroll');
document.addEventListener('touchstart', function(e) {
if ($iscroll.find('iframe').length > 0){
$.each($iscroll.find('iframe'), function(k,v){
var $parent = $(v).parent().first();
if ($parent.find('.preventTouch').length == 0){
$('<div class="preventTouch" style="position:absolute; z-index:2; width:100%; height:100%;"></div>')
.prependTo($parent);
};
$parent
.css('position', 'relative').css('z-index', 1);
});
$iscroll.find('.preventTouch').on('click', function(e){
e.preventDefault();
e.stopPropagation();
return false;
});
};
};
document.addEventListener('touchend', function(e) {
if ($iscroll.find('iframe').length > 0){
setTimeout(function(){
var $iscroll = $('#iscroll');
$iscroll.find('.preventTouch').remove();
$iscroll.find('iframe').css('z-index', '');
$iscroll.find('.preventTouch').off('click');
}, 400);
};
};
Thanks for looking!
I'm developing an extension for FireFox. I use a XUL deck element that contains a XUL browser element. Unfortunately, whenever the page displayed in the browser has an HTML title attribute, the value of this title attribute will not show up as a tooltip.
How can I get tooltips to display correctly?
There is no mechanism to automatically display title attributes in tooltips - the browser window has special code for that and you need to replicate this code in your extension. This means that you need to define a <tooltip> element, e.g.:
<popupset>
<tooltip id="browserTooltip" onpopupshowing="return fillTooltip(this);"/>
</popupset>
You should use this tooltip in your <browser> element, like this:
<browser tooltip="browserTooltip"/>
And you should create a fillTooltip() function that will be called whenever your tooltip shows up. It will need to look at the HTML element that the mouse pointer hovers over, check its title attribute and put the value of the attribute into the tooltip. The function performing this job in Firefox is FillInHTMLTooltip() though you might want to go with a simpler variant like this (untested code):
function fillTooltip(tooltip)
{
// Walk up the DOM hierarchy until we find something with a title attribute
var node = document.tooltipNode;
while (node && !node.hasAttribute("title"))
node = node.parentNode;
// Don't show tooltip if we didn't find anything
if (!node)
return false;
// Fill in tooltip text and show it
tooltip.setAttribute("label", node.getAttribute("title"));
return true;
}
I found the solution for those who are interested, it's by adding a tooltip property to the XUL browser element with the following value:
tooltip="aHTMLTooltip"
Or adding it programmatically using javascript like this:
browser.setAttribute('tooltip','aHTMLTooltip');
for more details check: https://bugzilla.mozilla.org/show_bug.cgi?id=451792#c1
Working example:
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="mainWindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" title="NanoFL" width="800" height="600" persist="screenX screenY width height sizemode">
<script>
<![CDATA[
function fillTooltip(tooltip)
{
var nodes = document.getElementById("browser").contentWindow.document.querySelectorAll(":hover");
for (var i=nodes.length-1; i>=0; i--)
{
if (nodes[i].hasAttribute("title"))
{
tooltip.setAttribute("label", nodes[i].getAttribute("title"));
return true;
}
}
return false;
}
]]>
</script>
<browser id="browser" src="chrome://nanofl/content/index.html" flex="1" disablehistory="true" tooltip="browserTooltip" />
<tooltip id="browserTooltip" onpopupshowing="return fillTooltip(this)"/>
</window>
In one panel I have the called resource,like a yellow square
I want drag the element to the another panel,and copy one,but the original one still there,
the markup is simple:
<div id="panel">
<div id="square" class="square"></div> //the resource
</div>
<div id="canvas">
</div>
the drag js code:
$('#panel .square').draggable({
appendTo: "#canvas",
helper: "clone"
});
$('#canvas').droppable({
drop: function (e, ui) {
var $temp_id = $(ui.draggable).attr('id');
var $new_id = $temp_id + "_01";
$(ui.draggable).clone()
.css({ 'top': ui.offset.top, 'left': ui.offset.left })
.appendTo($(this))
.attr('id', $new_id);
$('#'+$new_id+'').draggable();
}
});
I want only the resource element could copy itself,but the copy one in the canvas could copy themself,too!Inherit the copy ablity!
Thank you
here is example
What I have done ?Why this could happened?How can I cancel this?
Just add this to your drop event.
ui.draggable.remove();
That would remove the original element.
also to prevent the duplication of your items, consider adding this to your draggable.
accept: function(d) {
return $(this).find(d).length == 0
}
What it does is; it checks your container for the prescence of object d, if that object is present, the code would return false therefore preventing the drop of the object which causes the duplication.
Hope this helps.