I am working on an application with Django. There in this application, I am first using Django to create a database with points and extract a JSON file (It is called "markers.json"). Then, using this JSON file, I am creating markers on a map with Leaflet. When I finished entering all the points to the database they will be around 5000 thousand. So, I decided that it is a good idea to be able to search this markers with an input tag and a search button. I enter the "site_name" as input and when I click the "search" button the related marker should popup. However, always the same marker pops up and I don't know where I am doing wrong.
Could you please help me on that?
HTML PART
<input type="text" id="mast_find" name="mastName" placeholder="Search or masts...">
<button type="submit" id="mast_button">Search</button>
JAVASCRIPT PART
var streets = L.tileLayer( 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap',
subdomains: ['a', 'b', 'c']
}),
esri = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
}),
topo = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
maxZoom: 17,
attribution: 'Map data: © OpenStreetMap, SRTM | Map style: © OpenTopoMap (CC-BY-SA)'
});
var map = L.map( 'map', {
center: [20.0, 5.0],
minZoom: 2,
zoom: 2,
layers: [streets, esri, topo]
})
var baseMaps = {
"Streets": streets,
"Esri": esri,
"Topo": topo
};
$('.leaflet-control-attribution').hide()
L.control.scale().addTo(map);
L.control.layers(baseMaps).addTo(map);
var myURL = jQuery( 'script[src$="leaf.js"]' ).attr( 'src' ).replace( 'leaf.js', '' )
var myIcon = L.icon({
iconUrl: myURL + '/images/pin24.png',
iconRetinaUrl: myURL + '/images/pin48.png',
iconSize: [29, 24],
iconAnchor: [9, 21],
popupAnchor: [0, -14]
})
for ( var i=0; i < markers.length; ++i )
{
var deneme = [];
var meleme = L.marker( [markers[i].fields.latitude, markers[i].fields.longitude], {icon: myIcon} )
.bindPopup( "<b>" + "Mast name: " + "</b>" + markers[i].fields.site_name + "<b>" + "<br>" + "A: " + "</b>" + markers[i].fields.a_measured_height_lt + "<br>" + "<b>" + "k: " + "</b>" + markers[i].fields.k_measured_height_lt )
.addTo( map );
deneme.push(meleme);
document.getElementById("mast_button").onclick = mastFunct;
function mastFunct(){
var data = document.getElementById("mast_find");
for (var i=0; i < markers.length; ++i ){
var markerID = markers[i].fields.site_name;
if (markerID = data.value){
deneme[i].openPopup()
}
}
};
if (markerID = data.value){
should be
if (markerID == data.value){
the only issue that i see is this with the if (markerID = data.value){.
But you can try this alternative:
instead your for-loop:
map.eachLayer(function(marker){
if(marker.options){
var markerID = marker.options.site_name;
if (markerID == data.value){
marker.openPopup();
}
}
});
and add this to your marker creation:
L.marker([51.493782, -0.089951],{icon: myIcon, site_name: 'test'}).addTo(map)
I am using ionic2 ion-datetime, when I am going back in my application, still, date picker popup is showing, although there is no ion-data time tag in back page. help me to remove this pop on pressing back button
.html file
<ion-datetime id="dateofbirth" class="date" displayFormat="DD MMMM YYYY" [max]="maxDate" [min]="minDate">
.ts file(here i have written some logic for custom date time)
let date: any = new Date(),
maxYear = date.getFullYear() - 18, minYear = date.getFullYear() -65,
month = date.getMonth() + 1, minDay:any = date.getDate(),
this.minDate = minYear + "-" + month + "-" + minDay;
this.maxDate = maxYear + "-" + month + "-" + maxDay;
Use the below code in your .ts file where you have your component with ion date picker
ionViewWillLeave(){
let backDrop: any = document.getElementsByTagName('ion-picker-cmp');
if(backDrop.length > 0){
for(let i = 0; i< backDrop.length; i++){
backDrop[i].style.display = 'none';
}
}
}
Modify your app.component.ts file in following way,
import { Platform, IonicApp } from 'ionic-angular';
constructor(public platform: Platform, private ionicApp: IonicApp){}
initializeApp() {
this.platform.ready().then(() => {
//back button handle
this.platform.registerBackButtonAction(() => {
let activePortal = this.ionicApp._loadingPortal.getActive() ||
this.ionicApp._modalPortal.getActive() ||
this.ionicApp._toastPortal.getActive() ||
this.ionicApp._overlayPortal.getActive();
if (activePortal) {
activePortal.dismiss();
}
});
});
}
I have a problem when using Regex. I have a html document which create an anchor link when it matches condition.
An example html:
Căn cứ Luật Tổ chức HĐND và UBND ngày 26/11/2003;
Căn cứ Nghị định số 63/2010/NĐ-CP ngày 08/6/2010 của Chính phủ về
kiểm soát thủ tục hành chính;
Căn cứ Quyết định số 165/2011/QĐ-UBND ngày 06/5/2011 của UBND tỉnh
ban hành Quy định kiểm soát thủ tục hành chính trên địa bàn tỉnh;
Căn cứ Quyết định số 278/2011/QĐ-UBND ngày 02/8/2011 của UBND tỉnh
ban hành Quy chế phối hợp thực hiện thống kê, công bố, công khai thủ
tục hành chính và tiếp nhận, xử lý phản ánh, kiến nghị của cá nhân, tổ
chức về quy định hành chính trên địa bàn tỉnh;
Xét đề nghị của Giám đốc Sở Công Thương tại Tờ trình số
304/TTr-SCT ngày 29 tháng 5 năm 2013
I want to match these bold texts and make anchor links from these. If it has, try ignore. Link example 63/2010/NĐ-CP
var matchLegals = new Regex(#"(?:[\d]+\/?)\d+\/[a-z\dA-Z_ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂưăạảấầẩẫậắằẳẵặẹẻẽềềểỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ\-]+", RegexOptions.Compiled);
var doc = new HtmlDocument();
doc.LoadHtml(htmlString);
var allElements = doc.DocumentNode.SelectSingleNode("//div[#class='main-content']").Descendants();
foreach (var node in allElements)
{
var matches = matchLegals.Matches(node.InnerHtml);
foreach (Match m in matches)
{
var k = m.Value;
//dont know what to do
}
}
What can i do this
Many thanks.
I assume your regex pattern is OK and works. Another assumption is that node.InnerHtml doesn't contain any <a> tags already encompassing any of the potential matches.
In this case, it's as simple as doing something like this:
node.InnerHtml = Regex.Replace(node.InnerHtml, "[your pattern here]", "<a href='query=$&'>$&</a>");
...
doc.Save("output.html");
Note, that you may need to work on the href component - I'm unsure how your link should be built.
you match text and replace:
<script>
var s = '...';
var matchs = s.match(/\d{2,3}\/\d{4}\/[a-zA-Z\-áàảãạăâắằấầặẵẫậéèẻẽẹêếềểễệóòỏõọôốồổỗộơớờởỡợíìỉĩịđùúủũụưứửữựÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼÊỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỨỪỬỮỰỲỴÝỶỸửữựỵỷỹ]+/gi);
if (matchs != null) {
for(var i=0; i<matchs.length;i++){
var val = matchs[i];
s = s.replace(val, '<a href="?key=' + val + '"/>' + val + '</a>');
}
}
document.write(s);
</script>
#Shaamaan thank for your advice. After few hours of coding, it works now
var content = doc.DocumentNode.SelectSingleNode("//div[#class='main-content']");
var items = content.SelectNodes(".//text()[normalize-space(.) != '']");
foreach (HtmlNode node in items)
{
if (!matchLegals.IsMatch(node.InnerText) || node.ParentNode.Name == "a")
{
continue;
}
var texts = node.InnerHtml.Trim();
node.InnerHtml = matchLegals.Replace(texts, a => string.Format("<a href='/search?q={0}'>{0}</a>",a.Value));
}
The AdminTimeWidget rendered in admin for a DateTimeField displays an icon of a clock and when you click you have the choice between: "Now Midnight 6:00 Noon".
How can I change these choices to "16h 17h 18h"?
Chris has a great answer. As an alternative you could do this using just javascript. Place the following javascript on the pages where you want the different time options.
DateTimeShortcuts.overrideTimeOptions = function () {
// Find the first time element
timeElement = django.jQuery("ul.timelist li").eq(0).clone();
originalHref = timeElement.find('a').attr('href');
// remove all existing time elements
django.jQuery("ul.timelist li").remove();
// add new time elements representing those you want
var i=0;
for (i=0;i<=23;i++) {
// use a regular expression to update the link
newHref = originalHref.replace(/Date\([^\)]*\)/g, "Date(1970,1,1," + i + ",0,0,0)");
// update the text for the element
timeElement.find('a').attr('href', newHref).text(i+"h");
// Add the new element into the document
django.jQuery("ul.timelist").append(timeElement.clone());
}
}
addEvent(window, 'load', DateTimeShortcuts.overrideTimeOptions);
Subclass AdminTimeWidget to include a modified DateTimeShortcuts.js (get to that in a sec), then subclass AdminSplitDateTime to include your subclassed MyAdminTimeWidget instead of the default Django one:
from django.contrib.admin.widgets import AdminTimeWidget
from django.conf import settings
class MyAdminTimeWidget(AdminTimeWidget):
class Media:
js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
settings.MEDIA_URL + "js/admin/DateTimeShortcuts.js")
class MyAdminSplitDateTime(AdminSplitDateTime):
def __init__(self, attrs=None):
widgets = [AdminDateWidget, MyAdminTimeWidget]
forms.MultiWidget.__init__(self, widgets, attrs)
The secret sauce is in django/contrib/admin/media/js/admin/DateTimeShortcuts.js. This is what creates the list you want to modify. Copy this file and paste it into your project's site_media/js/admin directory. The relevant code you need to modify is on lines 85-88:
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");
Simply add to/delete from/modify that bit of javascript to your heart's content.
Finally, attach your new widget to any DateTimeFields you like. Your best bet for that will probably be the formfield_overrides attribute on ModelAdmin:
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
models.DateTimeField: {'widget': MyAdminSplitDateTime},
}
I tried using this method and found the above javascript didn't work when multiple datetime's were present on the form.
here is what I did.
In my ModelAdmin section i added:
class Media:
js = ('js/clock_time_selections.js',)
then in the js file:
$('document').ready(function () {
DateTimeShortcuts.overrideTimeOptions = function () {
var clockCount = 0;
console.log('ready');
$('ul.timelist').each(function () {
var $this = $(this);
var originalHref = $this.find('a').attr('href');
console.log(originalHref);
$this.find('li').remove();
for (i=8; i <= 20; i++) {
var newLink = '<li><a href="javascript:DateTimeShortcuts.handleClockQuicklink('+ clockCount + ', ' + i
+ ');"> ' + i + ':00h</a></li>';
$this.append(newLink);
}
//console.log($this.html());
clockCount++;
});
};
addEvent(window, 'load', DateTimeShortcuts.overrideTimeOptions);
});
Note: i had to put inside a document.ready because i found that i couldn't control where the script was included in the page (seems to have be loaded before the default calendar js files).
There's better solution. After reading DateTimeShortcuts.js the can be simplified to:
(function ($) {
$(document).ready(function () {
DateTimeShortcuts.clockHours.default_ = [];
for (let hour = 8; hour <= 20; hour++) {
let verbose_name = new Date(1970, 1, 1, hour, 0, 0).strftime('%H:%M');
DateTimeShortcuts.clockHours.default_.push([verbose_name, hour])
}
});
})(django.jQuery);
Then add this code to the javascript file in 'static//time-shortcuts.js' and add Meta to your admin model:
from django.contrib import admin
from .models import MyModel
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = [
'<myapp>/time-shortcuts.js',
]
I went with a much simpler approach and it worked for me. I simply added choices to my model using the following code:
class Class(Model):
program = ForeignKey('Program')
time_of_the_day = TimeField(choices=(
(datetime.datetime.strptime('7:00 am', "%I:%M %p").time(), '7:00 am'),
(datetime.datetime.strptime('8:00 am', "%I:%M %p").time(), '8:00 am'),
(datetime.datetime.strptime('9:00 am', "%I:%M %p").time(), '9:00 am'),
(datetime.datetime.strptime('6:00 pm', "%I:%M %p").time(), '6:00 pm'),
(datetime.datetime.strptime('7:00 pm', "%I:%M %p").time(), '7:00 pm'),
(datetime.datetime.strptime('8:00 pm', "%I:%M %p").time(), '8:00 pm'),
(datetime.datetime.strptime('9:00 pm', "%I:%M %p").time(), '9:00 pm'),
))
Hope this helps
Overriding JS by DateTimeShortcuts.overrideTimeOptions function works only with one form
( bug: the change of time in child model affects parent model, so you can't change timefield in child model form by this widget)
If you want use custom time options with inlines:
in /static/admin/js/admin/DateTimeShortcuts.js
replace:
quickElement("a", quickElement("li", time_list, ""), gettext("Now"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date().strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Midnight"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,0,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("6 a.m."), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,6,0,0,0).strftime('" + time_format + "'));");
quickElement("a", quickElement("li", time_list, ""), gettext("Noon"), "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1,12,0,0,0).strftime('" + time_format + "'));");
by:
for(j=6;j<=23;j++){
quickElement("a", quickElement("li", time_list, ""), j+":00", "href", "javascript:DateTimeShortcuts.handleClockQuicklink(" + num + ", new Date(1970,1,1," + j + ",0,0,0).strftime('" + time_format + "'));");
}
Expanding on #Bit68's answer, assuming other folks might want to create lists of regularly spaced times more than once, I created a helper function to build a choices tuple. (I'm adding a new answer because this length of code is too hard to follow in a comment.) This works in Django 2.2.
Note that this creates a dropdown list of options, it doesn't add options to the default admin date/time widget as the javascript methods do.
import datetime
def get_time_choices(start_time=datetime.time(9,0,0), end_time=datetime.time(17,0,0), delta=datetime.timedelta(minutes=15)):
'''
Builds a choices tuple of (time object, time string) tuples
starting at the start time specified and ending at or before
the end time specified in increments of size delta.
The default is to return a choices tuple for
9am to 5pm in 15-minute increments.
'''
time_choices = ()
time = start_time
while time <= end_time:
time_choices += ((time, time.strftime("%I:%M %p")),)
# This complicated line is because you can't add
# a timedelta object to a time object.
time = (datetime.datetime.combine(datetime.date.today(), time) + delta).time()
return time_choices
Then time_of_the_day = models.TimeField(choices=get_time_choices())