Detecting a single tap in a UIWebView while maintaining support for text selection and links

Currently, I am utilizing JavaScript to recognize taps within a page displayed in a UIWebView. Here is an example of my code:

<div id="wrapper">
  <a href="http://apple.com">Apple</a>
</div>
<script>
  document.getElementById("wrapper").addEventListener('click', function() {
      document.location = 'internal://tap';
  }, false);
</script>

My approach involves intercepting links using the web view delegate and searching for "internal://tap". Once found, I prevent navigation within the web view and handle the tap accordingly. However, this method causes the loss of text selection capability. Despite this issue, tapping the link itself continues to function as expected.

Interestingly, simply adding an event listener for 'click' results in the inability to select text, even if the handler does not manipulate the document location.

Do you have any insights on what mistakes I might be making?

Answer №1

It seems that adding a click listener to an element prevents text selection within that element on iOS. To work around this issue, I created a solution using touchstart, touchmove, and touchend events, along with a timer to handle multi-taps and checking the document selection to ensure no ongoing selection event.

Below is the JavaScript code implementation:

SingleTapDetector = function(element, handler) {
    this.element = element;
    this.handler = handler;

    element.addEventListener('touchstart', this, false);
};

SingleTapDetector.prototype.handleEvent = function(event) {
    switch (event.type) {
        case 'touchstart': this.onTouchStart(event); break;
        case 'touchmove': this.onTouchMove(event); break;
        case 'touchend': this.onTouchEnd(event); break;
    }
};

SingleTapDetector.prototype.onTouchStart = function(event) {
    this.element.addEventListener('touchend', this, false);
    document.body.addEventListener('touchmove', this, false);

    this.startX = this.currentX = event.touches[0].clientX;
    this.startY = this.currentY = event.touches[0].clientY;
    this.startTime = new Date().getTime();
};

SingleTapDetector.prototype.onTouchMove = function(event) {
    this.currentX = event.touches[0].clientX;
    this.currentY = event.touches[0].clientY;
};

SingleTapDetector.prototype.onTouchEnd = function(event) {
    var that = this;

    // Check for previous taps in this sequence
    if (this.tapTimer) {
        clearTimeout(this.tapTimer);
        this.tapTimer = setTimeout(function() {
            that.tapTimer = null;
        }, 300);
    } else {
        if (Math.abs(this.currentX - this.startX) < 4 &&
            Math.abs(this.currentY - this.startY) < 4) {
            if (new Date().getTime() - this.startTime <= 300) {
                if (window.getSelection() + '' == '') {                    
                    this.tapTimer = setTimeout(function() {
                        that.tapTimer = null;

                        that.handler(event);
                    }, 300);
                }
            }
        }
    }
};

new SingleTapDetector(document.body, function(event) {
    document.location = "internal://tap";
});

Answer №2

Avoid using Javascript in this scenario as it is unnecessary. The UIGestureRecognizerDelegate already provides suitable methods to handle the task efficiently. Simply ensure that text selection does not trigger the tap recognizer.

- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    BOOL hasTap = ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] ||
               [otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]);
    BOOL hasLongTouch = ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] ||
                     [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]);
    if (hasTap && hasLongTouch) {
        // user is selecting text
        return NO;
    }
    return YES;
}

This approach addresses text selection effectively, and ensures that links function correctly without any issues.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to link table A's ID to table B's userID in a postgreSQL database?

Is it possible in PostgreSQL to establish a relational index between table A ID and table B userId for the purpose of joining two tables based on their ids? To provide further clarification, here is an example using MongoDB and Mongoose: const Billing = ...

Enhance your website with a unique hover and left-click style inspired by the functionality of file explorer

I have a set of items like this: I am trying to replicate the functionality of a file explorer in terms of item selection. To clarify, I aim to create a feature where hovering over an item and left-clicking it would generate a virtual rectangle to select ...

What is the best way to sum up all the values per month from a JSON file in React and showcase it as a single month using ChartJs?

