Bootstrap input field inside tooltip popover removed from output html - input

Hello i`m using boostrap 4.3.1 and included popper 1.14.7.
Normally I can add input fields in the content of the popup/tooltip. I don`t since when, but at the moment when I put input field in the content then only the text is visible.
When I look in the source (compiled html) I can see that popper or bootstrap removed the input fields. Do I something wrong?
var options = {
html: true,
// content: function(){ return $(".amountElec.popup").html();},
placement: "bottom",
container: "body"
};
$(function(){
$('#manualinput').popover(options);
})
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<div id="manualinput"
data-container="body"
data-toggle="popover"
data-content="test <input name='test' type='text' value='2'>"
data-html="true"
data-placement="bottom">
OPEN TOOLTUP
</div>

It's even easier as you think:
Add
sanitize: false
as config option if you want to disable sanitize at all. If you just want to adapt the whitelist, you are right with your solution
https://github.com/twbs/bootstrap/blob/438e01b61c935409adca29cde3dbb66dd119eefd/js/src/tooltip.js#L472

I found the solution...
I my case add this to the javascript:
var myDefaultWhiteList = $.fn.tooltip.Constructor.Default.whiteList;
myDefaultWhiteList.input = [];
https://getbootstrap.com/docs/4.3/getting-started/javascript/#sanitizer

After searching in the debug console I found somehting in the tooltip.js from bootstrap.
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn)
setElementContent($element, content) {
if (typeof content === 'object' && (content.nodeType || content.jquery)) {
// Content is a DOM node or a jQuery
if (this.config.html) {
if (!$(content).parent().is($element)) {
$element.empty().append(content)
}
} else {
$element.text($(content).text())
}
return
}
if (this.config.html) {
if (this.config.sanitize) {
content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn)
}
$element.html(content)
} else {
$element.text(content)
}
}
sanitizeHtml function removes the input fields :(.

I just turned of sanitize by default (globally):
$.fn.tooltip.Constructor.DEFAULTS.sanitize = false;
$.fn.popover.Constructor.DEFAULTS.sanitize = false;
https://getbootstrap.com/docs/3.4/javascript/#default-settings

Related

Unable to use Lazy load + Dynamic image manipulation Cloudinary

I am unable to use the feature Cloudinary Lazyload + Dynamic image manipulation both at the same time.
Is there any trick to use both the function at the same time?
I am using an HTML website.
My code is
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/cloudinary-core#latest/cloudinary-core-shrinkwrap.js"></script>
<script type="text/javascript">
var cl = cloudinary.Cloudinary.new({cloud_name: "syg"});
// replace 'demo' with your cloud name in the line above
cl.responsive();
</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
const imageObserver = new IntersectionObserver((entries, imgObserver) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const lazyImage = entry.target
console.log("lazy loading ", lazyImage)
lazyImage.src = lazyImage.dataset.src
}
})
});
const arr = document.querySelectorAll('img.lzy_img')
arr.forEach((v) => {
imageObserver.observe(v);
})
})
</script>
<img class="cld-responsive lzy_img" data-src="https://res.cloudinary.com/syg/image/upload/w_auto,c_scale/sample.jpg" />
The responsive script will apply the relevant width value and replace w_auto in the URL based on the container size.
Since your code does not limit the <img> container, it applies the max width size of the screen.
For testing purposes, you can wrap your <img> element with <div style="width:50%;"></div> and you will see that the image URL adjusts the width transformation accordingly:
<div style="width:50%;">
<img class="cld-responsive lzy_img" data-src="https://res.cloudinary.com/syg/image/upload/w_auto,c_scale/v346346/sample.jpg"/>
</div>
In addition, you can take a look at the following broader implementation of LQIP+Lazy Loading+Responsive with Cloudinary for reference and ideas on how to implement these features within your site's pages.

dojo Grid renderCell Textarea

