In an ionic app, I am watching the on-swipe-right directive to implement a "Back" feature.
doctype html5
html(lang='en', ng-app='my-app')
head
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible', content='IE=edge,chrome=1')
meta(name='viewport', content='width=device-width,initial-scale=1')
//- snip
body(
ng-controller="DoloresMainCtrl"
on-swipe-right="toMainScreen($event)"
)
ion-nav-view
And in the controller
angular.module('my-app', [
'ui.router'
])
.controller 'DoloresMainCtrl', ($scope, $state)->
$scope.toMainScreen = ($event)->
$state.go '^' if $event?.gesture?.touches?.length is 2
The event fires just fine, but $event.gesture.touches.length is always 1.
What do I need to set to get ionic to detect multiple touches?
(Constraints: Android 4.4+, iOS 8+)
Here is a working example that can detect multiple touch points for tap events. The touchstart of the points have to be very simultaneous to count as multi-tap. Otherwise they are perceived as two sequential taps.
angular.module('my-app', ['ui.router'])
.directive('multiTap', function () {
return {
restrict: 'A',
link: function postLink(scope, element, attrs) {
element.text('this is the multi-tap directive');
var tap = ionic.onGesture("tap", handler, element[0]);
function handler(e) { console.log(e);
element.text(e.type + e.gesture.touches.length);
}
}
};
});
HTML example:
<ion-content class="padding" multi-tap>
Related
In my flutter app I have html inside a webview and some javascript with jquery attached. I want to trigger different actions depending on if a list item receives 'tap' or 'taphold'. I'm using jquery-mobile 1.5.0-rc1.
My javascript is as follows:
$('div.board').on('taphold tap', 'div.thread, div.thread-special', function(event) {
console.log('event');
var $item = $(this); // The item that was clicked or held
var scope = $item.data('itemscope'); // No numbered IDs! You can find everything about the item
// etc.
var type = event.type;
if (type === 'tap') {
console.log('tap');
} else if (type === 'taphold') {
console.log('taphold');
}
});
When I tap, I can see a 'tap' in the console. When I taphold, nothing at all happens or appears on the console. Any idea why?
I'm building a little browser app using android webview and I've been using window.getSelection() in javascript to get the nature of any text selected by the user and show a custom context menu based on the type of the selection i.e. whether it's a range, a carat, whether it's in a contenteditable etc.
This works fine unless the selection is in an iframe, then the browser security measures kick in and prevent me sniffing what has been selected using window.getSelection(). How can I workaround this?
Ideally I need a way to get better information about what was selected from the webview or if that's not possible I need a way to sniff whether the selection occurred in an iframe so I can disable my custom context menu logic and fallback to the default android context menu.
UPDATE/FURTHER CLARIFICATION 07/05/2019:
Seems I wasn't clear enough in my initial description...
My goal is to have a visually and functionally custom menu when selecting content in the webview that can cut/copy/paste as the standard context menu does in any part of the page/iframes etc. e.g.
I realised my original approach using javascript to detect the type of selection and to perform the cut/copy/paste was wrong because it will be blocked by cross origin security in iframes.
What I need is a native android/webview based approach. I've discovered that I can sniff the type of selection in the webview by looking at the items in mode.getMenu() on onActionModeStarted. This will allow me to show the correct buttons in my custom menu UI but I have been unable to manually trigger the same logic that gets called when cut/copy/paste is clicked. I thought I found the solution with webView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_CUT, null); but this doesn't work for some reason so I guess my question really is how can I manually trigger cut/copy/paste on the selected text from webview without using javascript? or any other approach that will allow me to have a custom selection menu with lots of options based on what was selected without hitting the browser security limitations?
Okay I figured out how roughly how to do this.
Step 1) In your activity, override onActionModeStarted and check the menu items available in the default context menu. This gives you a clue as to what the type of selection is and which buttons you will need to show in your custom menu. Also it gives you a reference to the item ID which you can use to later to trigger the action e.g.
systemSelectionMenu = mode.getMenu(); // keep a reference to the menu
MenuItem copyItem = systemSelectionMenu.getItem(0); // fetch any menu items you want
copyActionId = copyItem.getItemId(); // store reference to each item you want to manually trigger
Step 2) Instead of clearing the menu, use setVisible() to hide each menu item you want a custom button for e.g.
copyItem.setVisible(false);
Step 3) In your custom button onclick event you can trigger the copy action using:
myActivity.systemSelectionMenu.performIdentifierAction(myActivity.copyActionId, 0)
You can retrieve iframe's selection only if it has the same origin. Otherwise, you have no chances to track any iframe's events(clicks, touches, key presses, etc.).
const getSelectedText = (win, doc) => {
const isWindowSelectionAvailable = win && typeof win.getSelection != "undefined";
if (isWindowSelectionAvailable) {
return win.getSelection().toString();
}
const hasDocumentSelection = doc && typeof doc.selection != "undefined" && doc.selection.type == "Text";
if (hasDocumentSelection) {
return doc.selection.createRange().text;
}
return '';
}
const doIfTextSelected = (win, doc, cb) => () => {
const selectedText = getSelectedText(win, doc);
if (selectedText) {
cb(selectedText);
}
}
const setupSelectionListener = (win, doc, cb) => {
doc.onmouseup = doIfTextSelected(win, doc, cb);
doc.onkeyup = doIfTextSelected(win, doc, cb);
}
const getIframeWinAndDoc = (iframe) => {
try {
const doc = iframe.contentDocument || iframe.contentWindow.document;
const win = iframe.contentWindow || iframe.contentDocument.defaultView;
return { win, doc };
} catch (e) {
console.error(`${e}`);
return {};
}
}
const callback = console.log;
setupSelectionListener(window, document, callback);
document.querySelectorAll('iframe').forEach(iframe => {
const { win, doc } = getIframeWinAndDoc(iframe, console.log);
// Only for same origin iframes due to https://en.wikipedia.org/wiki/Same-origin_policy
if (win && doc) {
setupSelectionListener(win, doc, callback);
}
})
<h3>Select me</h3>
<div class="container">
<iframe src="https://teimurjan.github.io"></iframe>
</div>
This issue varying from browser to other if it works with internet explorer so it may fall with chrome
Try this
App.util.getSelectedText = function(frameId) {
var frame = Ext.getDom(frameId);
var frameWindow = frame.contentWindow;
var frameDocument = frameWindow.document;
if (frameDocument.getSelection) {
return frameDocument.getSelection();
}
else if (frameDocument.selection) {
return frameDocument.selection.createRange().text;
}
};
Hope it runs fine
Main problem is the window.getSelection() will return selection only for the main context/window. As iframe is the other window and other context, you should call getSelection() from iframe which is "current".
When I use plain html5 video/audio on Android, I have my user click a button on startup. In the click handler I kickstart all media:
$('.viewaud').each(function(i,el){
el.load();
el.play();
el.pause();
})
After that I can start videos/sounds programmatically without the user having to click.
Is something similar possible in videogular?
Yes, you can do something similar with Videogular.
HTML template:
<videogular vg-player-ready="vm.onPlayerReady($API)">
<!-- other components -->
</videogular>
<button type="button" ng-click="vm.onClickStart()">Start</button>
JS Controller:
angular.module("myApp").controller("MainCtrl",
function ($sce) {
this.onPlayerReady = function (API) {
this.API = API;
};
this.onClickStart = function (event) {
this.API.play();
this.API.pause();
};
// More code...
}
);
Does anyone have a working example of using proprietary properties like "ontouchend", and "gestureend" in TypeScript?
I've tried using something like this below:
//Create an alert.
function TouchedScreen(username: string): void {
alert(username + " has touched the screen.");
}
//Touch anywhere on screen for an alert on iOS/Android
window.ontouchend = () => {
TouchedScreen("[username]");
};
I'm assuming this is due to ontouchend being a proprietary property, using addEventListener compiles correctly but I wan't to use it with a property, how can I do this in TypeScript?
Just tell typescript that these properties exist on Window:
interface Window{
ontouchend: Function;
}
//Touch anywhere on screen for an alert on iOS/Android
window.ontouchend = () => { // compiles fine
};
If you want the same event on all HTMLElements just tell TypeScript about that too:
interface HTMLElement {
ontouchend: Function;
}
var a: HTMLAnchorElement;
a.ontouchend = () => { // compiles fine
};
I'm working on making an Android app using Phonegap and AngularJS. I'm attempting to create a button to be used as both a "cancel" and a "back" button, that will essentially just hit the browser's 'back' button.
Here's some sample HTML for the cancel button:
cancel
And here is the controller for that page, with the goBack() button:
function NewOccasionCtrl($scope, $window) {
$scope.$window = $window;
$scope.goBack = function() {
$window.history.back();
};
}
This throws no errors, but also doesn't work... the emulator remains on the same page. Without the $scope.$window = $window it throws an error. I was hoping to achieve a functional 'back' button without having to create/use a directive, because as far as I understand those then implement templating and things I don't need/want.
Is there a way to do this? Thanks
I went with using a Directive to make the back functionality reusable. Here is my final code:
HTML:
<a href back-button>back</a>
Javascript:
app.directive('backButton', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', goBack);
function goBack() {
history.back();
scope.$apply();
}
}
}
});
I had an issue like this using phonegap and angular, $window.history.back() would not work. So I created a workaround.
$scope.urlHistory = [];
$scope.$on('$routeChangeSuccess', function () {
if ($location.$$absUrl.split('#')[1] !== $scope.urlHistory[$scope.urlHistory.length - 1]) {
$scope.urlHistory.push($location.$$absUrl.split('#')[1]);
}
});
$scope.goBack = function () {
$scope.urlHistory.pop();
$location.path($scope.urlHistory[$scope.urlHistory.length - 1]);
};
Hope this help someone else.