Apologies if I didn't explain my question clearly enough. As a junior developer, sometimes it's challenging to ask the right questions, and I'm sure we've all been there, right? The data in my JSON file is structured like this: [ { &qu ...

Can someone guide me on how to organize a div structure into a table format with the help of JQuery

I am new to JQuery and I have created a table using divs instead of the traditional table structure. Each row has the same ids, which I thought would help me sort the table. Here's an example of my code: <div class="column_title">Column 1</ ...

A guide to crafting a renowned graph using Core Plot in Swift

I successfully created a CPTXYGraph using Core Plot in Swift and it is functioning perfectly. However, I am now attempting to add a legend to the graph. After reviewing various examples, I developed the following code snippet to implement the legend: ...

Encountering a problem while trying to install the create-react-app package using npm

Currently attempting to set up React on my computer as a newcomer to the technology. On my first attempt, running create-react-app react-app to initiate a project displayed the following error: https://i.sstatic.net/BQNTV.png Despite the error message, th ...

Hear for updates on Firebase data using AngularFire

Can Firebase server updates be listened to in the DOM through AngularFire? I am looking for a way to automatically retrieve any updates from the server and use them to update an array's values. The issue I am facing is related to using Firebase.Serve ...

Electron: X is not a function *** (Using callbacks with ipcrenderer/ipcmain)

The Issue While using Promises to receive callbacks upon loading libraries, a problem arises. Each promise triggers a message through ipcRenderer to ipcMain along with a callback function. Although the callback function is being executed as anticipated, ...

Breaking on newline, excluding newline-space in JavaScript

I want to divide my string into an array based on new lines, excluding those that start with a space. ORGANIZER;<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3758455056595e4d524577524f565a475b521954585a">[email prot ...

Textures in Three.js are appearing black when loaded

Currently in the process of transferring a mesh from Maya to three.js. After converting the Maya file to .obj format and loading it onto the page, I noticed that Materials with image textures (1024x1024 .tga files) appear black, while Materials with solid ...

Vue3 does not support parameter assignment

I am working on creating a function that takes two parameters, a string and an array. The array is meant to be filled with data obtained from Axios. However, I am encountering the issue {'assignment' is assigned a value but never used.}. My goal ...

A basic demonstration of a C++ client communicating with a node.js server via a Unix socket

Recently, I began my coding journey just a few months ago. I am eager to find a simple example of a C++ client communicating with a nodejs server - something as basic as "hello world." Despite searching online, all I can find is examples of C++ talking t ...

Strategies for reliably causing IE 10&11 to crash? Simulating the phenomenon of "Internet Explorer abruptly closing and reopening the tab"

Here's an interesting query. Is there a method to consistently trigger this error in Internet Explorer 10 & 11 using Javascript, CSS or HTML? An issue with this website is forcing Internet Explorer to close and reopen the tab. I'm not trying ...

Building objects with attributes using constructor functions

My question pertains to JavaScript constructor function prototypes. Suppose I have code like the following: a = function (name){this.name = name}; a['b'] = function (age){this.age = age}; c = new a('John'); c.a['b'](30); Is ...

AngularJS: Click on image to update modelUpdate the model by clicking

I am a newcomer to AngularJS and I am attempting to update my model after the user clicks on an image. Below is the code for this: <div class="col-xs-4 text-center"><a ng-model="user.platform" value="ios"><img src="ios.png" class="img-circl ...

Having trouble getting the Bootstrap navbar mega menu to function properly on an Asp.Net Core platform

I attempted to incorporate a Bootstrap navbar mega menu dropdown into my layout using the code from this source: However, after downloading and inserting the code into my layout, the mega menu does not expand or take any action when clicked. In the Chrome ...

Using Selenium with Python to interact with dropdown elements in webpages

My goal is to extract data from using python's selenium library. I've encountered an issue with two interconnected elements. There are two select statements: a) with id="promptCategoryInput" and b) id='promptShareInput'. The manual pro ...

Updating an AngularJS directive with a change in URL: Best practices

Similar Question: Customizing tab styles in AngularJS Utilizing AngularJS, I am attempting to include a "current" class in my menu item whenever the content of that tab is being shown. The current implementation works as expected upon page load: HTML ...

jQuery trigger event when a DropDownList/SELECT item is selected

My current jQuery code filters a list of links on the page by firing when a link with a specified href is clicked. The id of the link determines which content remains visible. Here's an example: <script type="text/javascript"> $(docume ...

What is the proper way to include jQuery script in HTML document?

I am facing an issue with the banners on my website. When viewed on mobile devices, the SWF banner does not show up. In this situation, I want to display an <img> tag instead, but the jQuery code is not functioning correctly. My template structure l ...