FileManagerBundle. Implement FileMangerBundle (artgris) using TinyMCE v6.2 with Symfony4 - tinymce

I have tinyMCE 6.2 in my project. How to chose file?
And I can't choose an image by click or by check.
The selected file path (tinymceCallBackURL) is empty. Can you help me?
tinyMCE init:
tinymce.init({ selector: '.tinymce', file_picker_callback: myFileBrowser, .......... }
My code js:
var type = meta.filetype;
var cmsURL = "file_manager/?conf=tiny";
if (cmsURL.indexOf("?") < 0) {
cmsURL = cmsURL + "?type=" + type;
} else {
cmsURL = cmsURL + "&type=" + type;
}
var windowManagerCSS = '<style type="text/css">' + '.tox-dialog {max-width: 100%!important; width:97.5%!important; overflow: hidden; height:95%!important; border-radius:0.25em;}' + '.tox-dialog__body { padding: 0!important; }' + '.tox-dialog__body-content > div { height: 100%; overflow:hidden}' + '</style> ';
window.tinymceCallBackURL = '';
window.tinymceWindowManager = tinymce.activeEditor.windowManager;
tinymceWindowManager.open({
title: 'Menedżer plików',
url: cmsURL,
body: {
type: 'panel',
items: [{
type: 'htmlpanel',
html: windowManagerCSS + <iframe src="/file_manager/?conf=tiny&type=${type}" style="width:100%; height:500px" id="filemanager"></iframe> }]
},
buttons: [],
onClose: function () {
if (tinymceCallBackURL != '') callback(tinymceCallBackURL, {}); //to set selected file path } }); }````

I have a solution. (unswer in github issue https://github.com/artgris/FileManagerBundle/issues/107):
I needed to add module=tiny in cmsURL :
var cmsURL = "file_manager/?module=tiny&conf=tiny";
and replace:
html: windowManagerCSS + '<iframe src="/file_manager/?conf=tiny&type=${type}" ... thinking
with:
html: windowManagerCSS + '<iframe src="' + cmsURL ...
https://github.com/artgris/FileManagerBundle/blob/master/Resources/doc/tutorials/integrate-tinymce.md

Related

Chartjs stacked bar separate tooltip for all stacked

I want to make a separate tooltip for every stacked bar, Ex. My demo "2022-01-17" has TWO stacked bars with FOUR values but I need a total of Stack 1 group and Stack 2 group
I've reviewed most of the options in chartjs https://www.chartjs.org/docs/3.5.1/samples/bar/stacked-groups.html
var barChartData = {
labels: ["2022-01-17","2022-01-18","2022-01-19","2022-01-20","2022-01-21","2022-01-22","2022-01-23","2022-01-24","2022-01-25","2022-01-26","2022-01-27","2022-01-28","2022-01-29","2022-01-30"],
datasets: [{"label":"Product 2","data":["292.53","328.5","273.83","305.44","260.33","251.87","118.15","253.95","86.64","87.78","116.68","295.49","61.32","83.78"],"backgroundColor":"#66bb6a","borderColor":"#66bb6a","pointBackgroundColor":"#66bb6a","stack":"Stack 0"},{"label":"Product ","data":["1522.27","1844.83","1581.01","2767.68","2821.36","2940.31","2876.1","2037.79","1593.01","1900.86","1607.21","2188.92","2428.74","2508.81"],"backgroundColor":"#1b5e20","borderColor":"#1b5e20","pointBackgroundColor":"#1b5e20","stack":"Stack 0"},{"label":"Product 2","data":["200","4.14","28.51","13.68","0","0","19.93","0","0","0","10.47","23.05","9.42","10.58"],"backgroundColor":"#ffcdd2","borderColor":"#ffcdd2","pointBackgroundColor":"#ffcdd2","stack":"Stack 1"},{"label":"Product ","data":["680.2","536.51","524.41","479.69","453.19","521.87","530.57","485.13","440.25","591.29","722.73","711.58","686.63","510.72"],"backgroundColor":"#ef9a9a","borderColor":"#ef9a9a","pointBackgroundColor":"#ef9a9a","stack":"Stack 1"}]
};
const footer = (tooltipItems) => {
let sum = 0;
tooltipItems.forEach(function(tooltipItem) {
sum += tooltipItem.parsed.y;
});
return 'Sum: ' + sum;
};
var ctx = document.getElementById("canvas").getContext("2d");
var myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
interaction: {
intersect: false,
mode: 'index',
},
plugins: {
tooltip: {
callbacks: {
footer: (tooltipItem) => {
let sum = 0;
tooltipItem.forEach(function(tooltipItem) {
sum += tooltipItem.parsed.y;
});
return 'Sum: ' + sum;
}
}
}
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.0/dist/chart.min.js"></script>
<canvas id="canvas" height="100"></canvas>
to get the total of each stack, you can use the dataPoints found in the tooltip context
and use the dataset labels to group by each stack
// group stacks
const groups = {};
tooltip.dataPoints.forEach(function (point) {
if (groups.hasOwnProperty(barChartData.datasets[point.datasetIndex].label)) {
groups[barChartData.datasets[point.datasetIndex].label] += parseFloat(barChartData.datasets[point.datasetIndex].data[point.dataIndex]);
} else {
groups[barChartData.datasets[point.datasetIndex].label] = parseFloat(barChartData.datasets[point.datasetIndex].data[point.dataIndex]);
}
});
e.g. --> {"Product 2":492.53,"Product ":2202.4700000000003}
then use the external option to create a custom tooltip
see following working snippet...
$(document).ready(function() {
var barChartData = {
labels: ["2022-01-17","2022-01-18","2022-01-19","2022-01-20","2022-01-21","2022-01-22","2022-01-23","2022-01-24","2022-01-25","2022-01-26","2022-01-27","2022-01-28","2022-01-29","2022-01-30"],
datasets: [{"label":"Product 2","data":["292.53","328.5","273.83","305.44","260.33","251.87","118.15","253.95","86.64","87.78","116.68","295.49","61.32","83.78"],"backgroundColor":"#66bb6a","borderColor":"#66bb6a","pointBackgroundColor":"#66bb6a","stack":"Stack 0"},{"label":"Product ","data":["1522.27","1844.83","1581.01","2767.68","2821.36","2940.31","2876.1","2037.79","1593.01","1900.86","1607.21","2188.92","2428.74","2508.81"],"backgroundColor":"#1b5e20","borderColor":"#1b5e20","pointBackgroundColor":"#1b5e20","stack":"Stack 0"},{"label":"Product 2","data":["200","4.14","28.51","13.68","0","0","19.93","0","0","0","10.47","23.05","9.42","10.58"],"backgroundColor":"#ffcdd2","borderColor":"#ffcdd2","pointBackgroundColor":"#ffcdd2","stack":"Stack 1"},{"label":"Product ","data":["680.2","536.51","524.41","479.69","453.19","521.87","530.57","485.13","440.25","591.29","722.73","711.58","686.63","510.72"],"backgroundColor":"#ef9a9a","borderColor":"#ef9a9a","pointBackgroundColor":"#ef9a9a","stack":"Stack 1"}]
};
var ctx = document.getElementById("canvas").getContext("2d");
var myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
interaction: {
intersect: false,
mode: 'index',
},
plugins: {
tooltip: {
enabled: false,
position: 'nearest',
external: function (context) {
// init
const {chart, tooltip} = context;
// remove old tooltip
var container = chart.canvas.parentNode.querySelector('.tooltip');
if (container) {
chart.canvas.parentNode.removeChild(container);
}
// determine if tooltip exists
if (tooltip.opacity === 0) {
return;
}
// group stacks
const groups = {};
tooltip.dataPoints.forEach(function (point) {
if (groups.hasOwnProperty(barChartData.datasets[point.datasetIndex].label)) {
groups[barChartData.datasets[point.datasetIndex].label] += parseFloat(barChartData.datasets[point.datasetIndex].data[point.dataIndex]);
} else {
groups[barChartData.datasets[point.datasetIndex].label] = parseFloat(barChartData.datasets[point.datasetIndex].data[point.dataIndex]);
}
});
// build tooltip rows
var rows = '';
Object.keys(groups).forEach(function (groupName) {
rows += renderTemplate('template-tooltip-row', {
group: groupName,
value: groups[groupName].toLocaleString(undefined, {minimumFractionDigits: 2})
});
});
// build tooltip
chart.canvas.parentNode.insertAdjacentHTML('beforeEnd', renderTemplate('template-tooltip', {
rows: rows,
title: tooltip.title[0]
}));
// position tooltip
const {offsetLeft: positionX, offsetTop: positionY} = chart.canvas;
container = chart.canvas.parentNode.querySelector('.tooltip');
container.style.left = positionX + tooltip.caretX + 'px';
container.style.top = positionY + tooltip.caretY + 'px';
container.style.font = tooltip.options.bodyFont.string;
container.style.padding = tooltip.options.padding + 'px ' + tooltip.options.padding + 'px';
}
}
}
}
});
/**
* render html template
* #param {string} templateId - id of html template
* #param {object} templateValues - values for each template placeholder
* #return {string} template content
*/
function renderTemplate(templateId, templateValues) {
var propHandle; // property key
var templateText; // html template content
var templateValue; // value for template placeholder
// get template content, replace each placeholder with value
templateText = document.querySelector('#' + templateId).innerHTML;
if (templateValues) {
for (propHandle in templateValues) {
if (templateValues.hasOwnProperty(propHandle)) {
templateValue = '';
// convert template value to string
if (templateValues[propHandle] !== null) {
if (templateValues[propHandle].hasOwnProperty('results')) {
templateValue = encodeURIComponent(JSON.stringify(templateValues[propHandle].results));
} else {
templateValue = templateValues[propHandle].toString();
}
}
// handle dollar sign in template value
if (templateValue.indexOf('$') > -1) {
templateValue = templateValue.replace(new RegExp('\\$', 'g'), '$$$');
}
// replace template placeholder(s) with template value
if (templateText.indexOf('{{' + propHandle + '}}') > -1) {
templateText = templateText.replace(
new RegExp('{{' + propHandle + '}}', 'g'),
templateValue
);
}
}
}
}
return templateText.trim();
}
});
.align-right {
text-align: right;
}
.table {
border-collapse: separate;
border-spacing: 0vw 0vw;
display: table;
}
.table-body {
display: table-row-group;
}
.table-cell {
display: table-cell;
padding: 4px;
}
.table-foot {
display: table-footer-group;
}
.table-head {
display: table-header-group;
}
.table-row {
display: table-row;
}
.title {
font-weight: bold;
}
.tooltip {
background-color: rgba(0, 0, 0, 0.85);
border-radius: 3px;
color: #ffffff;
pointer-events: none;
position: absolute;
transform: translate(-50%, 0);
transition: all 0.1s ease;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.7.0/dist/chart.min.js"></script>
<canvas id="canvas" height="100"></canvas>
<script id="template-tooltip" type="text/html">
<div class="tooltip">
<div class="title">{{title}}</div>
<div class="table">
<div class="table-body">{{rows}}</div>
</div>
</div>
</script>
<script id="template-tooltip-row" type="text/html">
<div class="table-row">
<div class="table-cell title">{{group}}:</div>
<div class="table-cell align-right">{{value}}</div>
</div>
</script>

How can I see the information from a tooltip of a circle marker which is contained within a polygon which also has a tooltip

I am very new to leaflet.
Below is my code where a polygon layer and a point layer are loaded from Geoserver through wfs service.
Each layer has a tooltip. When the two layers do not overlap the tooltips work as expected. When a point overlaps a polygon, in its position the tooltip of the polygon is shown. Unfortunately, for my purposes, when the two geometries overlap I want only the circle marker tooltip to be shown, that is exactly the opposite behavior than it is currently doing. It seems to be a kind of issue so impossible to solve for me.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1,user-scalable=no,maximum-scale=1,width=device-width">
<title>Example Leaflet</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.3/dist/leaflet.css">
</head>
<style>
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
</style>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet#1.0.3/dist/leaflet.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
var map = new L.Map('map');
var OSM = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {attribution: '© OpenStreetMap contributors'}).addTo(map);
var myRenderer = L.canvas({padding: 0.5});
var dataset = new L.layerGroup().addTo(map);
$.ajax({
url: 'http://46.101.36.208:8080/geoserver/ows?service=WFS&version=2.0&request=GetFeature&typeName=deep_map:point_tooltip_test&outputFormat=text/javascript&format_options=callback:getJson1&SrsName=EPSG:4326&MaxFeatures=200',
dataType: 'jsonp',
jsonpCallback: 'getJson1',
success: function(response) {
WFSLayer1 = L.geoJson(response, {
style: function(feature) {
return {
color: '#696969'
};
},
pointToLayer: function (feature, latlng) {
return L.circleMarker(latlng, {
renderer: myRenderer
});
},
onEachFeature: function(feature, layer) {
var popupText = '';
if (feature.properties.NOMECOMUNE) {
popupText += "<b>NOMECOMUNE: </b>" + feature.properties.NOMECOMUNE + "<br />";
}
if (feature.properties.CIVICO) {
popupText += "<b>CIVICO: </b>" + feature.properties.CIVICO + "<br />";
}
layer.bindTooltip(popupText, {'sticky': true});
}
}).addTo(dataset);
// map.fitBounds(WFSLayer1.getBounds());
}
});
$.ajax({
url: 'http://46.101.36.208:8080/geoserver/ows?service=WFS&version=2.0&request=GetFeature&typeName=deep_map:polygon_tooltip_test&outputFormat=text/javascript&format_options=callback:getJson2&SrsName=EPSG:4326&MaxFeatures=200',
dataType: 'jsonp',
jsonpCallback: 'getJson2',
success: function(response) {
WFSLayer2 = L.geoJson(response, {
style: function(feature) {
return {
stroke: true,
fillOpacity: 0
};
},
onEachFeature: function(feature, layer) {
var popupText = '';
if (feature.properties.NOMECOMUNE) {
popupText += "<b>NOMECOMUNE: </b>" + feature.properties.NOMECOMUNE + "<br />";
}
if (feature.properties.ZONA) {
popupText += "<b>TIPO ZONA: </b>" + feature.properties.ZONA + "<br />";
}
if (feature.properties.DEN_FI) {
popupText += "<b>AREA DI RISPETTO: </b>" + feature.properties.DEN_FI + "<br />";
}
if (feature.properties.TR_VINC) {
popupText += "<b>TRATTO VINCOLATO: </b>" + feature.properties.TR_VINC + "<br />";
}
if (feature.properties.DESCRIZION) {
popupText += "<b>CATEGORIA FORESTALE: </b>" + feature.properties.DESCRIZION + "<br />";
}
if (feature.properties.GIARDINI) {
popupText += "<b>PRESENZA GIARDINI: </b>" + feature.properties.GIARDINI + "<br />";
}
if (feature.properties.STAB_INDUS) {
popupText += "<b>STABILIMENTO A RISCHIO INCIDENTE GRAVE: </b>" + feature.properties.STAB_INDUS + "<br />";
}
if (feature.properties.CHANGETYPE) {
popupText += "<b>VARIAZIONI: </b>" + feature.properties.CHANGETYPE + "<br />";
}
layer.bindTooltip(popupText, {'sticky': true});
}
}).addTo(map);
map.fitBounds(WFSLayer2.getBounds());
}
});
map.on('zoomend', function() {
if (map.getZoom() < 16){
map.removeLayer(dataset);
}
else {
map.addLayer(dataset);
}
});
var BaseMap = {
"Base map": map
};
L.control.layers(BaseMap).addTo(map);
</script>
</html>
What I tried
I tried to create two explicit separate panes for each layer as follow:
map.createPane("polygonsPane");
map.createPane("pointsPane");
map.getPane('pointsPane').style.zIndex = 750;
map.getPane('polygonsPane').style.zIndex = 350;
Then I assigned each layer to its pane inside the style section.
For the polygon layer:
style: function(feature) {
return {
stroke: true,
fillOpacity: 1,
pane: "polygonsPane"
};
},
And for the point layer:
style: function(feature) {
return {
stroke: true,
fillOpacity: 1,
pane: "pointsPane"
};
},
With this, I was able to bring the points to the front and to make the tooltip work. Unfortunately, the tooltip for the polygon doesn't show anymore!
I'm very new to Leaflet. I'm sure I'm missing something obvious but I've been racking my brain trying to see what I'm missing. I would really appreciate it if anyone is able to give me a workaround.
Thank you very much.

leaflet .bindPopup() not working after page change

I am working on leaflet map and showing markers on it. on click of marker I am opening the popup and on click of that navigating it to another page, this all works fine but when I click back from the navigated page to map then the .bindPopup() is not working and I am not able to open the popup again.
here is my code:
var marker = leaflet.circleMarker([marker.latitude, marker.longitude], { renderer, radius: 8, weight: 1, color: '#fff', fillColor: markerColor, fillOpacity: 1 })
.addTo(this.map)
.bindPopup(marker.id + '<br/>' + marker.status + '<br/>');
marker.on('click', (e) => {
var popup = e.target.getPopup();
this.issueServiceProvider.getIssue(marker.id, false).subscribe((result) => {
var div = leaflet.DomUtil.create('div', 'command');
div.innerHTML = marker.id + '<br/>' + marker.status + '<br/>' + result.description + '<br/><a id = "command">More Details</a> <br/>';
popup.setContent(div);
leaflet.DomEvent.addListener(div, 'click', () => {
this.navCtrl.push(Constants.Page.IssueDetails, { markerId: marker.id }, Constants.Animation['TransitionForward']);
});
}, (err) => {
console.error('Error' + err);
});
});
How could I make it work?
This popup works, but does not reference your specific function. Try this and then add your function call once the basic setup is complete.
var marker = leaflet.circleMarker([39, -105], { radius: 8, weight: 1, color: "#274FCA", fillOpacity: 1 })
.addTo(map)
.bindPopup(this.id + '<br/>' + this.status + '<br/>');
marker.on('click', (e) => {
var popup = e.target.getPopup();
var div = L.DomUtil.create('div', 'command');
div.innerHTML = 'marker.id' + '<br/>' + 'marker.status' + '<br/>' + 'result.description' + '<br/><a id = "command">More Details</a> <br/>';
popup.setContent(div);
leaflet.DomEvent.addListener(div, 'click', () => {
this.navCtrl.push(Constants.Page.IssueDetails, { markerId: marker.id }, Constants.Animation['TransitionForward']);
});
});

Tinymce multiple instances in same page

I am using tinymce multiple instances in same page. When I try to insert image, I can but it will be added always in last text area fields( I have same 10 textarea with different name and id).
Html
<div class="admin__field field field-options_options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_1 with-note">
<label class="label admin__field-label" for="options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_1" data-ui-id="adminhtml-widget-form-field-wysiwygeditor-0-text-parameters-content-1-label"><span>Content 1</span></label>
<div class="admin__field-control control">
<textarea id="options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_13662927431522736609" name="parameters[content_1]" class="textarea admin__control-textarea wysiwyg-editor" rows="5" cols="15" data-ui-id="product-tabs-attributes-tab-fieldset-element-textarea-parameters[content_1]" aria-hidden="true"></textarea>
<button id="id_5abf1b8e544f38a8ca21aa8815613abd" title="WYSIWYG Editor" type="button" class="action-default scalable action-wysiwyg hidden" onclick="basewidgetWysiwygEditor.open('http://cei-shop.local/admin/catalog/product/wysiwyg/key/0367c4936326c7be6bf0fda5c407d274c1f3e4a9922173f53b72e75411d13406/', 'options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_13662927431522736609')" data-ui-id="widget-button-0">
<span>WYSIWYG Editor</span>
</button>
<button type="button" class="scalable action-show-hide" style="" id="toggleoptions_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_13662927431522736609"><span><span><span>Show / Hide Editor</span></span></span></button>
</div>
</div>
<div class="admin__field field field-options_options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_2 with-note">
<label class="label admin__field-label" for="options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_2" data-ui-id="adminhtml-widget-form-field-wysiwygeditor-1-text-parameters-content-2-label"><span>Content 2</span></label>
<div class="admin__field-control control">
<textarea id="options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_26925735391522736609" name="parameters[content_2]" class="textarea admin__control-textarea wysiwyg-editor" rows="5" cols="15" data-ui-id="product-tabs-attributes-tab-fieldset-element-textarea-parameters[content_2]" aria-hidden="true"></textarea>
<button id="id_504c308d5e46c342e202e961e97b2904" title="WYSIWYG Editor" type="button" class="action-default scalable action-wysiwyg hidden" onclick="basewidgetWysiwygEditor.open('http://cei-shop.local/admin/catalog/product/wysiwyg/key/0367c4936326c7be6bf0fda5c407d274c1f3e4a9922173f53b72e75411d13406/', 'options_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_26925735391522736609')" data-ui-id="widget-button-1">
<span>WYSIWYG Editor</span>
</button>
<button type="button" class="scalable action-show-hide" style="" id="toggleoptions_fieldset3ad06b8f111bff0225b3ee56e2a93cc4_content_26925735391522736609"><span><span><span>Show / Hide Editor</span></span></span></button>
</div>
</div>
setup.js
define([
'jquery',
'underscore',
'tinymce',
'mage/adminhtml/wysiwyg/tiny_mce/html5-schema',
'mage/translate',
'prototype',
'mage/adminhtml/events',
'mage/adminhtml/browser'
], function(jQuery, _, tinyMCE, html5Schema) {
vesBaseTinyMceWysiwygSetup = Class.create();
vesBaseTinyMceWysiwygSetup.prototype = {
mediaBrowserOpener: null,
mediaBrowserTargetElementId: null,
initialize: function(htmlId, config) {
if (config.baseStaticUrl && config.baseStaticDefaultUrl) {
tinyMCE.baseURL = tinyMCE.baseURL.replace(config.baseStaticUrl, config.baseStaticDefaultUrl);
}
this.id = htmlId;
this.config = config;
this.schema = config.schema || html5Schema;
_.bindAll(this, 'beforeSetContent', 'saveContent', 'onChangeContent', 'openFileBrowser', 'updateTextArea');
varienGlobalEvents.attachEventHandler('tinymceChange', this.onChangeContent);
varienGlobalEvents.attachEventHandler('tinymceBeforeSetContent', this.beforeSetContent);
varienGlobalEvents.attachEventHandler('tinymceSaveContent', this.saveContent);
if (typeof tinyMceEditors == 'undefined') {
tinyMceEditors = $H({});
}
tinyMceEditors.set(this.id, this);
},
setup: function(mode) {
if (this.config.widget_plugin_src) {
tinyMCE.PluginManager.load('magentowidget', this.config.widget_plugin_src);
}
if (this.config.plugins) {
this.config.plugins.each(function(plugin) {
tinyMCE.PluginManager.load(plugin.name, plugin.src);
});
}
if (jQuery.isReady) {
tinyMCE.dom.Event.domLoaded = true;
}
tinyMCE.init(this.getSettings(mode));
},
getSettings: function(mode) {
var plugins = 'inlinepopups,safari,pagebreak,style,layer,table,advhr,advimage,emotions,iespell,media,searchreplace,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras',
self = this;
if (this.config.widget_plugin_src) {
plugins = 'magentowidget,' + plugins;
}
var magentoPluginsOptions = $H({});
var magentoPlugins = '';
if (this.config.plugins) {
this.config.plugins.each(function(plugin) {
magentoPlugins = plugin.name + ',' + magentoPlugins;
magentoPluginsOptions.set(plugin.name, plugin.options);
});
if (magentoPlugins) {
plugins = '-' + magentoPlugins + plugins;
}
}
var settings = {
mode: (mode != undefined ? mode : 'none'),
elements: this.id,
theme: 'advanced',
plugins: plugins,
theme_advanced_buttons1: magentoPlugins + 'magentowidget,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect',
theme_advanced_buttons2: 'cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,forecolor,backcolor',
theme_advanced_buttons3: 'tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,iespell,media,advhr,|,ltr,rtl,|,fullscreen',
theme_advanced_buttons4: 'insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,pagebreak',
theme_advanced_toolbar_location: 'top',
theme_advanced_toolbar_align: 'left',
theme_advanced_statusbar_location: 'bottom',
theme_advanced_resizing: true,
theme_advanced_resize_horizontal: false,
convert_urls: false,
relative_urls: false,
content_css: this.config.content_css,
custom_popup_css: this.config.popup_css,
magentowidget_url: this.config.widget_window_url,
magentoPluginsOptions: magentoPluginsOptions,
doctype: '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
setup: function(ed){
ed.onInit.add(self.onEditorInit.bind(self));
ed.onSubmit.add(function(ed, e) {
varienGlobalEvents.fireEvent('tinymceSubmit', e);
});
ed.onPaste.add(function(ed, e, o) {
varienGlobalEvents.fireEvent('tinymcePaste', o);
});
ed.onBeforeSetContent.add(function(ed, o) {
varienGlobalEvents.fireEvent('tinymceBeforeSetContent', o);
});
ed.onSetContent.add(function(ed, o) {
varienGlobalEvents.fireEvent('tinymceSetContent', o);
});
ed.onSaveContent.add(function(ed, o) {
varienGlobalEvents.fireEvent('tinymceSaveContent', o);
});
var onChange = function(ed, l) {
varienGlobalEvents.fireEvent('tinymceChange', l);
};
ed.onChange.add(onChange);
ed.onKeyUp.add(onChange);
ed.onExecCommand.add(function(ed, cmd, ui, val) {
varienGlobalEvents.fireEvent('tinymceExecCommand', cmd);
});
}
};
// Set the document base URL
if (this.config.document_base_url) {
settings.document_base_url = this.config.document_base_url;
}
if (this.config.files_browser_window_url) {
settings.file_browser_callback = function(fieldName, url, objectType, w) {
varienGlobalEvents.fireEvent("open_browser_callback", {
win: w,
type: objectType,
field: fieldName
});
};
}
if (this.config.width) {
settings.width = this.config.width;
}
if (this.config.height) {
settings.height = this.config.height;
}
if (this.config.settings) {
Object.extend(settings, this.config.settings)
}
return settings;
},
applySchema: function (editor) {
var schema = editor.schema,
schemaData = this.schema,
makeMap = tinyMCE.makeMap;
jQuery.extend(true, {
nonEmpty: schema.getNonEmptyElements(),
boolAttrs: schema.getBoolAttrs(),
whiteSpace: schema.getWhiteSpaceElements(),
shortEnded: schema.getShortEndedElements(),
selfClosing: schema.getSelfClosingElements(),
blockElements: schema.getBlockElements()
}, {
nonEmpty: makeMap(schemaData.nonEmpty),
boolAttrs: makeMap(schemaData.boolAttrs),
whiteSpace: makeMap(schemaData.whiteSpace),
shortEnded: makeMap(schemaData.shortEnded),
selfClosing: makeMap(schemaData.selfClosing),
blockElements: makeMap(schemaData.blockElements)
});
},
openFileBrowser: function(o) {
//console.log(o.win.tinyMCE.activeEditor.editorId);
var typeTitle,
storeId = this.config.store_id !== null ? this.config.store_id : 0,
frameDialog = jQuery(o.win.frameElement).parents('[role="dialog"]'),
wUrl = this.config.files_browser_window_url +
'target_element_id/' + this.id + '/' +
'store/' + storeId + '/';
this.mediaBrowserOpener = o.win;
this.mediaBrowserTargetElementId = o.field;
if (typeof(o.type) != 'undefined' && o.type != "") {
typeTitle = 'image' == o.type ? this.translate('Insert Image...') : this.translate('Insert Media...');
wUrl = wUrl + "type/" + o.type + "/";
} else {
typeTitle = this.translate('Insert File...');
}
frameDialog = jQuery('[role="dialog"]');
frameDialog.hide();
jQuery('#mceModalBlocker').hide();
MediabrowserUtility.openDialog(wUrl, false, false, typeTitle, {
closed: function() {
jQuery(document).find('[role="dialog"]').show();
jQuery('#mceModalBlocker').show();
}
});
},
translate: function(string) {
return jQuery.mage.__ ? jQuery.mage.__(string) : string;
},
getMediaBrowserOpener: function() {
return this.mediaBrowserOpener;
},
getMediaBrowserTargetElementId: function() {
return this.mediaBrowserTargetElementId;
},
getToggleButton: function() {
return $('toggle' + this.id);
},
getPluginButtons: function() {
return $$('#buttons' + this.id + ' > button.plugin');
},
turnOn: function(mode) {
this.closePopups();
this.setup(mode);
tinyMCE.execCommand('mceAddControl', false, this.id);
this.getPluginButtons().each(function(e) {
e.hide();
});
return this;
},
turnOff: function() {
this.closePopups();
tinyMCE.execCommand('mceRemoveControl', false, this.id);
this.getPluginButtons().each(function(e) {
e.show();
});
return this;
},
closePopups: function() {
if (typeof closeEditorPopup == 'function') {
// close all popups to avoid problems with updating parent content area
closeEditorPopup('widget_window' + this.id);
closeEditorPopup('browser_window' + this.id);
}
},
toggle: function() {
if (!tinyMCE.get(this.id)) {
this.turnOn();
return true;
} else {
this.turnOff();
return false;
}
},
onEditorInit: function (editor) {
this.applySchema(editor);
},
onFormValidation: function() {
if (tinyMCE.get(this.id)) {
$(this.id).value = tinyMCE.get(this.id).getContent();
}
},
onChangeContent: function() {
// Add "changed" to tab class if it exists
if (tinyMCE.get(this.id)) {
jQuery('#' + this.id).val(tinyMCE.get(this.id).getContent()).trigger('change');
}
if (this.config.tab_id) {
var tab = $$('a[id$=' + this.config.tab_id + ']')[0];
if ($(tab) != undefined && $(tab).hasClassName('tab-item-link')) {
$(tab).addClassName('changed');
}
}
},
// retrieve directives URL with substituted directive value
makeDirectiveUrl: function(directive) {
return this.config.directives_url.replace('directive', 'directive/___directive/' + directive);
},
encodeDirectives: function(content) {
// collect all HTML tags with attributes that contain directives
return content.gsub(/<([a-z0-9\-\_]+.+?)([a-z0-9\-\_]+=".*?\{\{.+?\}\}.*?".+?)>/i, function(match) {
var attributesString = match[2];
// process tag attributes string
attributesString = attributesString.gsub(/([a-z0-9\-\_]+)="(.*?)(\{\{.+?\}\})(.*?)"/i, function(m) {
return m[1] + '="' + m[2] + this.makeDirectiveUrl(Base64.mageEncode(m[3])) + m[4] + '"';
}.bind(this));
return '<' + match[1] + attributesString + '>';
}.bind(this));
},
encodeWidgets: function(content) {
return content.gsub(/\{\{widget(.*?)\}\}/i, function(match) {
var attributes = this.parseAttributesString(match[1]);
if (attributes.type) {
attributes.type = attributes.type.replace(/\\\\/g, "\\");
var imageSrc = this.config.widget_placeholders[attributes.type];
var imageHtml = '<img';
imageHtml += ' id="' + Base64.idEncode(match[0]) + '"';
imageHtml += ' src="' + imageSrc + '"';
imageHtml += ' title="' + match[0].replace(/\{\{/g, '{').replace(/\}\}/g, '}').replace(/\"/g, '"') + '"';
imageHtml += '>';
return imageHtml;
}
}.bind(this));
},
decodeDirectives: function(content) {
// escape special chars in directives url to use it in regular expression
var url = this.makeDirectiveUrl('%directive%').replace(/([$^.?*!+:=()\[\]{}|\\])/g, '\\$1');
var reg = new RegExp(url.replace('%directive%', '([a-zA-Z0-9,_-]+)'));
return content.gsub(reg, function(match) {
return Base64.mageDecode(match[1]);
}.bind(this));
},
decodeWidgets: function(content) {
return content.gsub(/<img([^>]+id=\"[^>]+)>/i, function(match) {
var attributes = this.parseAttributesString(match[1]);
if (attributes.id) {
var widgetCode = Base64.idDecode(attributes.id);
if (widgetCode.indexOf('{{widget') != -1) {
return widgetCode;
}
return match[0];
}
return match[0];
}.bind(this));
},
parseAttributesString: function(attributes) {
var result = {};
attributes.gsub(/(\w+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/, function(match) {
result[match[1]] = match[2];
});
return result;
},
updateTextArea: function () {
var editor = tinyMCE.get(this.id),
content;
if (!editor) {
return;
}
content = editor.getContent();
content = this.decodeContent(content);
jQuery('#' + this.id).val(content).trigger('change');
},
decodeContent: function (content) {
var result = content;
if (this.config.add_widgets) {
result = this.decodeWidgets(result);
result = this.decodeDirectives(result);
} else if (this.config.add_directives) {
result = this.decodeDirectives(result);
}
if(result!=''){
result = result.replace(/ /g, ' ');
}
return result;
},
encodeContent: function (content) {
var result = content;
if (this.config.add_widgets) {
result = this.encodeWidgets(result);
result = this.encodeDirectives(result);
} else if (this.config.add_directives) {
result = this.encodeDirectives(result);
}
return result;
},
beforeSetContent: function(o){
o.content = this.encodeContent(o.content);
},
saveContent: function(o) {
o.content = this.decodeContent(o.content);
}
};
});

Mapbox autocomplete

I'm trying to implement Mapbox on my website.
I would like to add on my home page, an autocomplete field.
I know I can add it to the map, but I would like to know if I can use a separated input field to get the job done ?
I've not found anything on the Mapbox documentation.
Can someone help me with this ?
Thanks.
The mapbox team has done a good job in showing an example of it in Geocoder
And regarding your query: Yes, you can use your own input field. What you have to do is listen for every keyboard input as shown in this. Take that value as the query parameter and then make the API request as done in search.js and then display the suggestions returned by the API.
If you are using React, then you could very well, use the same code and just modify the styles for your input.
For placement of the input box
If you are using leafletjs, then you can add this input as a control
else, if you are using mapbox-gl-js, then you can add it as its specific control. The Control API has only fixed positions such as top-right, top-left, bottom etc. If this is not your intended positioning, then you can just place it as a simple div overlay.
AUTCOMPLETE SUGGESTION INPUT BOX WITH MAPBOX API
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Add a geocoder</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
<script src="https://code.jquery.com/jquery-3.4.1.js" type="text/javascript"></script>
<script src="https://unpkg.com/#mapbox/mapbox-sdk/umd/mapbox-sdk.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
box-sizing: border-box;
}
body {
font: 16px Arial;
}
/*the container must be positioned relative:*/
.autocomplete {
position: relative;
display: inline-block;
}
input {
border: 1px solid transparent;
background-color: #f1f1f1;
padding: 10px;
font-size: 16px;
}
input[type=text] {
background-color: #f1f1f1;
width: 100%;
}
input[type=submit] {
background-color: DodgerBlue;
color: #fff;
cursor: pointer;
}
.autocomplete-items {
position: absolute;
border: 1px solid #d4d4d4;
border-bottom: none;
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
}
.autocomplete-items div {
padding: 10px;
cursor: pointer;
background-color: #fff;
border-bottom: 1px solid #d4d4d4;
}
/*when hovering an item:*/
.autocomplete-items div:hover {
background-color: #e9e9e9;
}
/*when navigating through the items using the arrow keys:*/
.autocomplete-active {
background-color: DodgerBlue !important;
color: #ffffff;
}
</style>
</head>
<body>
<h2>Autocomplete</h2>
<p>Start typing:</p>
<!--Make sure the form has the autocomplete function switched off:-->
<form autocomplete="off" action="/action_page.php">
<div class="autocomplete" style="width:300px;">
<input id="myInput" type="text" name="myCountry" placeholder="Country">
</div>
<input type="submit">
</form>
<script>
var geocodingClient = mapboxSdk({accessToken: 'ADD_ACCESS_TOKEN_HERE'});
function autocompleteSuggestionMapBoxAPI(inputParams, callback) {
geocodingClient.geocoding.forwardGeocode({
query: inputParams,
countries: ['In'],
autocomplete: true,
limit: 5,
})
.send()
.then(response => {
const match = response.body;
callback(match);
});
}
function autocompleteInputBox(inp) {
var currentFocus;
inp.addEventListener("input", function (e) {
var a, b, i, val = this.value;
closeAllLists();
if (!val) {
return false;
}
currentFocus = -1;
a = document.createElement("DIV");
a.setAttribute("id", this.id + "autocomplete-list");
a.setAttribute("class", "autocomplete-items");
this.parentNode.appendChild(a);
// suggestion list MapBox api called with callback
autocompleteSuggestionMapBoxAPI($('#myInput').val(), function (results) {
results.features.forEach(function (key) {
b = document.createElement("DIV");
b.innerHTML = "<strong>" + key.place_name.substr(0, val.length) + "</strong>";
b.innerHTML += key.place_name.substr(val.length);
b.innerHTML += "<input type='hidden' data-lat='" + key.geometry.coordinates[1] + "' data-lng='" + key.geometry.coordinates[0] + "' value='" + key.place_name + "'>";
b.addEventListener("click", function (e) {
let lat = $(this).find('input').attr('data-lat');
let long = $(this).find('input').attr('data-lng');
inp.value = $(this).find('input').val();
$(inp).attr('data-lat', lat);
$(inp).attr('data-lng', long);
closeAllLists();
});
a.appendChild(b);
});
})
});
/*execute a function presses a key on the keyboard:*/
inp.addEventListener("keydown", function (e) {
var x = document.getElementById(this.id + "autocomplete-list");
if (x) x = x.getElementsByTagName("div");
if (e.keyCode == 40) {
/*If the arrow DOWN key is pressed,
increase the currentFocus variable:*/
currentFocus++;
/*and and make the current item more visible:*/
addActive(x);
} else if (e.keyCode == 38) { //up
/*If the arrow UP key is pressed,
decrease the currentFocus variable:*/
currentFocus--;
/*and and make the current item more visible:*/
addActive(x);
} else if (e.keyCode == 13) {
/*If the ENTER key is pressed, prevent the form from being submitted,*/
e.preventDefault();
if (currentFocus > -1) {
/*and simulate a click on the "active" item:*/
if (x) x[currentFocus].click();
}
}
});
function addActive(x) {
/*a function to classify an item as "active":*/
if (!x) return false;
/*start by removing the "active" class on all items:*/
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = (x.length - 1);
/*add class "autocomplete-active":*/
x[currentFocus].classList.add("autocomplete-active");
}
function removeActive(x) {
/*a function to remove the "active" class from all autocomplete items:*/
for (var i = 0; i < x.length; i++) {
x[i].classList.remove("autocomplete-active");
}
}
function closeAllLists(elmnt) {
/*close all autocomplete lists in the document,
except the one passed as an argument:*/
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt != x[i] && elmnt != inp) {
x[i].parentNode.removeChild(x[i]);
}
}
}
/*execute a function when someone clicks in the document:*/
document.addEventListener("click", function (e) {
closeAllLists(e.target);
});
}
autocompleteInputBox(document.getElementById("myInput"));
</script>
</body>
</html>
I've created something similar to this- separated from Mapbox. My use case involved taking a .csv file from a client and converting it to json format, then I bind map markers using leaflet.js. I'm then using the json file and an autocomplete plugin to query the json dataset to output info about the city, state on the map. Here's the code and codepen to follow:
var parseData = function () {
return {
mapMarkersInit: function () {
// Define an icon called cssIcon
var cssIcon = L.divIcon({
// Specify a class name we can refer to in CSS.
className: 'css-icon',
// Set marker width and height
iconAnchor: [5, 5],
iconSize: [10, 10]
});
//console.log(placesData);
placesData.forEach(function (place) {
L.marker([place.Latitude, place.Longitude], {icon: cssIcon}).addTo(mymap)
.bindPopup('<div class="active-place" data-active="' + place.City + '">City: ' + place.State + '<br>' +
'Population: ' + place.Population.toLocaleString() + '<br>' +
'# of Plans: ' + place.Sum + '<br>' +
'401(k) Plans per person: ' + Math.round(place.PerCapita) + '</div>');
});
},
selectCitiesInit: function () {
//map through data and return options
var cityData = placesData.map(function (place) {
return '<option name="selectCountry" data-active="' + place.City + '" value="' +
place.State + '">' + place.State + '</option>';
});
//take array of city data and string-ify it
var options = cityData.join('');
//console.log(options);
//print select options to page
jQuery('#input-city').append(options);
},
selectChange: function () {
//get user input city
var city = jQuery(this).val();
//Prefered method to use with data objects. Finds the match and exits the dataset.
var place = placesData.find(function (item) {
return (item.State == city);
});
//Best practice- deal with error first, returns out of function if error
if (!place) {
jQuery('#place-data').html('error! city not found');
return;
}
//now create html from data
var cityData = '<div class="active-place" data-active="' + place.City + '">' +
'<h2> ' + place.State + '</h2> | ' +
'<h4>Population: ' + place.Population.toLocaleString() + '</h4> | ' +
'<h4># of Plans: ' + place.Sum + '</h4> | ' +
'<h4>401(k) Plans per person: ' + Math.round(place.PerCapita) + '</h4></div>';
//print city data
jQuery('#place-data').html(cityData);
}
}
};
View example on codepen