I'm trying to create a grid from json data. Each cell will be editable eventually. One column contains type dependant data and based on the type I want to show either a pair of date pickers (start/end date) or Textarea or some other widget.
I'm using renderCell to attempt to render this type dependent column, but whenever I introduce Textarea to my code I get an error "TypeError: subRows is undefined" & just can't seem to shake it.
I'm quite new to dojo so I think I'm missing something obvious. I've read all the docs and in particular this post which didn't help in my case. Unfortunately many of the docs are slices of code & whatever it is I'm not getting means those code slices are too short to get started with.
Can someone help me out. Textarea is the one I'd like to solve as that seems simple & I've not attempted to configure the DateTextBox properly yet anyway. I figure get the Textarea working & that will explain the rest...
My code is below - whole page posted in case my error is missing a file somewhere;
<html>
<head>
<meta charset="utf-8">
<title>Role assignment</title>
<link rel="stylesheet" href="/library/js/dojo/dojo/resources/dojo.css">
<link rel="stylesheet" href="/library/js/dojo/dgrid/css/dgrid.css">
<link rel="stylesheet" href="/library/js/dojo/dgrid/css/skins/claro.css">
<link rel="stylesheet" href="/library/js/dojo/dijit/themes/dijit.css">
<LINK href="/library/css/custom.css" type="text/css" rel="stylesheet">
<LINK href="/favicon.ico" rel="shortcut icon" type="image/x-icon">
<script type="text/javascript" language="javascript" src="/library/js/script_main.js"></script>
</head>
<body class="claro">
<form>
<div id="grid"></div>
</form>
<!-- load Dojo -->
<script src="/library/js/dojo/dojo/dojo.js"></script>
<script>
require([
'dojo/_base/declare',
'dgrid/Grid',
"dgrid/Selection",
"dgrid/editor",
"dgrid/Keyboard",
"dijit/form/Button",
"dijit/form/Textarea",
"dijit/form/DateTextBox",
"dojo/domReady!"
], function (declare, Grid, Selection, editor, Keyboard, Button, Textarea, DateTextBox) {
var renderRoleData = function(object, value, node, options) {
if (object.role_type == "TIME_RANGE") {
return new DateTextBox();
// no attempt to initialise this yet
}
else if (object.role_type == "MULTI_STRING") {
return new Textarea({
name: "myarea",
value: object.role_data.text,
style: "width:200px;"
});
}
//....more types
}
var columns = [
{
field: 'role_name',
label: 'Role name'
},
{
field: 'role_type',
label: 'Role type'
},
{
field: 'role_enabled',
label: 'Role enabled'
},
{
field: 'role_data',
label: 'Role data',
renderCell: renderRoleData
}
];
var grid = new (declare([ Grid, Selection, editor, Keyboard, Textarea, DateTextBox ]))({
columns: columns,
postCreate: function() {
var data = [
{
"role_dn": "some_ldap_dn1,dc=com",
"role_name": "Water Controller",
"role_type": "TIME_RANGE",
"role_enabled" : true,
"role_data" : {"start_date" : "20150601", "end_date" : "20150701"}
}, {
"role_dn": "some_ldap_dn1,dc=com",
"role_name": "Waste Controller",
"role_type": "MULTI_STRING",
"role_enabled" : true,
"role_data" : { "text": "The reason I need this is very long and complicated. The big long reason is just big and long and honestly you wouldn't care if I told you anwyay" }
}
];
this.renderArray(data);
}
}, 'grid');
});
</script>
</body>
</html>
Initially, I notice a few issues which might be causing this problem. Try the following instead:
// Dijit widgets should not be mixed into the grid with declare.
// If you're using 0.3, editor should not be mixed in either,
// intended to be applied to specific columns (in 0.4 this is now a mixin).
// Only dgrid mixins should be mixed in via declare.
var CustomGrid = declare([ Grid, Selection, Keyboard ], {
postCreate: function () {
// Call this.inherited to run any postCreate logic in
// previous mixins first
this.inherited(arguments);
var data = [
{
"role_dn": "some_ldap_dn1,dc=com",
"role_name": "Water Controller",
"role_type": "TIME_RANGE",
"role_enabled" : true,
"role_data" : {"start_date" : "20150601", "end_date" : "20150701"}
}, {
"role_dn": "some_ldap_dn1,dc=com",
"role_name": "Waste Controller",
"role_type": "MULTI_STRING",
"role_enabled" : true,
"role_data" : { "text": "The reason I need this is very long and complicated. The big long reason is just big and long and honestly you wouldn't care if I told you anwyay" }
}
];
this.renderArray(data);
}
});
var grid = new CustomGrid({
columns: columns
}, 'grid');
I removed things from the declare array that didn't belong in it, which may have been causing the problem.
Note that postCreate is now defined in an object passed straight to declare. This object's properties will be mixed in after the constructors in the array, as opposed to properties of the object passed to the constructor when instantiating, which will simply override those properties straight on the instance. This also gives it access to call this.inherited(arguments) which will run any previous mixins' postCreate function first.

Google Script for Uploading File Not Working

