How to implement drag&drop functionality in ace-editor - drag-and-drop

I want to add drag&drop functionality into the ace-editor. I have a sidebar contains some objects, what I want to do is I can drag the object from the sidebar and drop it on the ace-editor.

Set text data when object starts dragging, ace will insert that text when dropping element onto it.
// create
document.querySelector("#drag").ondragstart = function(e) {
var dataTransfer = e.dataTransfer;
dataTransfer.effectAllowed
dataTransfer.setData("Text", e.target.outerHTML + "\n");
}
// create editor
var editor = ace.edit(null, {
maxLines: 10,
minLines: 5,
})
document.body.appendChild(editor.container)
#drag {
padding: 10px
}
#drag>span {
padding: 3px;
border: solid 1px purple;
cursor: grab;
}
<script src=https://ajaxorg.github.io/ace-builds/src-noconflict/ace.js></script>
<div id=drag>
<span draggable=true >Drag Me</span>
<span draggable=true >Or Me</span>
</div>

Related

Testing for existence of react-modal using React Testing Library with findByRole

I am trying to test for the existence of my modal using React Testing Library with findByRole. I keep getting an error saying: Unable to find role="dialog" even though I can see clearly see it printed out in the console of the test.
Here is my test:
import React from "react";
import {
render,
screen,
within,
fireEvent, cleanup, waitFor
} from '#testing-library/react';
import '#testing-library/jest-dom';
import "#testing-library/react/dont-cleanup-after-each";
import Modal from 'react-modal';
import PackagerModal from './PackagerModal';
const mockedEmptyFn = jest.fn();
const mockBaseProps = {
openPackager: true,
setOpenPackager: mockedEmptyFn,
activeOrder: {
// ... // lots of irrelevant properties here
]
},
setOrders: mockedEmptyFn,
customStyles: {
content: {
backgroundColor: "var(--color-primary)",
border: "1px solid #ccc",
boxShadow: "-2rem 2rem 2rem rgba(0, 0, 0, 0.5)",
color: "rgba(var(--RGB-text), 0.8)",
filter: "blur(0)",
fontSize: "1.1em",
fontWeight: "bold",
margin: "50px auto",
opacity: 1,
outline: 0,
position: "relative",
visibility: "visible",
width: "500px"
},
overlay: {
backgroundColor: "rgba(255, 255, 255, 0.9)"
}
},
readOnly: false,
setReadOnly: mockedEmptyFn,
};
Modal.setAppElement('body');
const Component = (props) => <PackagerModal {...mockBaseProps} {...props} />
describe('Packager Modal tests with editable inputs', () => {
afterAll(() => {
cleanup();
});
test('Should show packager modal', async () => {
render(
<Component/>
);
// screen.debug();
const modalWindow = await screen.findByRole('dialog');
expect(modalWindow).toBeInTheDocument();
});
});
And here is my modal:
import ReactModal from 'react-modal';
import React, { useEffect, useRef, useState } from 'react';
import CloseButton from './CloseButton';
import PropTypes from 'prop-types';
const PackagerModal = (props) => {
const {
openPackager,
setOpenPackager,
activeOrder,
setOrders,
customStyles,
readOnly,
setReadOnly,
} = props;
const cleanUpModal = () => {
setReadOnly(false);
setUserInput(initialState);
};
return (
<ReactModal
isOpen={openPackager}
style={customStyles}
className={'order-details-modal'}
closeTimeoutMS={1000}
onAfterClose={cleanUpModal}
>
<CloseButton setOpenModal={setOpenPackager} />
<h2 className={'title'}>Packager Order Checklist</h2>
</ReactModal>
);
};
PackagerModal.propTypes = {
openPackager: PropTypes.bool.isRequired,
setOpenPackager: PropTypes.func.isRequired,
customStyles: PropTypes.object.isRequired,
activeOrder: PropTypes.object.isRequired,
setOrders: PropTypes.func.isRequired,
readOnly: PropTypes.bool.isRequired,
setReadOnly: PropTypes.func.isRequired,
};
export default PackagerModal;
And finally, here is some of the output I see in the console from the test:
● Packager Modal tests with editable inputs › Should show packager modal
Unable to find role="dialog"
Ignored nodes: comments, script, style
<body
aria-hidden="true"
class="ReactModal__Body--open"
>
<div
data-react-modal-body-trap=""
style="position: absolute; opacity: 0;"
tabindex="0"
/>
<div />
<div
data-react-modal-body-trap=""
style="position: absolute; opacity: 0;"
tabindex="0"
/>
<div
class="ReactModalPortal"
>
<div
class="ReactModal__Overlay ReactModal__Overlay--after-open"
style="position: fixed; top: 0px; left: 0px; right: 0px; bottom: 0px; background-color: rgba(255, 255, 255, 0.9);"
>
<div
aria-modal="true"
class="ReactModal__Content ReactModal__Content--after-open order-details-modal"
role="dialog"
style="border: 1px solid #ccc; box-shadow: -2rem 2rem 2rem rgba(0, 0, 0, 0.5); filter: blur(0); font-size: 1.1em; font-weight: bold; margin: 50px auto; opacity: 1; outline: 0; position: relative; visibility: visible; width: 500px;"
tabindex="-1"
>
...
Looks like the body of your test is set to hidden - aria-hidden="true" (not sure why as I'm not familiar with the package). React Testing Library is heavily accessibility oriented, so by default it ignores any elements that are not accessible.
Try querying your element with the { hidden: true } option
const myModal = getByRole('dialog', { hidden: true });
Though Avi's answer works, it technically isn't the best for testing. I was having the same issue and have realised we also have the same issue with our code so here is what is happening.
The issue is that you are saying Modal.setAppElement('body'); in your test file.
If you read the docs for react-modal, they say you need to tell the modal where your apps content is so that when the modal is open, everything within that element will have aria-hidden: true so that screen readers don't pick up any of the other content other than whats inside the modal since that gets rendered via a portal appended to the end of your body. So you setting setAppElement to body is making everything inside that hidden to screen readers, including your modal.
So to solve this you need to set that to something else, I personally have my own render function that has things like providers so I just added a new div in there. But in your case you could add it to your Component
const Component = (props) => <div id="root"><PackagerModal {...mockBaseProps} {...props} /></div>
Then you can chance the line setAppElement line to
Modal.setAppElement('root');
This will mean that you don't have to add the { hidden: true } option to your queries.
You also dont have to use findBy since there isn't any async changes happening in your test so far
test('Should show packager modal', () => {
render(<Component/>);
const modalWindow = screen.getByRole('dialog');
expect(modalWindow).toBeInTheDocument();
});

How to dynamically adjust symbology based on user generated table

I have created a simple leaflet web app that allows for the user to search for the countries that they have traveled.
The user can use a search box or click on the layer on the map. either action will highlight the country green and load the name and flag in an adjacent table.
This works fine. However, problems arise should the user decide to remove a country visited (for example they made a mistake when selecting)
I have included the ability to delete the table items by user click and enabled a function on double click of the layer itself to reset the colour.
What I need is for these two actions to relate to one another. so if the user removes the flag, the related country is reset and vis versa.
I think I need some sort of listener on the click remove or highlight function or perhaps defining the symbology based on the user-generated table of countries visited. Any suggestions?
<!DOCTYPE html>
<html>
{% load static %}
{% load leaflet_tags %}
<head>
{% leaflet_js %}
{% leaflet_css %}
<script type="text/javascript" src="{% static 'dist/leaflet.ajax.js' %}"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<title>hello world</title>
<link rel="stylesheet" href="{% static 'leaflet-groupedlayercontrol/leaflet.groupedlayercontrol.min.css' %}" />
<link rel="stylesheet" href="https://labs.easyblog.it/maps/leaflet-search/src/leaflet-search.css" />
<link rel="stylesheet" href="https://labs.easyblog.it/maps/leaflet-search/examples/style.css" />
<style type="text/css">
#findbox {
background: #eee;
border-radius: 0.125em;
border: 2px solid #1978cf;
box-shadow: 0 0 8px #999;
margin-bottom: 10px;
padding: 2px 0;
width: 600px;
height: 26px;
}
.search-tooltip {
width: 200px;
}
.leaflet-control-search .search-cancel {
position: static;
float: left;
margin-left: -22px;
}
#map {
width: 50%;
height: 650px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<p style="text-align: center; font-size: 24px; color: #175b81; font-weight: bold;"></p>
<h3>My World Map</h3>
<div id="findbox"></div>
<div id="map" style="height: 680px; width: 48%; display: ;"></div>
<div class="sidebar" style="display: right;">
<p style="text-align: centre; font-size: 24px; color: #175b81; font-weight: bold;">My Flags:</p>
<table style="width: 90%;">
<tr>
<td id="name" hidden></td>
<td id="code" hidden></td>
</tr>
<ul id="Countries_Visted"></ul>
</table>
</div>
<script>
var img1 = "<img src=";
var im2 = ">";
var quotes = "'";
var flagimage_pt1 = "https://www.countryflags.io/";
var flagimage_pt2 = "/flat/64.png";
// creating mapbox basemap
var mapboxAccessToken =
"pk.eyJ1IjoiY2hyaXNyeWFuLXRlY2giLCJhIjoiY2thY2c3bDZyMDZsNDJ4cHJlZmhwZmFjaCJ9.3GuHRvRz-8fxi4r103z05w";
var mapbox = L.map("map").setView([46.0, 8.0], 2.2);
mapbox.doubleClickZoom.disable();
L.tileLayer(
"https://api.mapbox.com/styles/v1/chrisryan-tech/ckaxvc0bt10041iqfz5fb7dgj/tiles/256/{z}/{x}/{y}#2x?access_token=" +
mapboxAccessToken,
{
tileSize: 512,
zoomOffset: -1,
attribution:
'© Mapbox © OpenStreetMap',
}
).addTo(mapbox);
//loading data with style, click function and listener
var data_layer = new L.GeoJSON.AJAX("{% url 'borders_data' %}", {
style: countriesStyle,
onEachFeature: countriesOnEachFeature,
});
//listener - adding to map on load
data_layer.on("data:loaded", function (e) {
layer.addTo(mapbox);
});
function countriesStyle(feature) {
return {
fillColor: "grey",
weight: 2,
opacity: 0.2,
color: "grey",
dashArray: 3,
fillOpacity: 0.2,
};
}
function countriesOnEachFeature(feature, layer) {
layer.on({
click: function (e) {
var layer = e.target;
layer.setStyle({
weight: 1,
color: "#fff",
dashArray: "",
fillOpacity: 0.9,
fillColor: "green",
});
if (!L.Browser.ie && !L.Browser.opera && !L.Browser.edge) {
layer.bringToFront();
}
},
});
layer.on({
click: load_name_flag,
});
layer.on({
dblclick: clear,
});
}
///// clearing styling
var layer = data_layer;
function clear(e) {
layer.resetStyle(e.target);
}
///// adding to clicked countries to countries visted list
function load_name_flag(e) {
var field1 = document.getElementById("name");
field1.innerHTML = e.target.feature.properties.name;
var field2 = document.getElementById("code");
field2.innerHTML = e.target.feature.properties.iso2;
var selected_name_search = field1.innerHTML;
var selected_flag_search = img1 + quotes + flagimage_pt1 + field2.innerHTML + flagimage_pt2 + quotes + im2;
var selected_features_combine = selected_name_search + selected_flag_search;
$("#Countries_Visted").append("<li>" + selected_features_combine + "</li>").disabled = true;
}
</script>
<!- search box functionality - searches attribute data -->
<!- contained within Geojson from loaded event listener -->
<script src="https://unpkg.com/leaflet#1.3.0/dist/leaflet.js"></script>
<script src="https://labs.easyblog.it/maps/leaflet-search/src/leaflet-search.js"></script>
<script>
//pointing search function to map layer
var searchControl = new L.Control.Search({
container: "findbox",
layer: data_layer,
initial: false,
collapsed: false,
propertyName: "name",
marker: false,
});
// search box finds layer and adds country name and flag, changes layer symbol to green
searchControl.on("search:locationfound", function (e) {
var field1 = document.getElementById("name");
field1.innerHTML = e.layer.feature.properties.name;
var field2 = document.getElementById("code");
field2.innerHTML = e.layer.feature.properties.iso2;
var selected_name_search = field1.innerHTML;
var selected_flag_search = img1 + quotes + flagimage_pt1 + field2.innerHTML + flagimage_pt2 + quotes + im2;
var selected_features_combine = selected_name_search + selected_flag_search;
// styles for selected country
e.layer.setStyle({ fillColor: "green", color: "black", fillOpacity: 0.8 });
/// adding name and flag to countriesvisted list from searchbox select
$("#Countries_Visted").append("<li>" + selected_features_combine + "</li>").disabled = true;
});
mapbox.addControl(searchControl); //inizialize search control
// function to remove added layers
Countries_Visted.onclick = function remove(e) {
var li = e.target;
var layer = data_layer;
var listItems = document.querySelectorAll("li");
var ul = document.getElementById("ul");
li.parentNode.removeChild(li);
layer.resetStyle(e.target);
};
</script>
</body>
</html>

