mirror of
https://github.com/iiab/iiab.git
synced 2025-02-12 11:12:06 +00:00
Osm (#26)
* fixes to change iiab->osm * change the name in meta too * create osm_install/enabled default flags * add maps alias,copy map.html to index.html * source file names do not change * incorporate osm-fixes in playbook * template rather than copy * add iiab back in for menu system
This commit is contained in:
parent
a4fb89ba35
commit
617dbde56f
11 changed files with 651 additions and 37 deletions
|
@ -1,6 +1,6 @@
|
|||
dependencies:
|
||||
- { role: moodle, tags: ['olpc','moodle','edu-apps'], when: moodle_install }
|
||||
- { role: iiab, tags: ['iiab','edu-apps'], when: iiab_install }
|
||||
- { role: osm, tags: ['osm','edu-apps'], when: osm_install }
|
||||
- { role: pathagar, tags: ['pathagar','edu-apps'], when: pathagar_install }
|
||||
- { role: rachel, tags: ['rachel','edu-apps'], when: rachel_install }
|
||||
- { role: kalite, tags: ['kalite','edu-apps'], when: kalite_install }
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
#IIAB Apache2 configuration file
|
||||
|
||||
XSendFile on
|
||||
XSendFilePath /
|
||||
|
||||
WSGIScriptAlias /iiab {{ doc_root }}/iiab.wsgi
|
||||
|
||||
{% if is_debuntu %}
|
||||
Alias /iiabstatic /usr/local/lib/python2.7/dist-packages/iiab/static
|
||||
|
||||
<Directory /usr/local/lib/python2.7/dist-packages/iiab/static>
|
||||
{% else %}
|
||||
Alias /iiabstatic /usr/lib/python2.7/site-packages/iiab/static
|
||||
|
||||
<Directory /usr/lib/python2.7/site-packages/iiab/static>
|
||||
{% endif %}
|
||||
require all granted
|
||||
</Directory>
|
2
roles/osm/defaults/main.yml
Normal file
2
roles/osm/defaults/main.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
osm_install: True
|
||||
osm_enabled: False
|
|
@ -105,26 +105,26 @@
|
|||
|
||||
- name: Copy IIAB config file
|
||||
template: backup=yes
|
||||
src=iiab.conf.j2
|
||||
dest=/etc/{{ apache_config_dir }}/iiab.conf
|
||||
src=osm.conf.j2
|
||||
dest=/etc/{{ apache_config_dir }}/osm.conf
|
||||
owner=root
|
||||
group=root
|
||||
mode=0644
|
||||
|
||||
- name: Create a link from sites-enabled to sites-available
|
||||
file: src=/etc/apache2/sites-available/iiab.conf
|
||||
dest=/etc/apache2/sites-enabled/iiab.conf
|
||||
file: src=/etc/apache2/sites-available/osm.conf
|
||||
dest=/etc/apache2/sites-enabled/osm.conf
|
||||
state=link
|
||||
when: iiab_enabled and is_debuntu
|
||||
when: osm_enabled and is_debuntu
|
||||
|
||||
- name: Remove the link from sites-enabled to sites-available
|
||||
file: dest=/etc/apache2/sites-enabled/iiab.conf
|
||||
file: dest=/etc/apache2/sites-enabled/osm.conf
|
||||
state=absent
|
||||
when: not iiab_enabled and is_debuntu
|
||||
when: not osm_enabled and is_debuntu
|
||||
|
||||
- name: Create link to cgi
|
||||
file: src=/bin/iiab.wsgi
|
||||
dest={{ doc_root}}/iiab.wsgi
|
||||
dest={{ doc_root}}/osm.wsgi
|
||||
owner=root
|
||||
group=root
|
||||
state=link
|
||||
|
@ -132,7 +132,7 @@
|
|||
|
||||
- name: Create link to cgi
|
||||
file: src=/usr/local/bin/iiab.wsgi
|
||||
dest={{ doc_root }}/iiab.wsgi
|
||||
dest={{ doc_root }}/osm.wsgi
|
||||
owner=root
|
||||
group=root
|
||||
state=link
|
||||
|
@ -154,9 +154,28 @@
|
|||
dest=/usr/local/lib/python2.7/dist-packages/iiab/defaults.ini
|
||||
when: is_debuntu
|
||||
|
||||
- name: add iiab to service list
|
||||
# the following was brought into OSM playbook from iiab-factory osm-fix script
|
||||
- name: Get the path for python-redhat
|
||||
set_fact: python_path=/usr/lib/python2.7/site-packages/iiab
|
||||
when: is_redhat
|
||||
|
||||
- name: Get the path for python-debuntu
|
||||
set_fact: python_path=/usr/local/lib/python2.7/dist-packages/iiab
|
||||
when: is_debuntu
|
||||
|
||||
- name: Copy the files
|
||||
template: src={{ item.src }} dest={{ item.dest }}
|
||||
with_items:
|
||||
- { src: 'etc.iiab.conf', dest: '/etc/iiab.conf' }
|
||||
- { src: 'map_search.py', dest: "{{ python_path }}/map_search.py" }
|
||||
- { src: 'map.html', dest: "{{ python_path }}/static/map.html" }
|
||||
- { src: 'l.control.geosearch.js', dest: "{{ python_path }}/static/lib/leaflet/geosearch/l.control.geosearch.js" }
|
||||
# end of imported osm-fix
|
||||
- { src: '{{ python_path }}/static/map.html', dest: "{{ python_path }}/static/index.html" }
|
||||
|
||||
- name: add osm to service list
|
||||
ini_file: dest='{{ service_filelist }}'
|
||||
section=iiab
|
||||
section=osm
|
||||
option='{{ item.option }}'
|
||||
value='{{ item.value }}'
|
||||
with_items:
|
||||
|
@ -165,6 +184,6 @@
|
|||
- option: description
|
||||
value: '"The Internet-in-a-Box is a small, inexpensive device which provides essential Internet resources without any Internet connection. It provides a local copy of half a terabyte of the world’s Free information."'
|
||||
- option: path
|
||||
value: /iiab
|
||||
value: /osm
|
||||
- option: enabled
|
||||
value: "{{ iiab_enabled }}"
|
||||
value: "{{ osm_enabled }}"
|
|
@ -41,11 +41,11 @@ bin_dir = %(knowledge_dir)s/sys/bin-%(arch)s
|
|||
[WEBAPP]
|
||||
port = 25000
|
||||
interface = 0.0.0.0
|
||||
base_prefix = /iiab/
|
||||
base_prefix = /osm/
|
||||
use_x_sendfile = False
|
||||
|
||||
[ZIM]
|
||||
url = /iiab/zim
|
||||
url = /osm/zim
|
||||
wikipedia_zim_dir = %(modules_dir)s/wikipedia-zim
|
||||
wikipedia_index_dir = %(modules_dir)s/wikipedia-index
|
||||
kiwix_library_file = %(wikipedia_zim_dir)s/library.xml
|
||||
|
@ -72,7 +72,7 @@ khan_cache_file = /tmp/khan_cache.json
|
|||
; so they can be served directly by the front end web server
|
||||
symlink_dir = %(khanacademy_dir)s/khanlinks
|
||||
; This is static content, so it can change based on web server config
|
||||
video_url = /iiab/video/khanvideo
|
||||
video_url = /osm/video/khanvideo
|
||||
|
||||
[OSM]
|
||||
openstreetmap_dir = %(modules_dir)s/openstreetmap
|
||||
|
@ -80,4 +80,4 @@ osm_search_dir = %(modules_dir)s/geonames_index
|
|||
|
||||
[SOFTWARE]
|
||||
software_dir = %(modules_dir)s/ubuntu/12.04/mirror/archive.ubuntu.com/ubuntu
|
||||
software_url = /iiab/software
|
||||
software_url = /osm/software
|
25
roles/osm/templates/etc.iiab.conf
Normal file
25
roles/osm/templates/etc.iiab.conf
Normal file
|
@ -0,0 +1,25 @@
|
|||
;; Local Configuration file for Internet-in-a-Box
|
||||
;;
|
||||
;;
|
||||
;
|
||||
;; [DEFAULT] is a special section. Any settings there
|
||||
;; will automatically appear in all other sections.
|
||||
[DEFAULT]
|
||||
; Location of our dataset
|
||||
knowledge_dir = /library/knowledge
|
||||
; repeat all the other assignments to get the new dir
|
||||
processed_dir = %(knowledge_dir)s/processed
|
||||
modules_dir = %(knowledge_dir)s/modules
|
||||
data_dir = %(knowledge_dir)s/data
|
||||
|
||||
; If search_for_knowledge_dir is true, then
|
||||
; the system will search all mounted volumes
|
||||
; for a "knowledge/" directory if the path
|
||||
; specified in knowledge_dir does not exist.
|
||||
search_for_knowledge_dir = True
|
||||
|
||||
; Machine architecture. This is set by the
|
||||
; application at run-time.
|
||||
arch = unset
|
||||
bin_dir = %(knowledge_dir)s/sys/bin-%(arch)s
|
||||
|
425
roles/osm/templates/l.control.geosearch.js
Normal file
425
roles/osm/templates/l.control.geosearch.js
Normal file
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
* L.Control.GeoSearch - search for an address and zoom to it's location
|
||||
* https://github.com/smeijer/leaflet.control.geosearch
|
||||
*/
|
||||
|
||||
L.GeoSearch = {};
|
||||
L.GeoSearch.Provider = {};
|
||||
|
||||
// MSIE needs cors support
|
||||
jQuery.support.cors = true;
|
||||
|
||||
L.GeoSearch.Result = function (x, y, label) {
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Label = label;
|
||||
};
|
||||
|
||||
L.Control.GeoSearch = L.Control.extend({
|
||||
options: {
|
||||
position: 'topcenter'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this._config = {};
|
||||
L.Util.extend(this.options, options);
|
||||
this.setConfig(options);
|
||||
},
|
||||
|
||||
setConfig: function (options) {
|
||||
this._config = {
|
||||
'country': options.country || '',
|
||||
'provider': options.provider,
|
||||
|
||||
'searchLabel': options.searchLabel || 'search for address...',
|
||||
'notFoundMessage' : options.notFoundMessage || 'Sorry, that address could not be found.',
|
||||
'messageHideDelay': options.messageHideDelay || 3000,
|
||||
'zoomLevel': options.zoomLevel || 18,
|
||||
|
||||
'maxMarkers': options.maxMarkers || 1,
|
||||
'enableButtons': options.enableButtons || false,
|
||||
|
||||
'enableAutocomplete': options.enableAutocomplete || false,
|
||||
'autocompleteMinQueryLen': options.autocompleteMinQueryLen || 3, // query length request threshold
|
||||
'autocompleteQueryDelay_ms': options.autocompleteQueryDelay_ms || 800
|
||||
};
|
||||
},
|
||||
|
||||
onAdd: function (map) {
|
||||
var $controlContainer = $(map._controlContainer);
|
||||
|
||||
if ($controlContainer.children('.leaflet-top.leaflet-center').length == 0) {
|
||||
$controlContainer.append('<div class="leaflet-top leaflet-center"></div>');
|
||||
map._controlCorners.topcenter = $controlContainer.children('.leaflet-top.leaflet-center').first()[0];
|
||||
}
|
||||
|
||||
this._map = map;
|
||||
this._container = L.DomUtil.create('div', 'leaflet-control-geosearch');
|
||||
|
||||
var searchbox = document.createElement('input');
|
||||
searchbox.id = 'leaflet-control-geosearch-qry';
|
||||
searchbox.type = 'text';
|
||||
searchbox.placeholder = this._config.searchLabel;
|
||||
this._searchbox = searchbox;
|
||||
if (this._autocomplete) {
|
||||
this._autocomplete.recordLastUserInput('');
|
||||
}
|
||||
|
||||
if (this._config.enableButtons) {
|
||||
var submitContainer = L.DomUtil.create('div', 'leaflet-control-geosearch-button-submit-container', this._container);
|
||||
L.DomUtil.create('span', 'leaflet-geosearch-submit-button', submitContainer);
|
||||
var cancelButton = L.DomUtil.create('span', 'leaflet-geosearch-cancel-button', this._container);
|
||||
L.DomEvent.on(submitContainer, 'click', this._submitRequest, this);
|
||||
L.DomEvent.on(cancelButton, 'click', this._clearUserSearchInput, this);
|
||||
}
|
||||
|
||||
var msgbox = document.createElement('div');
|
||||
msgbox.id = 'leaflet-control-geosearch-msg';
|
||||
msgbox.className = 'leaflet-control-geosearch-msg';
|
||||
this._msgbox = msgbox;
|
||||
|
||||
var resultslist = document.createElement('ul');
|
||||
resultslist.id = 'leaflet-control-geosearch-results';
|
||||
this._resultslist = resultslist;
|
||||
|
||||
$(this._msgbox).append(this._resultslist);
|
||||
$(this._container).append(this._searchbox, this._msgbox);
|
||||
|
||||
if (this._config.enableAutocomplete) {
|
||||
this._autocomplete = new L.AutoComplete(this.options).addTo(this._container, function (suggestionText) {
|
||||
this._searchbox.value = suggestionText;
|
||||
}.bind(this));
|
||||
$(this._container).append(this._autocomplete);
|
||||
}
|
||||
|
||||
// TODO This will result in duplicate processing of events. Options?
|
||||
L.DomEvent
|
||||
.addListener(this._container, 'click', L.DomEvent.stop)
|
||||
.addListener(this._container, 'keyup', this._onKeyUp, this)
|
||||
.addListener(this._container, 'change', this._onInputUpdate, this)
|
||||
.addListener(this._container, 'paste', this._onPasteToInput, this);
|
||||
|
||||
L.DomEvent.disableClickPropagation(this._container);
|
||||
|
||||
return this._container;
|
||||
},
|
||||
|
||||
geosearch: function (qry) {
|
||||
this.geosearch_ext(qry, this._processResults.bind(this), this._printError.bind(this));
|
||||
},
|
||||
|
||||
geosearch_ext: function(qry, onSuccess, onFailure) {
|
||||
try {
|
||||
var provider = this._config.provider;
|
||||
|
||||
if(typeof provider.GetLocations == 'function') {
|
||||
var results = provider.GetLocations(qry, function(results) {
|
||||
onSuccess(results);
|
||||
}.bind(this));
|
||||
}
|
||||
else {
|
||||
var url = provider.GetServiceUrl(qry);
|
||||
|
||||
$.getJSON(url, function (data) {
|
||||
try {
|
||||
var results = provider.ParseJSON(data);
|
||||
onSuccess(results);
|
||||
}
|
||||
catch (error) {
|
||||
onFailure(error);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
onFailure(error);
|
||||
}
|
||||
},
|
||||
|
||||
// qry may be a String or a function
|
||||
geosearch_autocomplete: function (qry, requestDelay_ms) {
|
||||
if (!this._config.enableAutocomplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(this._autocompleteRequestTimer);
|
||||
|
||||
this._autocompleteRequestTimer = setTimeout(function () {
|
||||
var q = qry;
|
||||
if (typeof qry === 'function') {
|
||||
q = qry();
|
||||
}
|
||||
if (q.length >= this._config.autocompleteMinQueryLen) {
|
||||
this.geosearch_ext(q, this._autocomplete.show.bind(this._autocomplete), this._autocomplete.hide.bind(this._autocomplete));
|
||||
} else {
|
||||
this._autocomplete.hide();
|
||||
}
|
||||
}.bind(this), requestDelay_ms);
|
||||
},
|
||||
|
||||
_processResults: function(results) {
|
||||
if (results.length == 0)
|
||||
throw this._config.notFoundMessage;
|
||||
|
||||
this._map.fireEvent('geosearch_foundlocations', {Locations: results});
|
||||
this._showLocations(results);
|
||||
},
|
||||
|
||||
_showLocations: function (results) {
|
||||
if (typeof this._layer !== 'undefined') {
|
||||
this._map.removeLayer(this._layer);
|
||||
this._layer = null;
|
||||
}
|
||||
|
||||
this._markerList = []
|
||||
for (var ii=0; ii < results.length && ii < this._config.maxMarkers; ii++) {
|
||||
var location = results[ii];
|
||||
var marker = L.marker([location.Y, location.X]).bindPopup(location.Label);
|
||||
this._markerList.push(marker);
|
||||
}
|
||||
this._layer = L.layerGroup(this._markerList).addTo(this._map);
|
||||
this._printError('Displaying ' + Math.min(this._autocomplete._config.maxResultCount, results.length) + ' of ' + results.length +' results.');
|
||||
|
||||
var premierResult = results[0];
|
||||
this._map.setView([premierResult.Y, premierResult.X], this._config.zoomLevel, false);
|
||||
this._map.fireEvent('geosearch_showlocation', {Location: premierResult});
|
||||
},
|
||||
|
||||
_printError: function(message) {
|
||||
$(this._resultslist)
|
||||
.html('<li>'+message+'</li>')
|
||||
.fadeIn('slow').delay(this._config.messageHideDelay).fadeOut('slow',
|
||||
function () { $(this).html(''); });
|
||||
},
|
||||
|
||||
_submitRequest: function () {
|
||||
var q = $('#leaflet-control-geosearch-qry').val();
|
||||
if (q.length > 0) {
|
||||
this._hideAutocomplete();
|
||||
this.geosearch(q);
|
||||
}
|
||||
},
|
||||
|
||||
_hideAutocomplete: function () {
|
||||
clearTimeout(this._autocompleteRequestTimer);
|
||||
if (this._config.enableAutocomplete && this._autocomplete.isVisible()) {
|
||||
this._autocomplete.hide();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_clearUserSearchInput: function () {
|
||||
this._hideAutocomplete();
|
||||
$('#leaflet-control-geosearch-qry').val('');
|
||||
$('.leaflet-geosearch-cancel-button').hide();
|
||||
},
|
||||
|
||||
_onPasteToInput: function () {
|
||||
// onpaste requires callback to allow for input update do this by default.
|
||||
setTimeout(this._onInputUpdate.bind(this), 0);
|
||||
},
|
||||
|
||||
_onInputUpdate: function () {
|
||||
// define function for requery of user input after delay
|
||||
function getQuery() {
|
||||
return $('#leaflet-control-geosearch-qry').val();
|
||||
}
|
||||
var qry = getQuery();
|
||||
|
||||
if (this._config.enableAutocomplete) {
|
||||
this._autocomplete.recordLastUserInput(qry);
|
||||
if (qry.length >= this._config.autocompleteMinQueryLen) {
|
||||
this.geosearch_autocomplete(getQuery, this._config.autocompleteQueryDelay_ms);
|
||||
} else {
|
||||
this._autocomplete.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (qry.length > 0) {
|
||||
$('.leaflet-geosearch-cancel-button').show();
|
||||
} else {
|
||||
$('.leaflet-geosearch-cancel-button').hide();
|
||||
}
|
||||
},
|
||||
|
||||
_onKeyUp: function (e) {
|
||||
var REQ_DELAY_MS = 800;
|
||||
var MIN_AUTOCOMPLETE_LEN = 3;
|
||||
var enterKey = 13;
|
||||
var shift = 16;
|
||||
var ctrl = 17;
|
||||
var escapeKey = 27;
|
||||
var leftArrow = 37;
|
||||
var upArrow = 38;
|
||||
var rightArrow = 39;
|
||||
var downArrow = 40;
|
||||
|
||||
switch (e.keyCode) {
|
||||
case escapeKey:
|
||||
// ESC first closes autocomplete if open. If closed then clears input.
|
||||
if (!this._hideAutocomplete()) {
|
||||
this._clearUserSearchInput();
|
||||
}
|
||||
break;
|
||||
case enterKey:
|
||||
this._submitRequest();
|
||||
break;
|
||||
case upArrow:
|
||||
if (this._config.enableAutocomplete && this._autocomplete.isVisible()) {
|
||||
this._autocomplete.moveUp();
|
||||
}
|
||||
break;
|
||||
case downArrow:
|
||||
if (this._config.enableAutocomplete && this._autocomplete.isVisible()) {
|
||||
this._autocomplete.moveDown();
|
||||
}
|
||||
break;
|
||||
case leftArrow:
|
||||
case rightArrow:
|
||||
case shift:
|
||||
case ctrl:
|
||||
break;
|
||||
default:
|
||||
this._onInputUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
L.AutoComplete = L.Class.extend({
|
||||
initialize: function (options) {
|
||||
this._config = {};
|
||||
this.setConfig(options);
|
||||
},
|
||||
|
||||
setConfig: function (options) {
|
||||
this._config = {
|
||||
'maxResultCount': options.maxResultCount || 10,
|
||||
'onMakeSuggestionHTML': options.onMakeSuggestionHTML || function (geosearchResult) {
|
||||
return this._htmlEscape(geosearchResult.Label);
|
||||
}.bind(this),
|
||||
};
|
||||
},
|
||||
|
||||
addTo: function (container, onSelectionCallback) {
|
||||
this._container = container;
|
||||
this._onSelection = onSelectionCallback;
|
||||
return this._createUI(container, 'leaflet-geosearch-autocomplete');
|
||||
},
|
||||
|
||||
recordLastUserInput: function (str) {
|
||||
this._lastUserInput = str;
|
||||
},
|
||||
|
||||
_createUI: function (container, className) {
|
||||
this._tool = L.DomUtil.create('div', className, container);
|
||||
this._tool.style.display = 'none';
|
||||
L.DomEvent
|
||||
.disableClickPropagation(this._tool)
|
||||
// consider whether to make delayed hide onBlur.
|
||||
// If so, consider canceling timer on mousewheel and mouseover.
|
||||
.on(this._tool, 'blur', this.hide, this)
|
||||
.on(this._tool, 'mousewheel', function(e) {
|
||||
L.DomEvent.stopPropagation(e); // to prevent map zoom
|
||||
if (e.axis === e.VERTICAL_AXIS) {
|
||||
if (e.detail > 0) {
|
||||
this.moveDown();
|
||||
} else {
|
||||
this.moveUp();
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
show: function (results) {
|
||||
this._tool.innerHTML = '';
|
||||
this._tool.currentSelection = -1;
|
||||
var count = 0;
|
||||
while (count < results.length && count < this._config.maxResultCount) {
|
||||
var entry = this._newSuggestion(results[count]);
|
||||
this._tool.appendChild(entry);
|
||||
++count;
|
||||
}
|
||||
if (count > 0) {
|
||||
this._tool.style.display = 'block';
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
return count;
|
||||
},
|
||||
hide: function () {
|
||||
this._tool.style.display = 'none';
|
||||
this._tool.innerHTML = '';
|
||||
},
|
||||
|
||||
isVisible: function() {
|
||||
return this._tool.style.display !== 'none';
|
||||
},
|
||||
|
||||
_htmlEscape: function (str) {
|
||||
// implementation courtesy of http://stackoverflow.com/a/7124052
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
},
|
||||
|
||||
_newSuggestion: function (result) {
|
||||
var tip = L.DomUtil.create('li', 'leaflet-geosearch-suggestion');
|
||||
tip.innerHTML = this._config.onMakeSuggestionHTML(result);
|
||||
tip._text = result.Label;
|
||||
L.DomEvent
|
||||
.disableClickPropagation(tip)
|
||||
.on(tip, 'click', function(e) {
|
||||
this._onSelection(tip._text);
|
||||
}.bind(this), this);
|
||||
return tip;
|
||||
},
|
||||
_onSelectedUpdate: function () {
|
||||
var entries = this._tool.hasChildNodes() ? this._tool.childNodes : [];
|
||||
for (var ii=0; ii < entries.length; ++ii) {
|
||||
L.DomUtil.removeClass(entries[ii], 'leaflet-geosearch-suggestion-selected');
|
||||
}
|
||||
|
||||
// if selection is -1, then show last user typed text
|
||||
if (this._tool.currentSelection >= 0) {
|
||||
L.DomUtil.addClass(entries[this._tool.currentSelection], 'leaflet-geosearch-suggestion-selected');
|
||||
|
||||
// scroll:
|
||||
var tipOffsetTop = entries[this._tool.currentSelection].offsetTop;
|
||||
if (tipOffsetTop + entries[this._tool.currentSelection].clientHeight >= this._tool.scrollTop + this._tool.clientHeight) {
|
||||
this._tool.scrollTop = tipOffsetTop - this._tool.clientHeight + entries[this._tool.currentSelection].clientHeight;
|
||||
}
|
||||
else if (tipOffsetTop <= this._tool.scrollTop) {
|
||||
this._tool.scrollTop = tipOffsetTop;
|
||||
}
|
||||
|
||||
this._onSelection(entries[this._tool.currentSelection]._text);
|
||||
} else {
|
||||
this._onSelection(this._lastUserInput);
|
||||
}
|
||||
},
|
||||
moveUp: function () {
|
||||
// permit selection to decrement down to -1 (none selected)
|
||||
if (this.isVisible() && this._tool.currentSelection >= 0) {
|
||||
--this._tool.currentSelection;
|
||||
this._onSelectedUpdate();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
moveDown: function () {
|
||||
if (this.isVisible()) {
|
||||
this._tool.currentSelection = (this._tool.currentSelection + 1) % this.suggestionCount();
|
||||
this._onSelectedUpdate();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
suggestionCount: function () {
|
||||
return this._tool.hasChildNodes() ? this._tool.childNodes.length : 0;
|
||||
},
|
||||
});
|
||||
|
79
roles/osm/templates/map.html
Normal file
79
roles/osm/templates/map.html
Normal file
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<link rel="stylesheet" href="lib/leaflet/leaflet.css" />
|
||||
<link rel="stylesheet" href="lib/leaflet/geosearch/l.geosearch.css" />
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
html, body, #map {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Required for Firefox 3.6
|
||||
if (!Function.prototype.bind) {
|
||||
Function.prototype.bind = function (oThis) {
|
||||
if (typeof this !== "function") {
|
||||
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
||||
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
|
||||
}
|
||||
|
||||
var aArgs = Array.prototype.slice.call(arguments, 1),
|
||||
fToBind = this,
|
||||
fNOP = function () {},
|
||||
fBound = function () {
|
||||
return fToBind.apply(this instanceof fNOP && oThis
|
||||
? this
|
||||
: oThis,
|
||||
aArgs.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
|
||||
fNOP.prototype = this.prototype;
|
||||
fBound.prototype = new fNOP();
|
||||
|
||||
return fBound;
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="lib/jquery-1.9.0.js"></script>
|
||||
<script src="lib/leaflet/leaflet.js"></script>
|
||||
<script src="lib/leaflet/geosearch/l.control.geosearch.js"></script>
|
||||
<script src="lib/leaflet/geosearch/l.geosearch.provider.iiab.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var map = L.map('map'); /*.setView([51.505, -0.09], 14);*/
|
||||
L.tileLayer('/iiab/maps/tile/{z}/{x}/{y}.png', {
|
||||
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
|
||||
maxZoom: 15
|
||||
}).addTo(map);
|
||||
|
||||
var geoOptions = {
|
||||
provider: new L.GeoSearch.Provider.iiab(),
|
||||
searchLabel: "Search by City Name...",
|
||||
notFoundMessage: "No matches found",
|
||||
zoomLevel: 8,
|
||||
maxMarkers: 10,
|
||||
maxResultCount: 15,
|
||||
enableAutocomplete: true,
|
||||
enableButtons: true
|
||||
};
|
||||
new L.Control.GeoSearch(geoOptions).addTo(map);
|
||||
|
||||
map.fitWorld().setZoom(3); // default world view
|
||||
//map.locate({setView: true, maxZoom: 15});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
58
roles/osm/templates/map_search.py
Normal file
58
roles/osm/templates/map_search.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Internet-in-a-Box System
|
||||
# By Braddock Gaskill, 16 Feb 2013
|
||||
# Modified by Tim Moody, 8 Apr 2016
|
||||
from utils import whoosh_open_dir_32_or_64
|
||||
# from whoosh.qparser import QueryParser
|
||||
from whoosh.qparser import MultifieldParser
|
||||
from whoosh import sorting
|
||||
|
||||
from utils import whoosh2dict
|
||||
|
||||
|
||||
class MapSearch(object):
|
||||
def __init__(self, index_dir):
|
||||
"""Initialize a search object.
|
||||
index_dir is the Whoosh index directory to use."""
|
||||
self.index_dir = index_dir
|
||||
|
||||
def search(self, query, page=1, pagelen=20):
|
||||
"""Return a sorted list of results.
|
||||
pagelen specifies the number of hits per page.
|
||||
page specifies the page of results to return (first page is 1)
|
||||
Set pagelen = None or 0 to retrieve all results.
|
||||
"""
|
||||
query = unicode(query) # Must be unicode
|
||||
population_sort_facet = sorting.FieldFacet("population", reverse=True)
|
||||
ix = whoosh_open_dir_32_or_64(self.index_dir)
|
||||
with ix.searcher() as searcher:
|
||||
# query = QueryParser("ngram_name", ix.schema).parse(query)
|
||||
mparser = MultifieldParser(["ngram_name", "admin1_code", "country_code"], schema=ix.schema)
|
||||
query = mparser.parse(query)
|
||||
if pagelen is not None and pagelen != 0:
|
||||
try:
|
||||
results = searcher.search_page(query, page, pagelen=pagelen)
|
||||
except ValueError, e: # Invalid page number
|
||||
results = []
|
||||
else:
|
||||
results = searcher.search(query, limit=None)
|
||||
#r = [x.items() for x in results]
|
||||
r = whoosh2dict(results)
|
||||
ix.close()
|
||||
# experiment with tucking away content for display in popup.
|
||||
print r
|
||||
for d in r:
|
||||
d['popupText'] = 'test content'
|
||||
d['name'] = d['name'] + ', ' + d['admin1_code'] + ', ' + d['country_code']
|
||||
|
||||
return r
|
||||
|
||||
def count(self, query):
|
||||
"""Return total number of matching documents in index"""
|
||||
query = unicode(query) # Must be unicode
|
||||
ix = whoosh_open_dir_32_or_64(self.index_dir)
|
||||
with ix.searcher() as searcher:
|
||||
query = QueryParser("title", ix.schema).parse(query)
|
||||
results = searcher.search(query)
|
||||
n = len(results)
|
||||
ix.close()
|
||||
return n
|
24
roles/osm/templates/osm.conf.j2
Normal file
24
roles/osm/templates/osm.conf.j2
Normal file
|
@ -0,0 +1,24 @@
|
|||
#IIAB Apache2 configuration file
|
||||
|
||||
XSendFile on
|
||||
XSendFilePath /
|
||||
|
||||
WSGIScriptAlias /osm {{ doc_root }}/osm.wsgi
|
||||
|
||||
{% if is_debuntu %}
|
||||
Alias /iiabstatic /usr/local/lib/python2.7/dist-packages/iiab/static
|
||||
Alias /osm /usr/local/lib/python2.7/dist-packages/iiab/static
|
||||
Alias /maps /usr/local/lib/python2.7/dist-packages/iiab/static
|
||||
Alias /iiab /usr/local/lib/python2.7/dist-packages/iiab/static
|
||||
|
||||
<Directory /usr/local/lib/python2.7/dist-packages/iiab/static>
|
||||
{% else %}
|
||||
Alias /iiabstatic /usr/lib/python2.7/site-packages/iiab/static
|
||||
Alias /osm /usr/lib/python2.7/site-packages/iiab/static
|
||||
Alias /maps /usr/lib/python2.7/site-packages/iiab/static
|
||||
Alias /iiab /usr/lib/python2.7/site-packages/iiab/static
|
||||
|
||||
<Directory /usr/lib/python2.7/site-packages/iiab/static>
|
||||
{% endif %}
|
||||
require all granted
|
||||
</Directory>
|
|
@ -1,4 +1,4 @@
|
|||
[iiab]
|
||||
[osm]
|
||||
name=Internet-in-a-Box
|
||||
baseurl=http://downloads.internet-in-a-box.org/fedora/18
|
||||
enabled=1
|
Loading…
Reference in a new issue