I wrote a script for uploading files to my Google Drive using the Google Script. I deployed it as a WebApp but it's not working and I don't know why. The button just gets stuck on "Subiendo..." and never changes anything inside my Drive. I'm sure I gave the script all the permissions and I already tried to see what's happening on my own without any sucess. Can you maybe help me find what should I do? I post the code here:
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('main').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function serverFunc(theForm) {
try{
var folder_name = "publicaciones";
var folder,folders = DriveApp.getFoldersByName(folder_name);
if(folders.hasNext()){
folder = folders.next();
}else{
folder = DriveApp.createFolder(folder_name);
}
Logger.log("TheForm", theForm == null);
var blob = theForm.theFile;
Logger.log("Blob!", blob == null);
var file = folder.createFile(blob);
Logger.log("File:", file.getName());
return "Archivo subido exitosamente: " + file.getUrl();
} catch(error){
Logger.log("error: ", error.toString());
return error.toString();
}
}
** main.html **
<div>
<form id="myForm">
<input type="file" name="theFile">
<input type="hidden" name="anExample">
<br>
<input type="button" value="Subir Archivo" onclick="this.value='Subiendo...';
google.script.run.withSuccessHandler(fileUploaded).serverFunc(this.parentNode);
return false;">
</form>
</div>
<div id="output">
</div>
<script>
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
I'd appreaciate any help or pointers you can give me. Thanks a lot!
Looks like there is a bug currently that Google is working on. I found a possible fix:
Change your input tag to this:
<input type="button" value="Subir Archivo" onclick="callServerCode()"/>
Add a function to the <script> tag:
<script>
function callServerCode() {
var formToSend = document.getElementById('myForm');
google.script.run
.withSuccessHandler(fileUploaded)
.serverFunc(formToSend);
};
function fileUploaded(status) {
document.getElementById('myForm').style.display = 'none';
document.getElementById('output').innerHTML = status;
}
</script>
Note that inside the new function, it gets the form using var formToSend = document.getElementById('myForm');
And change IFRAME to NATIVE.
It's a doc issue needs to fix with Google when using SandBoxMode=IFRAME currently. See here. I've tested it works by swapping IFRAME to NATIVE. You can simply do it:
function doGet() {
return HtmlService.createHtmlOutputFromFile('main');
}
Google has turned of NATIVE for SandBoxMode. It is now set to IFRAME only.
See here

Leaflet - updating a keyword search call to a restful api and refreshing map