How do I change the background color with <type color>?

Only divs with id are clicking, div with class names are not clicking.
By clicking on div with id, you need to change the color. Class divs do not have to be clicked and they do not have to change their color. I added it to imput type color class, so it does not click also.
If I try document.getElementByID ("backgroundcolor"). Value; works normally
if I try document.getElementsByClassName ("backgroundcolor"). value; does not work.
I need to call the ByClassName function(color), but it does not work, Ideas?
#divid{
width: 450px;
height: 170px;
margin: 10px;
padding: 10px;
background-color: blue;
}
.divclass{
width: 450px;
height: 170px;
margin: 10px;
padding: 10px;
background-color: blue;
}
<input type="color" class="backgroundcolor" onchange="BackgroundColor()">
<div class="divclass">
</div>
<div id="divid">
</div>
var div = document.getElementsByTagName("div");
var divCount = div.length;
var clickedDivId;
for (var i = 0; i < divCount; i += 1) {
div[i].onclick = function(e) {
if (e.target.id) alert(this.id);
clickedDivId = this.id;
e.stopPropagation();
};
}
function BackgroundColor(){
var x = document.getElementsByClassName("backgroundcolor").value;
document.getElementById(clickedDivId).style.backgroundColor = x;
}
var x = document.getElementsByClassName("backgroundcolor")[0].value;

