diff --git a/WalkingTourPlugin.php b/WalkingTourPlugin.php
index 388df5a..f53a7ea 100644
--- a/WalkingTourPlugin.php
+++ b/WalkingTourPlugin.php
@@ -54,7 +54,7 @@ public function hookInstall()
$db = $this->_db;
$tourQuery = "
- CREATE TABLE IF NOT EXISTS `$db->Tour` (
+ CREATE TABLE IF NOT EXISTS `$db->WalkingTour` (
`id` int( 10 ) unsigned NOT NULL auto_increment,
`title` varchar( 255 ) collate utf8_unicode_ci default NULL,
`description` text collate utf8_unicode_ci NOT NULL,
@@ -68,7 +68,7 @@ public function hookInstall()
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ";
$tourItemQuery = "
- CREATE TABLE IF NOT EXISTS `$db->TourItem` (
+ CREATE TABLE IF NOT EXISTS `$db->WalkingTourItem` (
`id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT,
`tour_id` INT( 10 ) UNSIGNED NOT NULL,
`ordinal` INT NOT NULL,
@@ -86,27 +86,75 @@ public function hookInstall()
public function hookUninstall()
{
$db = $this->_db;
- $db->query("DROP TABLE IF EXISTS `$db->TourItem`");
- $db->query("DROP TABLE IF EXISTS `$db->Tour`");
+ $db->query("DROP TABLE IF EXISTS `$db->WalkingTourItem`");
+ $db->query("DROP TABLE IF EXISTS `$db->WalkingTour`");
$this->_uninstallOptions();
}
public function hookUpgrade($args)
{
-
- $oldVersion = $args['old_version'];
- $newVersion = $args['new_version'];
$db = $this->_db;
+ $oldVersion = $args['old_version'];
- if (version_compare($oldVersion, '0.1-dev', "<")) {
- $sql = "ALTER TABLE `{$db->prefix}tour_items` MODIFY COLUMN `exhibit_id` INT NOT NULL;";
- $db->query($sql);
- }
+ $oldTourTable = "{$db->prefix}tours";
+ $newWalkingTourTable = "{$db->prefix}walking_tours";
+
+ $oldTourItemTable = "{$db->prefix}tour_items";
+ $newWalkingTourItemTable = "{$db->prefix}walking_tour_items";
+
+ $db->query("CREATE TABLE IF NOT EXISTS `$newWalkingTourTable` (
+ `id` int( 10 ) unsigned NOT NULL auto_increment,
+ `title` varchar( 255 ) collate utf8_unicode_ci default NULL,
+ `description` text collate utf8_unicode_ci NOT NULL,
+ `route` text collate utf8_unicode_ci,
+ `credits` text collate utf8_unicode_ci,
+ `postscript_text` text collate utf8_unicode_ci,
+ `featured` tinyint( 1 ) default '0',
+ `public` tinyint( 1 ) default '0',
+ `color` text collate utf8_unicode_ci,
+ PRIMARY KEY( `id` )
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"
+ );
+
+ $db->query("CREATE TABLE IF NOT EXISTS `$newWalkingTourItemTable` (
+ `id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT,
+ `tour_id` INT( 10 ) UNSIGNED NOT NULL,
+ `ordinal` INT NOT NULL,
+ `item_id` INT( 10 ) UNSIGNED NOT NULL,
+ `exhibit_id` INT NOT NULL,
+ PRIMARY KEY( `id` ),
+ KEY `tour` ( `tour_id` )
+ ) ENGINE=InnoDB"
+ );
+
+ if (version_compare($oldVersion, '2.0.0', '<')) {
+ $checkOldTourTable = $db->query("SHOW TABLES LIKE '$oldTourTable'")->fetchAll();
+
+ if (!empty($checkOldTourTable)) {
+ $migrateTourSql = "INSERT INTO `$newWalkingTourTable` (
+ id, title, description, route, credits, postscript_text, featured, public, color)
+ SELECT
+ id, title, description, route, credits, postscript_text, featured, public, color
+ FROM `$oldTourTable`
+ WHERE id NOT IN (SELECT id FROM `$newWalkingTourTable`)";
+ $db->query($migrateTourSql);
+
+ // $db->query("DROP TABLE `$oldTourTable` text;");
+ }
- if (version_compare($oldVersion, '1.0.0', '<=')) {
- $sql = "ALTER TABLE `{$db->prefix}tours` ADD COLUMN `route` TEXT;";
- $db->query($sql);}
+ $checkOldTourItemTable = $db->query("SHOW TABLES LIKE '$oldTourItemTable'")->fetchAll();
+
+ if (!empty($checkOldTourItemTable)) {
+ $migrateItemSql = "INSERT INTO `$newWalkingTourItemTable` (
+ id, tour_id, ordinal, item_id, exhibit_id)
+ SELECT id, tour_id, ordinal, item_id, exhibit_id
+ FROM `$oldTourItemTable`
+ WHERE id NOT IN (SELECT id FROM `$newWalkingTourItemTable`)";
+ $db->query($migrateItemSql);
+ // $db->query("DROP TABLE `$oldTourItemTable` text;");
+ }
}
+ }
public function hookDefineAcl($args)
{
@@ -191,8 +239,8 @@ public function hookAdminDashboard()
// Get the database.
$db = get_db();
- // Get the Tour table.
- $table = $db->getTable('Tour');
+ // Get the Walking Tour table.
+ $table = $db->getTable('WalkingTour');
// Build the select query.
$select = $table->getSelect();
@@ -205,15 +253,15 @@ public function hookAdminDashboard()
for ($i = 0; $i <= 5; $i++) {
if (array_key_exists($i, $results) && is_object($results[$i])) {
- $tourItems .= '
';
+ $tourItems .= '';
}
}
$html .= '';
echo $html;
@@ -233,23 +281,25 @@ public function hookAdminHead()
public function filterPublicNavigationMain($nav)
{
- $nav[] = array('label' => 'Map', 'uri' => url('map'));
+ $nav[] = array(
+ 'label' => 'Map',
+ 'uri' => url('map')
+ );
return $nav;
}
public function filterSearchRecordTypes($recordTypes)
{
- $recordTypes['Tour'] = __('Tour');
+ $recordTypes['WalkingTour'] = __('Walking Tour');
return $recordTypes;
}
public function filterAdminNavigationMain($nav)
{
- $nav['Tours'] = array(
+ $nav['WalkingTours'] = array(
'label' => __('Walking Tours'),
- 'action' => 'browse',
- 'controller' => 'tours'
+ 'uri' => url('walking-tours/browse')
);
return $nav;
}
diff --git a/controllers/IndexController.php b/controllers/IndexController.php
index 5672dbd..c5b307c 100755
--- a/controllers/IndexController.php
+++ b/controllers/IndexController.php
@@ -21,8 +21,8 @@ public function publicTours()
{
// Get the database.
$db = get_db();
- // Get the Tour table.
- $tour_table = $db->getTable('Tour');
+ // Get the Walking Tour table.
+ $tour_table = $db->getTable('WalkingTour');
// Build the select query.
$select = $tour_table->getSelect();
// Fetch some items with our select.
@@ -46,7 +46,7 @@ public function saveRouteAction() {
$tourId = $this->getRequest()->getPost('tour_id');
$route = $this->getRequest()->getPost('route');
$db = get_db();
- $tourTable = $db->getTable('Tour');
+ $tourTable = $db->getTable('WalkingTour');
$tour = $tourTable->find($tourId);
if ($tour) {
$tour->route = $route;
@@ -57,6 +57,73 @@ public function saveRouteAction() {
}
}
+ public function previewAction()
+ {
+ if (!$this->_request->isXmlHttpRequest()) {
+ throw new Omeka_Controller_Exception_403;
+ }
+
+ $tourId = (int) $this->_request->getPost('tour_id');
+ $itemIds = $this->_request->getPost('item_ids', array());
+
+ if (is_string($itemIds)) {
+ $itemIds = array_filter(array_map('trim', explode(',', $itemIds)));
+ }
+
+ $itemIds = array_values(array_filter(array_map('intval', (array) $itemIds)));
+
+ $db = $this->_helper->db->getDb();
+ $tourTable = $db->getTable('WalkingTour');
+ $tour = $tourTable->find($tourId);
+
+ if (!$tour) {
+ $this->_helper->json(array('error' => 'Tour not found.'));
+ return;
+ }
+
+ $locations = array();
+ if (!empty($itemIds)) {
+ $prefix = $db->prefix;
+ $placeholders = implode(',', array_fill(0, count($itemIds), '?'));
+ $sql = "SELECT item_id, latitude, longitude FROM {$prefix}locations WHERE item_id IN ($placeholders)";
+ $rows = $db->fetchAll($sql, $itemIds);
+ foreach ($rows as $row) {
+ $locations[(int) $row['item_id']] = $row;
+ }
+ }
+
+ $features = array();
+ foreach ($itemIds as $itemId) {
+ if (!isset($locations[$itemId])) {
+ continue;
+ }
+
+ $features[] = array(
+ 'type' => 'Feature',
+ 'geometry' => array(
+ 'type' => 'Point',
+ 'coordinates' => array((float) $locations[$itemId]['longitude'], (float) $locations[$itemId]['latitude']),
+ ),
+ 'properties' => array(
+ 'id' => $itemId,
+ 'marker-color' => $tour->color,
+ ),
+ );
+ }
+
+ $this->_helper->json(array(
+ 'Data' => array(
+ 'type' => 'FeatureCollection',
+ 'features' => $features,
+ ),
+ 'Color' => $tour->color,
+ 'Tour Name' => $tour->title,
+ 'Description' => $tour->description,
+ 'Credits' => $tour->credits,
+ 'Route' => $tour->route,
+ ));
+ }
+
/**
* Display the map.
*/
@@ -74,12 +141,12 @@ public function indexAction()
->appendFile(src('modernizr.custom.63332', 'javascripts', 'js'))
->appendFile(src('Polyline.encoded', 'javascripts', 'js'))
->appendFile('//cdn.jsdelivr.net/npm/@allmaps/leaflet/dist/bundled/allmaps-leaflet-1.9.umd.js')
- ->appendFile(src('walking-tour', 'javascripts', 'js'));
+ ->appendFile(src('walking-tour-public', 'javascripts', 'js'));
$this->view->headLink()
->appendStylesheet('//code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css', 'all')
// ->appendStylesheet('//cdn.leafletjs.com/leaflet-0.7/leaflet.css', 'all')
// ->appendStylesheet('//cdn.leafletjs.com/leaflet-0.7/leaflet.ie.css', 'all', 'lte IE 8')
- ->appendStylesheet(src('walking-tour', 'css', 'css'));
+ ->appendStylesheet(src('walking-tour-public', 'css', 'css'));
// ->appendStylesheet(src('/../../../themes/mall-theme', 'css', 'css'));
}
@@ -117,20 +184,36 @@ public function queryAction()
$joins = array("$db->Item AS items ON items.id = locations.item_id");
$wheres = array("items.public = 1");
$prefix = $db->prefix;
+ $previewTourId = (int) $this->_request->getParam('tour_id');
+ $previewItemIds = array();
+ $postedItemIds = trim((string) $this->_request->getParam('item_ids'));
+
+ if ($postedItemIds !== '') {
+ foreach (explode(',', $postedItemIds) as $postedItemId) {
+ $postedItemId = (int) trim($postedItemId);
+ if ($postedItemId) {
+ $previewItemIds[] = $postedItemId;
+ }
+ }
+ }
// Filter public tours' items
$request_tour_id = $this->publicTours();
$colorArray = array();
- $tourItemTable = $db->getTable('TourItem');
+ $tourItemTable = $db->getTable('WalkingTourItem');
$tourItemsIDs = array();
$returnArray = array();
foreach ($request_tour_id['id'] as $tour_id => $tour_title) {
+ if ($previewTourId && $tour_id == $previewTourId) {
+ $tourItemsIDs[$tour_id] = $previewItemIds;
+ continue;
+ }
+
if ($tour_id != 0) {
- $tourItemsDat = $tourItemTable->fetchObjects("SELECT item_id FROM " . $prefix . "tour_items
- WHERE tour_id = $tour_id");
+ $tourItemsDat = $tourItemTable->fetchObjects("SELECT item_id FROM " . $prefix . "walking_tour_items WHERE tour_id = $tour_id");
} else {
- $tourItemsDat = $tourItemTable->fetchObjects("SELECT item_id FROM " . $prefix . "tour_items");
+ $tourItemsDat = $tourItemTable->fetchObjects("SELECT item_id FROM " . $prefix . "walking_tour_items");
}
$tourItemsIDs[$tour_id] = array();
foreach ($tourItemsDat as $dat) {
@@ -140,6 +223,20 @@ public function queryAction()
foreach ($tourItemsIDs as $tour_id => $item_array) {
+ $returnArray[$tour_id]["Data"] = array('type' => 'FeatureCollection', 'features' => array());
+ $returnArray[$tour_id]["Color"] = $request_tour_id['color'][$tour_id];
+ $returnArray[$tour_id]["Tour Name"] = $request_tour_id['id'][$tour_id];
+ $returnArray[$tour_id]["Description"] = $request_tour_id['description'][$tour_id];
+ $returnArray[$tour_id]["Credits"] = $request_tour_id['credits'][$tour_id];
+
+ $tourTable = $db->getTable('WalkingTour');
+ $tour = $tourTable->find($tour_id);
+ $returnArray[$tour_id]["Route"] = $tour ? $tour->route : null;
+
+ if (empty($item_array)) {
+ continue;
+ }
+
$tourItemsID = implode(", ", $item_array);
$wheres = array("items.public = 1");
$wheres[] = $db->quoteInto("items.id IN ($tourItemsID)", Zend_Db::INT_TYPE);
@@ -154,6 +251,7 @@ public function queryAction()
}
$sql .= "\nGROUP BY items.id";
+ // TODO ERROR
$dbItems = $db->query($sql)->fetchAll();
$orderedItems = array();
@@ -166,7 +264,6 @@ public function queryAction()
}
}
// Build geoJSON: http://www.geojson.org/geojson-spec.html
- $returnArray[$tour_id]["Data"] = array('type' => 'FeatureCollection', 'features' => array());
foreach ($orderedItems as $row) {
$returnArray[$tour_id]["Data"]['features'][] = array(
'type' => 'Feature',
@@ -180,14 +277,6 @@ public function queryAction()
),
);
}
- $returnArray[$tour_id]["Color"] = $request_tour_id['color'][$tour_id];
- $returnArray[$tour_id]["Tour Name"] = $request_tour_id['id'][$tour_id];
- $returnArray[$tour_id]["Description"] = $request_tour_id['description'][$tour_id];
- $returnArray[$tour_id]["Credits"] = $request_tour_id['credits'][$tour_id];
-
- $tourTable = $db->getTable('Tour');
- $tour = $tourTable->find($tour_id);
- $returnArray[$tour_id]["Route"] = $tour ? $tour->route : null;
}
$this->_helper->json($returnArray);
@@ -202,16 +291,24 @@ public function getItemAction()
if (!$this->_request->isXmlHttpRequest()) {
throw new Omeka_Controller_Exception_403;
}
- $item_id = $this->_request->getParam('id');
- $tour_id = $this->_request->getParam('tour');
+ $item_id = (int) $this->_request->getParam('id');
+ $tour_id = (int) $this->_request->getParam('tour_id', $this->_request->getParam('tour'));
+
+ if (!$item_id || !$tour_id) {
+ $this->_helper->json(array('error' => 'Missing tour or item id.'));
+ return;
+ }
$db = $this->_helper->db->getDb();
- $tourItemTable = $db->getTable('TourItem');
+ $tourItemTable = $db->getTable('WalkingTourItem');
$prefix = $db->prefix;
+ $tourItem = $tourItemTable->fetchObjects("SELECT * FROM " . $prefix . "walking_tour_items WHERE tour_id = $tour_id AND item_id = $item_id");
- $tourItem = $tourItemTable->fetchObjects("SELECT * FROM " . $prefix . "tour_items
- WHERE tour_id = $tour_id AND item_id = $item_id");
+ if (empty($tourItem)) {
+ $this->_helper->json(array('error' => 'Tour item not found.'));
+ return;
+ }
$exhibit_id = $tourItem[0]["exhibit_id"];
diff --git a/controllers/ToursController.php b/controllers/ToursController.php
index 696c735..1ec1924 100644
--- a/controllers/ToursController.php
+++ b/controllers/ToursController.php
@@ -1,12 +1,12 @@
_helper->db->setDefaultModelName( 'Tour' );
+ $this->_helper->db->setDefaultModelName( 'WalkingTour' );
}
}
diff --git a/helpers/TourFunctions.php b/helpers/TourFunctions.php
index d51ef56..87e552f 100644
--- a/helpers/TourFunctions.php
+++ b/helpers/TourFunctions.php
@@ -34,39 +34,39 @@ function availableExhibit() {
}
}
-function has_tours()
+function has_walking_tours()
{
return( total_tours() > 0 );
}
-function has_tours_for_loop()
+function has_walking_tours_for_loop()
{
$view = get_view();
- return $view->tours && count( $view->tours );
+ return $view->walking_tours && count( $view->walking_tours );
}
-function tour( $fieldName, $options=array(), $tour=null )
+function tour( $fieldName, $options=array(), $walking_tour=null )
{
- if( ! $tour ) {
- $tour = get_current_tour();
+ if( ! $walking_tour ) {
+ $walking_tour = get_current_tour();
}
switch( strtolower( $fieldName ) ) {
case 'id':
- $text = $tour->id;
+ $text = $walking_tour->id;
break;
case 'title':
- $text = $tour->title;
+ $text = $walking_tour->title;
break;
case 'description':
- $text = $tour->description;
+ $text = $walking_tour->description;
break;
case 'credits':
- $text = $tour->credits;
+ $text = $walking_tour->credits;
break;
case 'postscript_text':
- $text = $tour->postscript_text;
+ $text = $walking_tour->postscript_text;
break;
default:
throw new Exception( "\"$fieldName\" does not exist for tours!" );
@@ -92,7 +92,7 @@ function tour( $fieldName, $options=array(), $tour=null )
function get_current_tour()
{
- return get_view()->tour;
+ return get_view()->walking_tour;
}
function link_to_tour(
@@ -116,7 +116,7 @@ function link_to_tour(
function total_tours()
{
$view = get_view();
- return count( $view->tours );
+ return count( $view->walking_tours );
}
function nls2p($str) {
diff --git a/models/Tour.php b/models/WalkingTour.php
similarity index 88%
rename from models/Tour.php
rename to models/WalkingTour.php
index cac1f09..5a6d4e3 100644
--- a/models/Tour.php
+++ b/models/WalkingTour.php
@@ -1,12 +1,12 @@
'getItems','Image' => 'getImage' );
+ protected $_related = array(
+ 'Items' => 'getItems',
+ 'Image' => 'getImage'
+ );
public function _initializeMixins()
{
@@ -32,7 +35,7 @@ public function getItems()
public function removeAllItems( ) {
$db = get_db();
- $tiTable = $db->getTable( 'TourItem' );
+ $tiTable = $db->getTable( 'WalkingTourItem' );
$select = $tiTable->getSelect();
$select->where( 'tour_id = ?', array( $this->id ) );
@@ -54,7 +57,7 @@ public function addItem( $item_id, $exhibit_id = 0 , $ordinal = null )
# Get the next ordinal
$db = get_db();
- $tiTable = $db->getTable( 'TourItem' );
+ $tiTable = $db->getTable( 'WalkingTourItem' );
$select = $tiTable->getSelectForCount();
$select->where( 'tour_id = ?', array( $this->id ) );
if($ordinal === null) {
@@ -62,7 +65,7 @@ public function addItem( $item_id, $exhibit_id = 0 , $ordinal = null )
}
# Create, assign, and save the new tour item connection
- $tourItem = new TourItem;
+ $tourItem = new WalkingTourItem;
$tourItem->tour_id = $this->id;
$tourItem->item_id = $item_id;
$tourItem->ordinal = $ordinal;
@@ -96,6 +99,7 @@ protected function afterSave($args)
{
$post=$args['post'];
if($post && isset($post['tour_item_ids']) && !$args['insert']){
+ // if($post && isset($post['tour_item_ids'])){
$this->removeAllItems();
diff --git a/models/TourItem.php b/models/WalkingTourItem.php
similarity index 77%
rename from models/TourItem.php
rename to models/WalkingTourItem.php
index 0553116..c3d3186 100644
--- a/models/TourItem.php
+++ b/models/WalkingTourItem.php
@@ -4,7 +4,7 @@
* Tour Item.
* @package: Omeka
*/
-class TourItem extends Omeka_Record_AbstractRecord
+class WalkingTourItem extends Omeka_Record_AbstractRecord
{
public $tour_id;
public $item_id;
@@ -12,18 +12,18 @@ class TourItem extends Omeka_Record_AbstractRecord
public $exhibit_id = -1;
protected $_related = array(
- 'Tour' => 'getTour',
+ 'WalkingTour' => 'getWalkingTour',
'Item' => 'getItem',
);
protected function getItem()
{
- return $this->getTable( 'Item' )->find( $this->item_id );
+ return $this->getTable( 'WalkingTourItem' )->find( $this->item_id );
}
- protected function getTour()
+ protected function getWalkingTour()
{
- return $this->getTable( 'Tour' )->find( $this->tour_id );
+ return $this->getTable( 'WalkingTour' )->find( $this->tour_id );
}
protected function _validate()
diff --git a/models/TourTable.php b/models/WalkingTourTable.php
similarity index 81%
rename from models/TourTable.php
rename to models/WalkingTourTable.php
index 1f5de47..20a312b 100644
--- a/models/TourTable.php
+++ b/models/WalkingTourTable.php
@@ -1,6 +1,6 @@
getTable( 'Item' );
$select = $itemTable->getSelect();
$iAlias = $itemTable->getTableAlias();
- $select->joinInner( array( 'ti' => $db->TourItem ),
+ $select->joinInner( array( 'ti' => $db->WalkingTourItem ),
"ti.item_id = $iAlias.id", array() );
$select->where( 'ti.tour_id = ?', array( $tour_id ) );
$select->order( 'ti.ordinal ASC' );
$items = $itemTable->fetchObjects( "SELECT i.*, ti.ordinal, ti.exhibit_id
- FROM ".$prefix."items i LEFT JOIN ".$prefix."tour_items ti
+ FROM ".$prefix."items i LEFT JOIN ".$prefix."walking_tour_items ti
ON i.id = ti.item_id
WHERE ti.tour_id = ?
ORDER BY ti.ordinal ASC",
@@ -31,13 +31,13 @@ public function findImageByTourId( $tour_id ) {
$itemTable = $this->getTable( 'File' );
$select = $itemTable->getSelect();
$iAlias = $itemTable->getTableAlias();
- $select->joinInner( array( 'ti' => $db->TourItem ),
+ $select->joinInner( array( 'ti' => $db->WalkingTourItem ),
"ti.item_id = $iAlias.id", array() );
$select->where( 'ti.tour_id = ?', array( $tour_id ) );
$select->order( 'ti.ordinal ASC' );
$items = $itemTable->fetchObjects( "SELECT f.*, ti.ordinal
- FROM ".$prefix."files f LEFT JOIN ".$prefix."tour_items ti
+ FROM ".$prefix."files f LEFT JOIN ".$prefix."walking_tour_items ti
ON i.id = ti.item_id
WHERE ti.tour_id = ?
ORDER BY ti.ordinal ASC",
@@ -49,7 +49,7 @@ public function findImageByTourId( $tour_id ) {
public function getSelect()
{
- $select = parent::getSelect()->order('tours.id');
+ $select = parent::getSelect()->order('walking_tours.id');
$permissions = new Omeka_Db_Select_PublicPermissions( 'WalkingTourBuilder_Tours' );
$permissions->apply( $select, 'tours', null );
diff --git a/plugin.ini b/plugin.ini
index 6de57f6..5ea789b 100755
--- a/plugin.ini
+++ b/plugin.ini
@@ -5,7 +5,7 @@ description="Adds the ability to create and display walking tours on a map"
license="GPLv3"
link=""
support_link="https://github.com/DigitalCarleton/WalkingTour"
-version="1.0.1"
+version="1.0.3"
omeka_minimum_version="3.0"
omeka_target_version="3.1.2"
tags="map, tour"
diff --git a/routes.ini b/routes.ini
index 0fbe13a..160efc9 100644
--- a/routes.ini
+++ b/routes.ini
@@ -1,22 +1,22 @@
-[routes]
-tours.route = "tours/:action"
+[routes] ; for admin site
+tours.route = "walking-tours/:action"
tours.defaults.module = walking-tour
tours.defaults.controller = tours
tours.defaults.action = "browse"
-tourAction.route = "tours/:action/:id"
+tourAction.route = "walking-tours/:action/:id"
tourAction.defaults.module = walking-tour
tourAction.defaults.controller = tours
tourAction.defaults.action = "show"
tourAction.reqs.id = "\d+"
-tourItemAction.route = "tours/edit/:id/:action/:item"
+tourItemAction.route = "walking-tours/edit/:id/:action/:item"
tourItemAction.defaults.module = walking-tour
tourItemAction.defaults.controller = tours
tourItemAction.reqs.id = "\d+"
tourItemAction.reqs.item = "\d+"
-oldTour.route = "tour-builder/tours/:action/:id"
+oldTour.route = "tour-builder/walking-tours/:action/:id"
oldTour.defaults.module = walking-tour
oldTour.defaults.controller = tours
oldTour.defaults.action = "browse"
diff --git a/views/admin/css/tour-1.7.css b/views/admin/css/tour-1.7.css
index a357198..9f0ce95 100644
--- a/views/admin/css/tour-1.7.css
+++ b/views/admin/css/tour-1.7.css
@@ -1,111 +1,194 @@
-#admin-tour-image img{max-width: 100%; }
-#tour.edit #admin-tour-image img{margin: 1em 0;}
-#tour.show #admin-tour-image img{margin: 0 0;}
-#tour.edit input[type="text"]{margin-bottom:0; width:100%;}
-#tour.edit input#image{background:#eaeaea;padding:.5em 0 .5em .5em;width: 100%;border: 1px solid #D8D8D8;}
-#tour.edit p.explanation{padding:.25em 0;}
-#tour.edit .file-helper{display: inline-block;font-style: italic;padding: .5em 0 0;}
-
-#tour.browse .fa{
- font-family:"FontAwesome";
+#admin-tour-image img {
+ max-width: 100%;
+}
+
+#tour.edit #admin-tour-image img {
+ margin: 1em 0;
+}
+
+#tour.show #admin-tour-image img {
+ margin: 0 0;
+}
+
+#tour.edit input[type="text"] {
+ margin-bottom: 0;
+ width: 100%;
+}
+
+#tour.edit input#image {
+ background: #eaeaea;
+ padding: .5em 0 .5em .5em;
+ width: 100%;
+ border: 1px solid #D8D8D8;
+}
+
+#tour.edit p.explanation {
+ padding: .25em 0;
+}
+
+#tour.edit .file-helper {
+ display: inline-block;
+ font-style: italic;
+ padding: .5em 0 0;
+}
+
+#tour-form {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+#tour-form #save.panel,
+#tour-form #public-featured.panel */ {
+ background: #fff;
+ border: 1px solid #d8d8d8;
+ margin-bottom: 1rem;
+}
+
+#tour-form #public-featured .checkbox {
+ margin-bottom: 0.75rem;
+}
+
+#tour-form .tour-form-sidebar {
+ background: #fff;
+ box-sizing: border-box;
+ padding: 0 0 1rem 0;
+}
+
+#tour.browse .fa {
+ font-family: "FontAwesome";
font-style: normal;
font-weight: lighter;
- font-size:1.35em;
- line-height:inherit;
+ font-size: 1.35em;
+ line-height: inherit;
vertical-align: middle;
padding-left: .25em;
- text-shadow:0 0 2px #fff;
+ text-shadow: 0 0 2px #fff;
}
-#tour.browse i.fa.fa-camera:after{
+
+#tour.browse i.fa.fa-camera:after {
content: "\f030";
- color: #ccc;
+ color: #ccc;
float: right;
display: inline-block;
}
-.hidden{
- display:none;
+
+.hidden {
+ display: none;
visibility: hidden;
}
-.admin-tour-browse-meta{
+
+.admin-tour-browse-meta {
margin: .25em 0;
- color:#777;
+ color: #777;
}
-#tourbuilder-item-list{
+
+#tourbuilder-item-list {
padding-left: 0;
}
-#tour-items-picker{
- min-height: 600px;
+
+#tour-items-picker {
+ min-height: 600px;
min-height: 90vh;
}
-#tour-item-search, #tour-item-exhibit-search{
- padding: 10px;
- width: 100%;
- box-sizing: border-box;
- margin: 0 !important;
- border: 0px solid transparent;
+
+#tour-item-search,
+#tour-item-exhibit-search {
+ padding: 10px;
+ width: 100%;
+ box-sizing: border-box;
+ margin: 0 !important;
+ border: 0px solid transparent;
}
-.input-container{
- background:linear-gradient(to bottom, #22546b, #102d3b);
+
+.input-container {
+ background: linear-gradient(to bottom, #22546b, #102d3b);
padding: 1em !important;
box-sizing: border-box;
}
-.exhibit-input-container{
+
+.exhibit-input-container {
margin-left: 3rem;
border: 1px solid #D6D5C2;
box-sizing: border-box;
}
-.exhibit{
+
+.exhibit {
cursor: pointer;
- margin: 0 1em;
- flex: 0 0 80px;
+ margin: 0 1em;
+ flex: 0 0 80px;
}
-.remove{
+
+.remove {
cursor: pointer;
flex: 0 0;
}
-.tour-item-ui{
+
+.tour-item-ui {
display: flex;
- padding-bottom: 0.5em;
+ padding-bottom: 0.5em;
}
-.tour-item-header{
+
+.tour-item-header {
display: flex;
}
-.tour-item-title p{
+
+.tour-item-title p {
margin: 0;
}
+
.exhibit-name {
margin-top: 0.2em;
- color: #666;
- font-style: italic;
+ color: #666;
+ font-style: italic;
}
-.ui-menu-item{
+.ui-menu-item {
padding-left: 5px;
}
-#sortable { list-style-type: none; margin: 2em 0 0; padding: 0; width: 100%;}
+#sortable {
+ list-style-type: none;
+ margin: 2em 0 0;
+ padding: 0;
+ width: 100%;
+}
+
#sortable li {
display: flex;
padding: 0.5em 1em;
- margin:0;
- cursor: move; cursor: grab; cursor: -moz-grab; cursor: -webkit-grab;
+ margin: 0;
+ cursor: move;
+ cursor: grab;
+ cursor: -moz-grab;
+ cursor: -webkit-grab;
flex-direction: column;
}
-#sortable li span:first-child {flex-grow: 1;}
-.ui-state-highlight { line-height: 1.2em; color:#fff;background: linear-gradient(to bottom, #eaf2e1, #8eb763);text-shadow: -1px -1px 1px rgba(0,0,0,.5);}
-svg#drag{
+#sortable li span:first-child {
+ flex-grow: 1;
+}
+
+.ui-state-highlight {
+ line-height: 1.2em;
+ color: #fff;
+ background: linear-gradient(to bottom, #eaf2e1, #8eb763);
+ text-shadow: -1px -1px 1px rgba(0, 0, 0, .5);
+}
+
+svg#drag {
margin-right: 1em;
vertical-align: middle;
margin-top: 0.4em;
}
-.ui-state-highlight svg#drag{
- fill-opacity:.55;
+.ui-state-highlight svg#drag {
+ fill-opacity: .55;
}
-.ui-state-highlight svg#drag #top path{
- fill:#fff;
+
+.ui-state-highlight svg#drag #top path {
+ fill: #fff;
}
-.ui-state-highlight svg#drag #shadow path{
- fill:#eaf2e1;
+
+.ui-state-highlight svg#drag #shadow path {
+ fill: #eaf2e1;
}
\ No newline at end of file
diff --git a/views/admin/javascripts/walking-tour.js b/views/admin/javascripts/walking-tour-admin.js
similarity index 79%
rename from views/admin/javascripts/walking-tour.js
rename to views/admin/javascripts/walking-tour-admin.js
index aa72e98..09ef88c 100755
--- a/views/admin/javascripts/walking-tour.js
+++ b/views/admin/javascripts/walking-tour-admin.js
@@ -1,4 +1,8 @@
jQuery(document).ready(function ($) {
+ var currentTour = (typeof window.currentTour !== 'undefined' && window.currentTour !== null && window.currentTour !== '')
+ ? window.currentTour.toString()
+ : null;
+
var markers;
var map;
var markerData;
@@ -25,7 +29,7 @@ jQuery(document).ready(function ($) {
var IS_AUTO_FIT;
var historicMapLayer;
-
+
var jqXhr;
var locationMarker;
var allItems = {};
@@ -34,7 +38,7 @@ jQuery(document).ready(function ($) {
var baseUrl = window.location.origin;
var urlpaths = window.location.pathname.split("/");
if (urlpaths[1] != "admin") { baseUrl += "/" + urlpaths[1] };
-
+
/*
* JQuery Setup
*/
@@ -242,12 +246,165 @@ jQuery(document).ready(function ($) {
$('#info-panel-container').fadeToggle(200, 'linear');
});
+ async function refreshCurrentTourPreview() {
+ if (!currentTour) {
+ return;
+ }
+
+ var itemIds = ($('#tour_item_ids').val() || '')
+ .split(',')
+ .map(function (value) {
+ return parseInt(value, 10);
+ })
+ .filter(function (value) {
+ return !isNaN(value) && value > 0;
+ });
+
+ if (!itemIds.length) {
+ markerData[currentTour] = markerData[currentTour] || {};
+ markerData[currentTour].Data = { type: 'FeatureCollection', features: [] };
+ markerData[currentTour].geoJson = L.geoJson([]);
+ markerData[currentTour].walkingPath = L.polyline([], {
+ color: markerData[currentTour].Color || '#000000',
+ weight: 3,
+ opacity: 1,
+ smoothFactor: 1
+ });
+ doFilters();
+ return;
+ }
+
+ try {
+ var response = await $.ajax({
+ url: baseUrl + '/walking-tour/index/preview',
+ method: 'POST',
+ dataType: 'json',
+ data: {
+ tour_id: currentTour,
+ item_ids: itemIds.join(',')
+ }
+ });
+
+ markerData[currentTour] = response;
+
+ var itemIDList = [];
+ var features = (response.Data && response.Data.features) ? response.Data.features : [];
+ features.forEach(function (feature) {
+ itemIDList.push(feature.properties.id);
+ });
+
+ var previewMarkerFontHtmlStyles = `
+ transform: rotate(-45deg);
+ color:white;
+ text-align: center;
+ padding: 0.2rem 0 0.18rem 0;
+ font-size: 15px;
+ `;
+
+ var numMarker = 1;
+ var geoJsonLayer = L.geoJson(features, {
+ pointToLayer: function (feature, latlng) {
+ var numberIcon = L.divIcon({
+ className: "my-custom-pin",
+ iconSize: [25, 41],
+ iconAnchor: [12, 40],
+ popupAnchor: [0, -5],
+ html: ` ${numMarker}
`
+ });
+ numMarker++;
+ return L.marker(latlng, { icon: numberIcon });
+ }
+ });
+
+ markerData[currentTour].Data = response.Data;
+ markerData[currentTour].geoJson = geoJsonLayer;
+
+ var pointList = [];
+ features.forEach(function (feature) {
+ if (feature.geometry && feature.geometry.coordinates) {
+ pointList.push(new L.LatLng(feature.geometry.coordinates[1], feature.geometry.coordinates[0]));
+ }
+ });
+
+ async function getRoute(points) {
+ var pointsParam = [];
+ points.forEach(function (ele) {
+ pointsParam.push([ele.lng, ele.lat]);
+ });
+ if (pointsParam.length < 2) {
+ return null;
+ }
+ const response = await fetch('https://api.openrouteservice.org/v2/directions/foot-walking/geojson', {
+ method: 'POST',
+ headers: {
+ 'Accept': 'application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8',
+ 'Content-Type': 'application/json',
+ 'Authorization': '5b3ce3597851110001cf62489dde4c6690bc423bb86bd99921c5da77'
+ },
+ body: `{"coordinates": ${JSON.stringify(pointsParam)}}`
+ });
+
+ if (!response.ok) {
+ const errorText = await response.text();
+ console.error('OpenRouteService API error:', response.status, response.statusText, errorText);
+ return null;
+ }
+
+ return response.json();
+ }
+
+ if (pointList.length >= 2) {
+ const routeData = await getRoute(pointList);
+ if (routeData && routeData.features && routeData.features.length) {
+ var path = routeData.features[0].geometry.coordinates;
+ path = path.map(function (coord) {
+ return [coord[1], coord[0]];
+ });
+ markerData[currentTour].walkingPath = L.polyline(path, {
+ color: response.Color || '#000000',
+ weight: 3,
+ opacity: 1,
+ smoothFactor: 1
+ });
+ } else {
+ markerData[currentTour].walkingPath = L.polyline([], {
+ color: response.Color || '#000000',
+ weight: 3,
+ opacity: 1,
+ smoothFactor: 1
+ });
+ }
+ } else {
+ markerData[currentTour].walkingPath = L.polyline([], {
+ color: response.Color || '#000000',
+ weight: 3,
+ opacity: 1,
+ smoothFactor: 1
+ });
+ }
+
+ createCustomCSS();
+ doFilters();
+ } catch (error) {
+ console.error('Failed to refresh tour preview:', error);
+ }
+ }
+
+ $(document).on('tourItemsUpdated', function () {
+ refreshCurrentTourPreview();
+ });
+
$(document).on('tourOrderChanged', async function (event, updatedOrder) {
async function getRoute(points) {
const coordinates = points.map(point => [point[1], point[0]]); // Convert to [lng, lat] format
const url = "https://api.openrouteservice.org/v2/directions/foot-walking/geojson";
-
+
+ if (coordinates.length < 2) {
+ console.error("At least two coordinates are required to request a route.", coordinates);
+ return null;
+ }
+
try {
const response = await fetch(url, {
method: "POST",
@@ -259,12 +416,13 @@ jQuery(document).ready(function ($) {
coordinates: coordinates
})
});
-
+
if (!response.ok) {
- console.error("OpenRouteService API error:", response.statusText);
+ const errorText = await response.text();
+ console.error("OpenRouteService API error:", response.status, response.statusText, errorText);
return null;
}
-
+
const data = await response.json();
const route = data.features[0].geometry.coordinates.map(coord => [coord[1], coord[0]]); // Convert back to [lat, lng]
saveRoute(data);
@@ -275,11 +433,11 @@ jQuery(document).ready(function ($) {
return null;
}
}
-
+
if (markers) {
map.removeLayer(markers);
}
-
+
// Map the updated order to coordinates
const reorderedPoints = updatedOrder.map((id, index) => {
const feature = markerData[currentTour].Data.features.find(f => f.properties.id === id);
@@ -289,15 +447,15 @@ jQuery(document).ready(function ($) {
}
return feature ? [feature.geometry.coordinates[1], feature.geometry.coordinates[0]] : null;
}).filter(point => point !== null);
-
+
if (reorderedPoints.length < 2) {
console.error("At least two points are required to calculate a route.");
return;
}
-
+
// Query OpenRouteService for the new route
const route = await getRoute(reorderedPoints);
-
+
const reorderedPath = L.polyline(route, {
color: markerData[currentTour].Color || '#000000',
weight: 3,
@@ -321,7 +479,7 @@ jQuery(document).ready(function ($) {
const marker = L.marker(latlng, { icon: numberIcon });
markers.addLayer(marker);
});
-
+
markers.addLayer(reorderedPath);
map.addLayer(markers);
});
@@ -330,7 +488,7 @@ jQuery(document).ready(function ($) {
* Query backend
*/
-
+
jqXhr = $.post(baseUrl + '/walking-tour/index/map-config', function (response) {
mapSetUp(response);
doQuery();
@@ -339,7 +497,7 @@ jQuery(document).ready(function ($) {
// Retain previous form state, if needed.
retainFormState();
- function mapLocateCenter(map){
+ function mapLocateCenter(map) {
map.flyTo(MAP_CENTER, MAP_ZOOM);
}
@@ -446,10 +604,10 @@ jQuery(document).ready(function ($) {
tour_id: currentTour,
route: JSON.stringify(route)
},
- success: function(response) {
+ success: function (response) {
console.log('Route saved to database');
},
- error: function(xhr, status, error) {
+ error: function (xhr, status, error) {
console.error('Failed to save route:', error);
}
})
@@ -475,6 +633,10 @@ jQuery(document).ready(function ($) {
points.forEach(ele => {
pointsParam.push([ele.lng, ele.lat])
})
+ if (pointsParam.length < 2) {
+ console.error("At least two coordinates are required to request a route.", pointsParam);
+ return { features: [] };
+ }
url = "https://api.openrouteservice.org/v2/directions/foot-walking/geojson"
const response = await fetch(url, {
method: "POST", // *GET, POST, PUT, DELETE, etc.
@@ -486,6 +648,11 @@ jQuery(document).ready(function ($) {
},
body: `{"coordinates": ${JSON.stringify(pointsParam)}}`, // body data type must match "Content-Type" header
})
+ if (!response.ok) {
+ const errorText = await response.text();
+ console.error("OpenRouteService API error:", response.status, response.statusText, errorText);
+ return { features: [] };
+ }
return response.json();
}
@@ -495,6 +662,13 @@ jQuery(document).ready(function ($) {
var markerBounds = L.latLngBounds();
jqXhr = $.post(baseUrl + '/walking-tour/index/query', function (response) {
markerData = response;
+ console.log(markerData);
+ if (!currentTour) {
+ var tourIds = Object.keys(markerData || {});
+ if (tourIds.length) {
+ currentTour = tourIds[0];
+ }
+ }
dataArray = Object.entries(markerData)
for (const tour in markerData) {
itemArray = itemArray.concat(markerData[tour]['Data']['features'])
@@ -528,7 +702,7 @@ jQuery(document).ready(function ($) {
onEachFeature: function (feature, layer) {
layer.on('click', function (e) {
// center click location
- map.flyTo(e.latlng,MAP_ZOOM + MAP_MAX_ZOOM_STOP);
+ map.flyTo(e.latlng, MAP_ZOOM + MAP_MAX_ZOOM_STOP);
// Close the filtering
var filterButton = $('filter-button');
filterButton.removeClass('on').
@@ -539,7 +713,7 @@ jQuery(document).ready(function ($) {
var marker = this;
//response = allItems[`${tourId}:${feature.properties.id}`]
//if (response == undefined) {
- // $.post(baseUrl + '/walking-tour//index/get-item', { id: feature.properties.id, tour: tourId }, function (response) {
+ // $.post(baseUrl + '/walking-tour/index/get-item', { id: feature.properties.id, tour: tourId }, function (response) {
// allItems[`${tourId}:${feature.properties.id}`] = response;
// featureOnclickAction(response, layer, marker, itemIDList, value, tourId);
// })
@@ -563,36 +737,45 @@ jQuery(document).ready(function ($) {
pointList[i] = point;
}
getOverallPath(pointList, key).then((data) => {
- saveRoute(data);
-
- var path = data["features"][0]["geometry"]["coordinates"];
- path = orderCoords(path);
- for (var p of path) {
- walkingPath.push(p);
+ if (data && data.features && data.features.length) {
+ saveRoute(data);
+
+ var path = data.features[0].geometry.coordinates;
+ path = orderCoords(path);
+ for (var p of path) {
+ walkingPath.push(p);
+ }
+ var tourPolyline = new L.Polyline(walkingPath, {
+ color: value["Color"],
+ weight: 3,
+ opacity: 1,
+ smoothFactor: 1
+ });
+
+ markerData[tourId].walkingPath = tourPolyline;
+ } else {
+ console.error('OpenRouteService returned no features for tour', tourId, data);
+ markerData[tourId].walkingPath = new L.Polyline([], { color: value["Color"] || '#000000', weight: 3 });
}
- var tourPolyline = new L.Polyline(walkingPath, {
- color: value["Color"],
- weight: 3,
- opacity: 1,
- smoothFactor: 1
- });
-
- markerData[tourId].walkingPath = tourPolyline;
- resolve()
+ resolve();
+ }).catch(function (err) {
+ console.error('Error fetching route for tour', tourId, err);
+ markerData[tourId].walkingPath = new L.Polyline([], { color: value["Color"] || '#000000', weight: 3 });
+ resolve();
});
});
})
Promise.all(requests).then(() => {
createCustomCSS();
- if (IS_AUTO_FIT){
- map.fitBounds(markerBounds, {padding: [10, 10]})
- mapLocateCenter = function(map) {
- map.fitBounds(markerBounds, {padding: [10, 10]})
- }
+ if (IS_AUTO_FIT) {
+ map.fitBounds(markerBounds, { padding: [10, 10] })
+ mapLocateCenter = function (map) {
+ map.fitBounds(markerBounds, { padding: [10, 10] })
+ }
var curZoom = map._zoom;
- map.setMaxZoom( curZoom + MAP_MAX_ZOOM_STOP);
- map.setMinZoom( curZoom - MAP_MIN_ZOOM_STOP);
- // map["options"]["minZoom"] = curZoom - MAP_MIN_ZOOM_STOP
+ map.setMaxZoom(curZoom + MAP_MAX_ZOOM_STOP);
+ map.setMinZoom(curZoom - MAP_MIN_ZOOM_STOP);
+ // map["options"]["minZoom"] = curZoom - MAP_MIN_ZOOM_STOP
}
doFilters();
});
@@ -605,6 +788,7 @@ jQuery(document).ready(function ($) {
* This must be called on every form change.
*/
function doFilters() {
+ console.log(markers)
// Remove the current markers.
if (markers) {
map.removeLayer(markers);
@@ -662,10 +846,10 @@ jQuery(document).ready(function ($) {
for (const tour_id in markerData) {
var color = markerData[tour_id]['Color']
- if (color.length == 0){
+ if (color.length == 0) {
color = "#000000"
}
-
+
var rgb = hexToRgb(color)
css += `#filters div label.label${tour_id}:before {
background-color: ${color} !important;
@@ -809,9 +993,9 @@ jQuery(document).ready(function ($) {
rightContent += 'No descriptions available.
';
}
rightContent += ''
infoContent += '';
@@ -915,9 +1099,9 @@ jQuery(document).ready(function ($) {
return b_new
}
- /*
- * Revert to default (original) form state.
- */
+ /*
+ * Revert to default (original) form state.
+ */
function revertFormState() {
if (historicMapLayer) {
removeHistoricMapLayer();
@@ -1020,10 +1204,10 @@ jQuery(document).ready(function ($) {
function hexToRgb(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
- r: parseInt(result[1], 16),
- g: parseInt(result[2], 16),
- b: parseInt(result[3], 16)
+ r: parseInt(result[1], 16),
+ g: parseInt(result[2], 16),
+ b: parseInt(result[3], 16)
} : null;
- }
+ }
});
diff --git a/views/admin/tours/add.php b/views/admin/tours/add.php
index ed96d43..2571ded 100644
--- a/views/admin/tours/add.php
+++ b/views/admin/tours/add.php
@@ -1,43 +1,58 @@
'Add Tour', 'content_class' => 'vertical-nav',
- 'bodyclass' => 'tours primary add-tour-form' ) );
+echo head(array(
+ 'title' => 'Add Tour',
+ 'content_class' => 'vertical-nav',
+ 'bodyclass' => 'tours primary add-tour-form'
+));
echo flash();
?>
-
+
\ No newline at end of file
diff --git a/views/admin/tours/browse.php b/views/admin/tours/browse.php
index a34b229..06a0407 100644
--- a/views/admin/tours/browse.php
+++ b/views/admin/tours/browse.php
@@ -20,10 +20,10 @@
-
+
@@ -38,7 +38,7 @@
'show','id' => $tour->id ), 'tourAction' );
$editUrl = url( array( 'action' => 'edit','id' => $tour->id ), 'tourAction' );
@@ -72,7 +72,7 @@
-
+
diff --git a/views/admin/tours/edit.php b/views/admin/tours/edit.php
index 9e7363a..32b26e4 100644
--- a/views/admin/tours/edit.php
+++ b/views/admin/tours/edit.php
@@ -1,62 +1,76 @@
$tourTitle, 'content_class' => 'vertical-nav',
- 'bodyclass' => 'edit','bodyid'=>'tour' ) );
+echo head(array(
+ 'title' => $tourTitle,
+ 'content_class' => 'vertical-nav',
+ 'bodyclass' => 'tours primary edit add-tour-form',
+ 'bodyid' => 'tour'
+));
echo flash();
?>