My Question (UPDATED): How do I get my keyword to change in the API URL Search Query based off of an AJAX Call (having a scope problem here) ?
I connected a leaflet map to an an API to plot Wikipedia articles with geocoordinates. An example URL looks like: http://api.infochimps.com/encyclopedic/wikipedia/dbpedia/wikipedia_articles/search?g.radius=10000&g.latitude=30.3&g.longitude=-97.75&f.q=park&apikey=api_test-W1cipwpcdu9Cbd9pmm8D4Cjc469
So far so good. But I am stuck on how to implement an AJAX call that would allow the user to search for a new query term and reload the map. When I click the search box, the keyword alerts that the keyword is the text in the search box. But the map does not update based on the new keyword.
So I have as a JS script:
var map;
var pointsLayer;
var markerMap = {};
var keyword; //instantiating keyword for global scope
$(document).ready(function(){
map = new L.Map('mapContainer');
var url = 'http://{s}.tiles.mapbox.com/v3/mapbox.mapbox-streets/{z}/{x}/{y}.png';
var copyright = 'Map data © 2011 OpenStreetMap contributors, Imagery © 2011 CloudMade';
var tileLayer = new L.TileLayer(url, {attribution:copyright});
//var startPosition = new L.LatLng(42.33143, -83.04575);//detroit
var startPosition = new L.LatLng(41.883333, -87.633333);//chicago
//var startPosition = new L.LatLng(40.7143528, -74.0059731);//new york
map.on('load', function(){
keyword = 'history'; //setting keyword to history on first load
requestUpdatedPoints();
keyword = ''; //clearing keyword after first load
});
map.setView(startPosition, 13).addLayer(tileLayer);
map.on('moveend', function(){
requestUpdatedPoints();
});
//////////////
/// WRONG ADDITION OF ADDING KEYWORD SEARCH?
//////////////
$('a#submitSearch').on('click', function(e, keyword){
e.preventDefault();
//keyword = '';
keyword = $('input#keyword').val(); //setting keyword to whatever is in the search box
alert(keyword); //did it set it?
requestUpdatedPoints(keyword); //send in new AJAX call with new keyword
location.reload();
});
});
function requestUpdatedPoints(keyword){
$.ajax({
type: 'GET',
url: 'http://api.infochimps.com/encyclopedic/wikipedia/dbpedia/wikipedia_articles/search?g.radius=100000&g.latitude=41.883333&g.longitude=-87.633333&f.q='+this.keyword+'&apikey=api_test-W1cipwpcdu9Cbd9pmm8D4Cjc469',
dataType: 'jsonp',
//data: JSON.stringify(data),
contentType: 'application/json; charset=utf-8',
success: function(result){
for( var i=0; i<result.results.length - 1; i++ ){
console.log("adding " + result.results[i].wikipedia_id + " to the map")
var marker = L.marker([result.results[i].coordinates[1], result.results[i].coordinates[0]]).addTo(map);
marker.bindPopup(''+result.results[i].wikipedia_id+'');
}
},
error: function(){
alert('check your error log.');
}
});
}
the HTML is:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="./style.css">
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.4/leaflet.css">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cdn.leafletjs.com/leaflet-0.4/leaflet.js"></script>
<script type="text/javascript" src="./map.js"></script>
</head>
<body>
<h1>WikiMap</h1>
<div id="mapContainer"></div>
<div id="infoContainer">
<div id="search">
<form id="searchForm">
<label>Keyword:</label>
<input type="text" id="keyword" name="keyword" placeholder="search by keyword"/>
<a id="submitSearch" href="#">search</a>
</form>
</div>
</div>
</body>
</html>
My Question (UPDATED): How do I get my keyword to change in the API URL Search Query based off of an AJAX Call (having a scope problem here) ?
I've finally figured that my layout is poor for accomplishing what I want to get done. Even if the keyword is updating, the map.on() load function is reverting everything back to the beginning. I've decided to use Backbone.js to help me organize my data flows.
var searchControl = L.esri.Geocoding.Controls.geosearch({
providers: [
new L.esri.Geocoding.Controls.Geosearch.Providers.MapService({
label: 'States and Counties',
url: 'http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer',
layers: [2, 3],
searchFields: ['NAME', 'STATE_NAME']
})
]
}).addTo(map);
I am using leaflet map search api by address but I find an autosuggestion searching api something that.

How to show next/previous links in Google Custom Search Engine paging links

The Google Custom Search integration only includes numbered page links and I cannot find a way to include Next/Previous links like on a normal Google search. CSE used to include these links with their previous iframe integration method.
I stepped through the javascript and found the undocumented properties I was looking for.
<div id="cse" style="width: 100%;">Loading</div>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load('search', '1', {language : 'en'});
google.setOnLoadCallback(function() {
var customSearchControl = new google.search.CustomSearchControl('GOOGLEIDGOESHERE');
customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
customSearchControl.setSearchCompleteCallback(null,
function() { searchCompleteCallback(customSearchControl) });
customSearchControl.draw('cse');
}, true);
function searchCompleteCallback(customSearchControl) {
var currentPageIndex = customSearchControl.e[0].g.cursor.currentPageIndex;
if (currentPageIndex < customSearchControl.e[0].g.cursor.pages.length - 1) {
$('#cse .gsc-cursor').append('<div class="gsc-cursor-page">Next</div>').click(function() {
customSearchControl.e[0].g.gotoPage(currentPageIndex + 1);
});
}
if (currentPageIndex > 0) {
$($('#cse .gsc-cursor').prepend('<div class="gsc-cursor-page">Previous</div>').children()[0]).click(function() {
customSearchControl.e[0].g.gotoPage(currentPageIndex - 1);
});
}
window.scrollTo(0, 0);
}
</script>
<link rel="stylesheet" href="http://www.google.com/cse/style/look/default.css" type="text/css" />
I've been using this to find the current page:
ctrl.setSearchCompleteCallback(null, function(gControl, gResults)
{
currentpage = 1+gResults.cursor.currentPageIndex;
// or, here is an alternate way
currentpage = $('.gsc-cursor-current-page').text();
});
And now it's customSearchControl.k[0].g.cursor ... (as of this weekend, it seems)
Next time it stops working just go to script debugging in IE, add customSearchControl as a watch, open the properties (+), under the Type column look for Object, (Array) and make sure there is a (+) there as well (i.e. contains elements), open[0], and look for Type Object, again with child elements. Open that and once you see "cursor" in the list, you've got it.