How to place a HTML element on a map in OpenLayers

I am working on Openlayers 5.13 with jQuery 3.21. I am trying to place a html div element on the viewport of a map in openlayers. This element is supposed to have two check-boxes to filter out some content on the map.
For this purpose I am using an Overlay instance.
There are two problems:
1) When I zoom-in or zoom-out the overlay tends to increase and decrease in size, which is not what I am expecting.
I want that overlay (html div element) to retain its size.
2) I cant quit figure out how to place the overlay in top right corner.
An overlay is instantiated with a position property which I don't know what to set to.
I also don't know that if the overlay is what I should seek to show some static element on the map. (I highly doubt that overlay is right way)
Here is my code :
css-
<style>
.ol-panel {
position: absolute;
background-color: white;
filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
min-width: 100px;
}
</style>
html -
<div id="panel" class="ol-panel">
<div id="content">
<table>
<tr>
<td>
Ports <input type="checkbox">
</td>
</tr>
<tr>
<td>
Vessels <input type="checkbox">
</td>
</tr>
</table>
</div>
</div>
<div id="map"></div>
script -
map = new ol.Map({
logo: 'false',
target: 'map',
layers: [new ol.layer.Tile({
title: 'OSM',
type: 'base',
visible: true,
source: new ol.source.OSM()
})],
view: new ol.View({
center: ol.proj.transform([17.813988, 43.342019], 'EPSG:4326', 'EPSG:3857'),
zoom: 3
})
});
panelDiv = document.getElementById("panel");
var panel = new ol.Overlay({
element: panelDiv,
stopEvent: false,
//offset:[0,0],
autoPan: true,
position: ol.proj.transform([82,80 ], 'EPSG:4326', 'EPSG:3857'),
positioning: 'top-right',
autoPanAnimation: {
duration: 250
}
});
map.addOverlay(panel);
This is my current output:
This is what I am expecting, an element that stays fixed at a position:
Reference - [http://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html]
I got what I was looking for here [http://openlayers.org/en/latest/examples/custom-controls.html?q=custom-controls]
/** Create a checkbox to toggle visibility of straits on map
* You can create different controls for different operations
*/
var strait_cbx = document.createElement('input');
strait_cbx.type = "checkbox";
strait_cbx.id = "strait_cbx";
strait_cbx.checked = true;
/**
* This is a container element which holds input elements which are controls for the map
* You can add as many as you want depending upon use.
* The element is a div which would act like a panel to add controls on map like toggling visibility of the layers
*/
var element = document.createElement('div');
element.className = 'ol-control-panel ol-unselectable ol-control';
element.innerHTML="<b>Straits</b> "
element.appendChild(strait_cbx);
/*A custom control which has container holding input elements etc*/
var controlPanel = new ol.control.Control({
element: element
});
map.addControl(controlPanel);

Google place Api, autocomplete and infowindow

following the example on the google developpers website, I would like to have an infowindow open on click within the results of a search (instead of just the tile on hover)
There are a few similar questions but I did't find an answer that does just this.
Can somebody tell me how to fix it please ?
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
html, body, #map-canvas {
height: 100%;
margin: 0;
padding: 0;
}
.controls {
margin-top: 16px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
#pac-input {
background-color: #fff;
font-family: Roboto;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 400px;
}
#pac-input:focus {
border-color: #4d90fe;
}
.pac-container {
font-family: Roboto;
}
#type-selector {
color: #fff;
background-color: #4d90fe;
padding: 5px 11px 0px 11px;
}
#type-selector label {
font-family: Roboto;
font-size: 13px;
font-weight: 300;
}
</style>
<title>Places search box</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=places"></script>
<script>
// This example adds a search box to a map, using the Google Place Autocomplete
// feature. People can enter geographical searches. The search box will return a
// pick list containing a mix of places and predicted search terms.
function initialize() {
var markers = [];
var map = new google.maps.Map(document.getElementById('map-canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-33.8902, 151.1759),
new google.maps.LatLng(-33.8474, 151.2631));
map.fitBounds(defaultBounds);
// Create the search box and link it to the UI element.
var input = /** #type {HTMLInputElement} */(
document.getElementById('pac-input'));
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
var searchBox = new google.maps.places.SearchBox(
/** #type {HTMLInputElement} */(input));
// [START region_getplaces]
// Listen for the event fired when the user selects an item from the
// pick list. Retrieve the matching places for that item.
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
for (var i = 0, marker; marker = markers[i]; i++) {
marker.setMap(null);
}
// For each place, get the icon, place name, and location.
markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var image = {
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(17, 34),
scaledSize: new google.maps.Size(25, 25)
};
// Create a marker for each place.
var marker = new google.maps.Marker({
map: map,
icon: image,
title: place.name,
position: place.geometry.location
});
markers.push(marker);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
});
// [END region_getplaces]
// Bias the SearchBox results towards places that are within the bounds of the
// current map's viewport.
google.maps.event.addListener(map, 'bounds_changed', function() {
var bounds = map.getBounds();
searchBox.setBounds(bounds);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<style>
#target {
width: 345px;
}
</style>
</head>
<body>
<input id="pac-input" class="controls" type="text" placeholder="Search Box">
<div id="map-canvas"></div>
</body>
</html>
Thanks.
For some reason, I can't make a jsfiddle with this (maybe it's a domain permission issue) and I can't upload an image since i'm new here
Try putting this into a jsfiddle referencing https://maps.googleapis.com/maps/api/js?v=3.exp&signed_in=true&libraries=places in the External Resources.
After an address/place is selected from the searchbox, the marker and infoWindow render with the infoWindow open and populated.
<div id="map_canvas"></div>
<div id="locationField">
<input id="autocomplete" name="autocomplete" type="text" placeholder="Location Search" onFocus="geolocate()" />
</div>
function initialize() {
var placeSearch;
var mapOptions = {
center: new google.maps.LatLng(41.877461, -87.638085),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false,
disableDefaultUI: true,
streetViewControl: false,
panControl: false
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
var input = /** #type {HTMLInputElement} */
(
document.getElementById('autocomplete'));
map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
var autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.bindTo('bounds', map);
var infowindow = new google.maps.InfoWindow();
var marker = new google.maps.Marker({
map: map,
anchorPoint: new google.maps.Point(0, -29)
});
google.maps.event.addListener(marker, 'click', function () {
infowindow.open(map, marker);
});
google.maps.event.addListener(autocomplete, 'place_changed', function () {
infowindow.close();
marker.setVisible(false);
var place = autocomplete.getPlace();
if (!place.geometry) {
window.alert("Autocomplete's returned place contains no geometry");
return;
}
// If the place has a geometry, then present it on a map.
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(12); // Why 17? Because it looks good.
}
marker.setIcon( /** #type {google.maps.Icon} */ ({
url: place.icon,
size: new google.maps.Size(71, 71),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(25, 34),
scaledSize: new google.maps.Size(50, 50)
}));
marker.setPosition(place.geometry.location);
marker.setVisible(true);
infowindow.setContent('<div><strong>' + place.name + '</strong><br>' +
'Place ID: ' + place.place_id + '<br>' + place.formatted_address);
infowindow.open(map, marker);
});
// Bias the autocomplete object to the user's geographical location,
// as supplied by the browser's 'navigator.geolocation' object.
function geolocate() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
var geolocation = new google.maps.LatLng(
position.coords.latitude, position.coords.longitude);
autocomplete.setBounds(new google.maps.LatLngBounds(geolocation, geolocation));
});
}
}
}
initialize();
html, body, #map_canvas {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#autocomplete {
height: 60px;
width: 100%;
border: 2px solid #fff;
color: #1c1c1c;
font-size: 15px;
text-align: center;
background-color: #fff;
font-family: Roboto;
font-weight: 300;
text-overflow: ellipsis;
}
#autocomplete:focus {
border-color: #4d90fe;
}