pictures table
This commit is contained in:
14
files/db/update_v2_to_v3.sql
Normal file
14
files/db/update_v2_to_v3.sql
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
CREATE TABLE `pictures` (
|
||||||
|
`id_picture` int(10) UNSIGNED auto_increment,
|
||||||
|
`id_project` int(10) UNSIGNED,
|
||||||
|
`filename` VARCHAR(100) NOT NULL,
|
||||||
|
`taken_on` DATETIME,
|
||||||
|
`timestamp` DATETIME,
|
||||||
|
`rotate` SMALLINT,
|
||||||
|
`led` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id_picture`),
|
||||||
|
UNIQUE KEY `uni_file_name` (`filename`)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE pictures ADD INDEX(`id_project`);
|
||||||
|
ALTER TABLE pictures ADD FOREIGN KEY (`id_project`) REFERENCES projects(`id_project`);
|
||||||
147
inc/picture.php
Normal file
147
inc/picture.php
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Picture extends PhpObject {
|
||||||
|
|
||||||
|
//DB Tables
|
||||||
|
const PIC_TABLE = 'pictures';
|
||||||
|
|
||||||
|
//Picture folders
|
||||||
|
const PIC_FOLDER = 'files/';
|
||||||
|
const THUMB_FOLDER = self::PIC_FOLDER.'thumbs/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database Handle
|
||||||
|
* @var Db
|
||||||
|
*/
|
||||||
|
private $oDb;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Picture Project
|
||||||
|
* @var Project
|
||||||
|
*/
|
||||||
|
private $oProject;
|
||||||
|
private $asPics;
|
||||||
|
|
||||||
|
public function __construct(Db &$oDb, &$oProject) {
|
||||||
|
parent::__construct(__CLASS__, Settings::DEBUG);
|
||||||
|
$this->oDb = &$oDb;
|
||||||
|
$this->oProject = &$oProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPicsInfo() {
|
||||||
|
if(empty($this->asPics)) {
|
||||||
|
if($this->oProject->getProjectId()) {
|
||||||
|
$asPics = $this->oDb->selectRows(array(
|
||||||
|
'select' => array(Db::getId(self::PIC_TABLE), 'filename', 'taken_on', 'timestamp AS added_on', 'rotate'),
|
||||||
|
'from' => self::PIC_TABLE,
|
||||||
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId())
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach($asPics as &$asPic) {
|
||||||
|
$asPic['pic_path'] = self::getPicPath($asPic['filename']);
|
||||||
|
$asPic['thumb_path'] = self::getPicThumbnail($asPic['filename']);
|
||||||
|
}
|
||||||
|
$this->asPics = $asPics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->asPics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isProjectModeValid() {
|
||||||
|
return ($this->oProject->getMode() == Project::MODE_BLOG);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addPic($sPicName, $sMethod='upload') {
|
||||||
|
$sError = '';
|
||||||
|
if(!$this->isProjectModeValid() && $sMethod!='sync') $sError = 'Le projet (id='.$this->oProject->getProjectId().') n\'est pas en mode "blog"';
|
||||||
|
elseif($this->oDb->pingValue(self::PIC_TABLE, array('filename'=>$sPicName))) $sError = 'l\'image existe déjà';
|
||||||
|
else {
|
||||||
|
//Add picture to DB
|
||||||
|
$asPicInfo = self::getPicInfo($sPicName);
|
||||||
|
$iPicId = $this->oDb->insertRow(self::PIC_TABLE, array(
|
||||||
|
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||||
|
'filename' => $sPicName,
|
||||||
|
'taken_on' => date(Db::TIMESTAMP_FORMAT, $asPicInfo['taken_ts']),
|
||||||
|
'timestamp' => date(Db::TIMESTAMP_FORMAT, $asPicInfo['file_ts']),
|
||||||
|
'rotate' => $asPicInfo['rotate']
|
||||||
|
));
|
||||||
|
|
||||||
|
if(!$iPicId) $sError = 'l\'image n\'a pas pu être entrée en base';
|
||||||
|
else {
|
||||||
|
//Create thumbnail
|
||||||
|
self::getPicThumbnail($sPicName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($sError!='') {
|
||||||
|
$sError = 'Erreur lors de l\'ajout de "'.$sPicName.'" : '.$sError;
|
||||||
|
$this->addError($sError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One-shot function to initialize DB with existing images
|
||||||
|
*/
|
||||||
|
public function syncFileFolder() {
|
||||||
|
$asPicPaths = glob(self::getPicPath('*.{jpg,JPG,jpeg,JPEG,png,PNG}'), GLOB_BRACE);
|
||||||
|
foreach($asPicPaths as $sPicPath)
|
||||||
|
{
|
||||||
|
$sPicName = pathinfo($sPicPath, PATHINFO_BASENAME);
|
||||||
|
$this->addPic($sPicName, 'sync');
|
||||||
|
}
|
||||||
|
$this->setExtractMode(PhpObject::MODE_HTML);
|
||||||
|
return $this->getCleanMessageStack();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPicInfo($sPicName)
|
||||||
|
{
|
||||||
|
$sPicPath = self::getPicPath($sPicName);
|
||||||
|
$iPicTimeStamp = $iPicTakenTimeStamp = $iPicFileTimeStamp = 0;
|
||||||
|
$asExif = @exif_read_data($sPicPath, 0, true);
|
||||||
|
if(!$asExif) $asExif['FILE']['FileDateTime'] = filemtime($sPicPath);
|
||||||
|
|
||||||
|
//Timestamps
|
||||||
|
if(array_key_exists('EXIF', $asExif) && array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $iPicTakenTimeStamp = strtotime($asExif['EXIF']['DateTimeOriginal']);
|
||||||
|
if(array_key_exists('FILE', $asExif) && array_key_exists('FileDateTime', $asExif['FILE'])) $iPicFileTimeStamp = $asExif['FILE']['FileDateTime'];
|
||||||
|
|
||||||
|
//Merge timestamps
|
||||||
|
$iPicTimeStamp = ($iPicTakenTimeStamp > 0)?$iPicTakenTimeStamp:$iPicFileTimeStamp;
|
||||||
|
|
||||||
|
//Orientation
|
||||||
|
if(array_key_exists('IFD0', $asExif) && array_key_exists('Orientation', $asExif['IFD0'])) {
|
||||||
|
switch($asExif['IFD0']['Orientation'])
|
||||||
|
{
|
||||||
|
case 1: $sRotate = '0'; break; //None
|
||||||
|
case 3: $sRotate = '180'; break; //Flip over
|
||||||
|
case 6: $sRotate = '90'; break; //Clockwise
|
||||||
|
case 8: $sRotate = '-90'; break; //Trigo
|
||||||
|
default: $sRotate = '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else $sRotate = '0';
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'timestamp' => $iPicTimeStamp,
|
||||||
|
'taken_ts' => $iPicTakenTimeStamp,
|
||||||
|
'file_ts' => $iPicFileTimeStamp,
|
||||||
|
'rotate' => $sRotate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPicThumbnail($sPicName)
|
||||||
|
{
|
||||||
|
$sPicPath = self::getPicPath($sPicName);
|
||||||
|
$sThumbPath = self::getPicPath($sPicName, 'thumbnail');
|
||||||
|
|
||||||
|
if(!file_exists($sThumbPath)) $asThumbInfo = ToolBox::createThumbnail($sPicPath, 400, 0, $sThumbPath/*, false, array('jpg', 'jpeg', 'gif', 'png'), true*/);
|
||||||
|
else $asThumbInfo = array('error'=>'', 'out'=>$sThumbPath);
|
||||||
|
|
||||||
|
return ($asThumbInfo['error']=='')?$asThumbInfo['out']:$sPicPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getPicPath($sPicName, $sFileType='picture') {
|
||||||
|
return ($sFileType=='thumbnail'?self::THUMB_FOLDER:self::PIC_FOLDER).$sPicName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ class Project extends PhpObject {
|
|||||||
|
|
||||||
public function __construct(Db &$oDb) {
|
public function __construct(Db &$oDb) {
|
||||||
parent::__construct(__CLASS__, Settings::DEBUG);
|
parent::__construct(__CLASS__, Settings::DEBUG);
|
||||||
$this->oDb = $oDb;
|
$this->oDb = &$oDb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setProjectId($iProjectId=0) {
|
public function setProjectId($iProjectId=0) {
|
||||||
|
|||||||
145
inc/spot.php
145
inc/spot.php
@@ -13,10 +13,6 @@ class Spot extends Main
|
|||||||
const SPOT_TABLE = 'spots';
|
const SPOT_TABLE = 'spots';
|
||||||
const POST_TABLE = 'posts';
|
const POST_TABLE = 'posts';
|
||||||
|
|
||||||
//Picture folders
|
|
||||||
const PIC_FOLDER = 'files/';
|
|
||||||
const THUMB_FOLDER = self::PIC_FOLDER.'thumbs/';
|
|
||||||
|
|
||||||
const FORMAT_TIME = 'd/m/Y à H:i';
|
const FORMAT_TIME = 'd/m/Y à H:i';
|
||||||
|
|
||||||
const FEED_CHUNK_SIZE = 15;
|
const FEED_CHUNK_SIZE = 15;
|
||||||
@@ -27,15 +23,23 @@ class Spot extends Main
|
|||||||
*/
|
*/
|
||||||
private $oProject;
|
private $oProject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Picture Class
|
||||||
|
* @var Picture
|
||||||
|
*/
|
||||||
|
private $oPicture;
|
||||||
|
|
||||||
public function __construct($oClassManagement, $sProcessPage)
|
public function __construct($oClassManagement, $sProcessPage)
|
||||||
{
|
{
|
||||||
$asClasses = array(
|
$asClasses = array(
|
||||||
array('name'=>'project', 'project'=>true),
|
array('name'=>'project', 'project'=>true),
|
||||||
|
array('name'=>'picture', 'project'=>true),
|
||||||
array('name'=>'cacher', 'project'=>true)
|
array('name'=>'cacher', 'project'=>true)
|
||||||
);
|
);
|
||||||
parent::__construct($oClassManagement, $sProcessPage, $asClasses);
|
parent::__construct($oClassManagement, $sProcessPage, $asClasses);
|
||||||
|
|
||||||
$this->oProject = new Project($this->oDb);
|
$this->oProject = new Project($this->oDb);
|
||||||
|
$this->oPicture = new Picture($this->oDb, $this->oProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function install()
|
protected function install()
|
||||||
@@ -54,7 +58,8 @@ class Spot extends Main
|
|||||||
self::FEED_TABLE => array('ref_feed_id', Db::getId(self::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
|
self::FEED_TABLE => array('ref_feed_id', Db::getId(self::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
|
||||||
self::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
self::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
||||||
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to', 'geofile', 'timezone'),
|
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to', 'geofile', 'timezone'),
|
||||||
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), 'name', 'content', 'timestamp')
|
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), 'name', 'content', 'timestamp'),
|
||||||
|
Picture::PIC_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'taken_on', 'timestamp', 'rotate')
|
||||||
),
|
),
|
||||||
'types' => array
|
'types' => array
|
||||||
(
|
(
|
||||||
@@ -77,7 +82,10 @@ class Spot extends Main
|
|||||||
'active_to' => "DATETIME",
|
'active_to' => "DATETIME",
|
||||||
'geofile' => "VARCHAR(50)",
|
'geofile' => "VARCHAR(50)",
|
||||||
'timezone' => "VARCHAR(100)",
|
'timezone' => "VARCHAR(100)",
|
||||||
'last_update' => "DATETIME"
|
'last_update' => "DATETIME",
|
||||||
|
'filename' => "VARCHAR(100) NOT NULL",
|
||||||
|
'taken_on' => "DATETIME",
|
||||||
|
'rotate' => "SMALLINT"
|
||||||
),
|
),
|
||||||
'constraints' => array
|
'constraints' => array
|
||||||
(
|
(
|
||||||
@@ -88,6 +96,7 @@ class Spot extends Main
|
|||||||
self::FEED_TABLE => "INDEX(`ref_feed_id`)",
|
self::FEED_TABLE => "INDEX(`ref_feed_id`)",
|
||||||
self::SPOT_TABLE => "INDEX(`ref_spot_id`)",
|
self::SPOT_TABLE => "INDEX(`ref_spot_id`)",
|
||||||
Project::PROJ_TABLE => "UNIQUE KEY `uni_proj_name` (`codename`)",
|
Project::PROJ_TABLE => "UNIQUE KEY `uni_proj_name` (`codename`)",
|
||||||
|
Picture::PIC_TABLE => "UNIQUE KEY `uni_file_name` (`filename`)"
|
||||||
),
|
),
|
||||||
'cascading_delete' => array
|
'cascading_delete' => array
|
||||||
(
|
(
|
||||||
@@ -180,7 +189,7 @@ class Spot extends Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMessages()
|
public function getMarkers()
|
||||||
{
|
{
|
||||||
/* Adding another point to test
|
/* Adding another point to test
|
||||||
$test = $this->oDb->selectRow(self::MSG_TABLE, 1);
|
$test = $this->oDb->selectRow(self::MSG_TABLE, 1);
|
||||||
@@ -196,7 +205,7 @@ class Spot extends Main
|
|||||||
|
|
||||||
//Add pictures
|
//Add pictures
|
||||||
if($bSuccess) {
|
if($bSuccess) {
|
||||||
$asPics = $this->getPictures();
|
$asPics = $this->getPictures('taken_on');
|
||||||
|
|
||||||
//Sort messages and pictures chronologically
|
//Sort messages and pictures chronologically
|
||||||
uasort($asPics, function($a, $b){return $a['unix_timestamp'] > $b['unix_timestamp'];});
|
uasort($asPics, function($a, $b){return $a['unix_timestamp'] > $b['unix_timestamp'];});
|
||||||
@@ -255,13 +264,13 @@ class Spot extends Main
|
|||||||
$asMessages = $this->oDb->selectRows($asInfo);
|
$asMessages = $this->oDb->selectRows($asInfo);
|
||||||
foreach($asMessages as $asMessage)
|
foreach($asMessages as $asMessage)
|
||||||
{
|
{
|
||||||
$asMessage['unix_timestamp'] = (int) $asMessage['unix_timestamp'];
|
|
||||||
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
||||||
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
||||||
$asMessage['lat_dms'] = self::DecToDMS($asMessage['latitude'], 'lat');
|
$asMessage['lat_dms'] = self::DecToDMS($asMessage['latitude'], 'lat');
|
||||||
$asMessage['lon_dms'] = self::DecToDMS($asMessage['longitude'], 'lon');
|
$asMessage['lon_dms'] = self::DecToDMS($asMessage['longitude'], 'lon');
|
||||||
$asMessage['relative_time'] = Toolbox::getDateTimeDesc($asMessage['unix_timestamp'], 'fr');
|
|
||||||
$asMessage['formatted_time'] = date(self::FORMAT_TIME, $asMessage['unix_timestamp']);
|
$this->addTimeStamp($asMessage, $asMessage['unix_timestamp']);
|
||||||
|
|
||||||
$asAllFeedMessages[] = $asMessage;
|
$asAllFeedMessages[] = $asMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,34 +278,20 @@ class Spot extends Main
|
|||||||
return $asAllFeedMessages;
|
return $asAllFeedMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPictures()
|
private function getPictures($sTimeRefField)
|
||||||
{
|
{
|
||||||
$asPicPaths = glob(self::PIC_FOLDER.'*.{jpg,JPG,jpeg,JPEG,png,PNG}', GLOB_BRACE);
|
$asPics = $this->oPicture->getPicsInfo();
|
||||||
|
$asValidPics = array();
|
||||||
$asPics = array();
|
foreach($asPics as &$asPic) {
|
||||||
foreach($asPicPaths as $sPicPath)
|
$sTimeRef = $asPic[$sTimeRefField];
|
||||||
{
|
if($sTimeRef >= $this->oProject->getActivePeriod('from') && $sTimeRef <= $this->oProject->getActivePeriod('to')) {
|
||||||
//Finding picture timestamp
|
$asPic['taken_on_formatted'] = date(self::FORMAT_TIME, strtotime($asPic['taken_on']));
|
||||||
$asPicInfo = self::getPicInfo($sPicPath);
|
$this->addTimeStamp($asPic, strtotime($sTimeRef));
|
||||||
$iPicTimeStamp = $asPicInfo['timestamp'];
|
$asValidPics[] = $asPic;
|
||||||
|
|
||||||
//Get/Create thumbnail
|
|
||||||
$sThumbnailPath = self::getPicThumbnail($sPicPath);
|
|
||||||
|
|
||||||
//Filter on valid time interval
|
|
||||||
if($iPicTimeStamp >= strtotime($this->oProject->getActivePeriod('from')) && $iPicTimeStamp <= strtotime($this->oProject->getActivePeriod('to'))) {
|
|
||||||
|
|
||||||
$asPics[] = array(
|
|
||||||
'path' => $sPicPath,
|
|
||||||
'thumb_path' => $sThumbnailPath,
|
|
||||||
'rotate' => $asPicInfo['rotate'],
|
|
||||||
'unix_timestamp'=> $iPicTimeStamp,
|
|
||||||
'formatted_time'=> date(self::FORMAT_TIME, $iPicTimeStamp),
|
|
||||||
'relative_time' => Toolbox::getDateTimeDesc($iPicTimeStamp, 'fr')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $asPics;
|
|
||||||
|
return $asValidPics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPosts()
|
private function getPosts()
|
||||||
@@ -314,10 +309,9 @@ class Spot extends Main
|
|||||||
|
|
||||||
foreach($asPosts as &$asPost) {
|
foreach($asPosts as &$asPost) {
|
||||||
$iUnixTimeStamp = strtotime($asPost['timestamp']);
|
$iUnixTimeStamp = strtotime($asPost['timestamp']);
|
||||||
$asPost['unix_timestamp'] = $iUnixTimeStamp;
|
|
||||||
$asPost['relative_time'] = Toolbox::getDateTimeDesc($iUnixTimeStamp, 'fr');
|
|
||||||
$asPost['formatted_time'] = date(self::FORMAT_TIME, $iUnixTimeStamp);
|
|
||||||
$asPost['formatted_name'] = Toolbox::mb_ucwords($asPost['name']);
|
$asPost['formatted_name'] = Toolbox::mb_ucwords($asPost['name']);
|
||||||
|
|
||||||
|
$this->addTimeStamp($asPost, $iUnixTimeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $asPosts;
|
return $asPosts;
|
||||||
@@ -328,23 +322,28 @@ class Spot extends Main
|
|||||||
return ($iTimeStamp * -1).'.'.$sPriority.$iDbId;
|
return ($iTimeStamp * -1).'.'.$sPriority.$iDbId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function addTimeStamp(&$asData, $iTime) {
|
||||||
|
$asData['unix_timestamp'] = (int) $iTime;
|
||||||
|
$asData['relative_time'] = Toolbox::getDateTimeDesc($iTime, 'fr');
|
||||||
|
$asData['formatted_time'] = date(self::FORMAT_TIME, $iTime);
|
||||||
|
}
|
||||||
|
|
||||||
public function getNewsFeed($iChunk=0)
|
public function getNewsFeed($iChunk=0)
|
||||||
{
|
{
|
||||||
$asFeed = array();
|
$asFeed = array();
|
||||||
|
|
||||||
//Messages
|
//Messages
|
||||||
$asMessages = $this->getSpotMessages();
|
$asMessages = $this->getSpotMessages();
|
||||||
foreach($asMessages as $asMessage)
|
foreach($asMessages as $iIndex=>$asMessage)
|
||||||
{
|
{
|
||||||
$iMsgId = $asMessage[Db::getId(self::MSG_TABLE)];
|
$iId = self::getJsonId($asMessage['unix_timestamp'], '0', $asMessage[Db::getId(self::MSG_TABLE)]);
|
||||||
$iId = self::getJsonId($asMessage['unix_timestamp'], '0', $iMsgId);
|
|
||||||
$asFeed[$iId] = $asMessage;
|
$asFeed[$iId] = $asMessage;
|
||||||
$asFeed[$iId]['type'] = 'message';
|
$asFeed[$iId]['type'] = 'message';
|
||||||
$asFeed[$iId]['displayed_id'] = $iMsgId;
|
$asFeed[$iId]['displayed_id'] = 'N°'.$iIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Pictures
|
//Pictures
|
||||||
$asPics = $this->getPictures();
|
$asPics = $this->getPictures('added_on');
|
||||||
foreach($asPics as $iKey=>$asPic)
|
foreach($asPics as $iKey=>$asPic)
|
||||||
{
|
{
|
||||||
$iId = self::getJsonId($asPic['unix_timestamp'], '1', $iKey);
|
$iId = self::getJsonId($asPic['unix_timestamp'], '1', $iKey);
|
||||||
@@ -370,6 +369,10 @@ class Spot extends Main
|
|||||||
return self::getJsonResult(true, '', $asFeed);
|
return self::getJsonResult(true, '', $asFeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncPics() {
|
||||||
|
return $this->oPicture->syncFileFolder();
|
||||||
|
}
|
||||||
|
|
||||||
public function addPost($sName, $sPost)
|
public function addPost($sName, $sPost)
|
||||||
{
|
{
|
||||||
$asData = array(
|
$asData = array(
|
||||||
@@ -385,9 +388,9 @@ class Spot extends Main
|
|||||||
public function upload()
|
public function upload()
|
||||||
{
|
{
|
||||||
$this->oClassManagement->incClass('uploader', true);
|
$this->oClassManagement->incClass('uploader', true);
|
||||||
$oUploader = new Uploader(array('image_versions'=>array(), 'accept_file_types'=>'/\.(gif|jpe?g|png)$/i'));
|
$oUploader = new Uploader($this->oPicture);
|
||||||
$oUploader->init();
|
|
||||||
return $oUploader->getBody();
|
return self::getJsonResult(true, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTile($sMapId, $iX, $iY, $iZ)
|
public function getTile($sMapId, $iX, $iY, $iZ)
|
||||||
@@ -432,54 +435,6 @@ class Spot extends Main
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getPicInfo($sPicPath)
|
|
||||||
{
|
|
||||||
$iPicTimeStamp = $iPicTakenTimeStamp = $iPicFileTimeStamp = 0;
|
|
||||||
$asExif = @exif_read_data($sPicPath, 0, true);
|
|
||||||
if(!$asExif) $asExif['FILE']['FileDateTime'] = filemtime($sPicPath);
|
|
||||||
|
|
||||||
//Timestamps
|
|
||||||
if(array_key_exists('EXIF', $asExif) && array_key_exists('DateTimeOriginal', $asExif['EXIF'])) $iPicTakenTimeStamp = strtotime($asExif['EXIF']['DateTimeOriginal']);
|
|
||||||
if(array_key_exists('FILE', $asExif) && array_key_exists('FileDateTime', $asExif['FILE'])) $iPicFileTimeStamp = $asExif['FILE']['FileDateTime'];
|
|
||||||
|
|
||||||
//Merge timestamps
|
|
||||||
$iPicTimeStamp = ($iPicTakenTimeStamp > 0)?$iPicTakenTimeStamp:$iPicFileTimeStamp;
|
|
||||||
|
|
||||||
//Time Zone
|
|
||||||
//if($iPicTimeStamp >= self::HONEYMOON_DATE_BEG && $iPicTimeStamp <= self::HONEYMOON_DATE_END) $iPicTimeStamp -= 60*60*(12+1); //timezone + daylight saving
|
|
||||||
|
|
||||||
//Orientation
|
|
||||||
if(array_key_exists('IFD0', $asExif) && array_key_exists('Orientation', $asExif['IFD0'])) {
|
|
||||||
switch($asExif['IFD0']['Orientation'])
|
|
||||||
{
|
|
||||||
case 1: $sRotate = '0'; break; //None
|
|
||||||
case 3: $sRotate = '180'; break; //Flip over
|
|
||||||
case 6: $sRotate = '90'; break; //Clockwise
|
|
||||||
case 8: $sRotate = '-90'; break; //Trigo
|
|
||||||
default: $sRotate = $asExif['IFD0']['Orientation'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else $sRotate = '0';
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'timestamp' => $iPicTimeStamp,
|
|
||||||
'taken_ts' => $iPicTakenTimeStamp,
|
|
||||||
'file_ts' => $iPicFileTimeStamp,
|
|
||||||
'rotate' => $sRotate
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getPicThumbnail($sPicPath)
|
|
||||||
{
|
|
||||||
$sPicName = pathinfo($sPicPath, PATHINFO_BASENAME);
|
|
||||||
$sThumbPath = self::THUMB_FOLDER.$sPicName;
|
|
||||||
|
|
||||||
if(!file_exists($sThumbPath)) $asThumbInfo = ToolBox::createThumbnail($sPicPath, 400, 0, $sThumbPath/*, false, array('jpg', 'jpeg', 'gif', 'png'), true*/);
|
|
||||||
else $asThumbInfo = array('error'=>'', 'out'=>$sThumbPath);
|
|
||||||
|
|
||||||
return ($asThumbInfo['error']=='')?$asThumbInfo['out']:$sPicPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function DecToDMS($dValue, $sType='lat') {
|
public static function DecToDMS($dValue, $sType='lat') {
|
||||||
if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S';
|
if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S';
|
||||||
else $sDirection = ($dValue >= 0)?'E':'W';
|
else $sDirection = ($dValue >= 0)?'E':'W';
|
||||||
|
|||||||
126
inc/uploader.php
126
inc/uploader.php
@@ -2,27 +2,41 @@
|
|||||||
|
|
||||||
class Uploader extends UploadHandler
|
class Uploader extends UploadHandler
|
||||||
{
|
{
|
||||||
private $sBody;
|
/**
|
||||||
|
* Pictures Management
|
||||||
|
* @var Picture
|
||||||
|
*/
|
||||||
|
private $oPicture;
|
||||||
|
|
||||||
function __construct($asOptions = null, $bInitialize = false, $asErrorMessages = null)
|
function __construct(&$oPicture)
|
||||||
{
|
{
|
||||||
parent::__construct($asOptions, $bInitialize, $asErrorMessages);
|
$this->error_messages['wrong_project_mode'] = 'Le projet n\'est pas en mode "blog".';
|
||||||
$this->sBody = '';
|
$this->oPicture = &$oPicture;
|
||||||
|
parent::__construct(array('image_versions'=>array(), 'accept_file_types'=>'/\.(gif|jpe?g|png)$/i'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function init()
|
protected function validate($uploaded_file, $file, $error, $index) {
|
||||||
{
|
$bResult = parent::validate($uploaded_file, $file, $error, $index);
|
||||||
$this->initialize();
|
|
||||||
|
//Check project mode
|
||||||
|
if(!$this->oPicture->isProjectModeValid()) {
|
||||||
|
$file->error = $this->get_error_message('wrong_project_mode');
|
||||||
|
$bResult = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function body($sText)
|
return $bResult;
|
||||||
{
|
|
||||||
$this->sBody .= $sText;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBody()
|
protected function handle_file_upload($uploaded_file, $name, $size, $type, $error, $index = null, $content_range = null) {
|
||||||
{
|
$file = parent::handle_file_upload($uploaded_file, $name, $size, $type, $error, $index, $content_range);
|
||||||
return $this->sBody;
|
if(empty($file->error)) {
|
||||||
|
$sError = $this->oPicture->addPic($file->name);
|
||||||
|
if($sError!='') {
|
||||||
|
$file->error = $this->get_error_message($sError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +79,10 @@ class UploadHandler
|
|||||||
'image_resize' => 'Failed to resize image'
|
'image_resize' => 'Failed to resize image'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const IMAGETYPE_GIF = 1;
|
||||||
|
const IMAGETYPE_JPEG = 2;
|
||||||
|
const IMAGETYPE_PNG = 3;
|
||||||
|
|
||||||
protected $image_objects = array();
|
protected $image_objects = array();
|
||||||
|
|
||||||
public function __construct($options = null, $initialize = true, $error_messages = null) {
|
public function __construct($options = null, $initialize = true, $error_messages = null) {
|
||||||
@@ -116,17 +134,32 @@ class UploadHandler
|
|||||||
'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB
|
'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB
|
||||||
// Defines which files can be displayed inline when downloaded:
|
// Defines which files can be displayed inline when downloaded:
|
||||||
'inline_file_types' => '/\.(gif|jpe?g|png)$/i',
|
'inline_file_types' => '/\.(gif|jpe?g|png)$/i',
|
||||||
// Defines which files (based on their names) are accepted for upload:
|
// Defines which files (based on their names) are accepted for upload.
|
||||||
'accept_file_types' => '/.+$/i',
|
// By default, only allows file uploads with image file extensions.
|
||||||
|
// Only change this setting after making sure that any allowed file
|
||||||
|
// types cannot be executed by the webserver in the files directory,
|
||||||
|
// e.g. PHP scripts, nor executed by the browser when downloaded,
|
||||||
|
// e.g. HTML files with embedded JavaScript code.
|
||||||
|
// Please also read the SECURITY.md document in this repository.
|
||||||
|
'accept_file_types' => '/\.(gif|jpe?g|png)$/i',
|
||||||
|
// Replaces dots in filenames with the given string.
|
||||||
|
// Can be disabled by setting it to false or an empty string.
|
||||||
|
// Note that this is a security feature for servers that support
|
||||||
|
// multiple file extensions, e.g. the Apache AddHandler Directive:
|
||||||
|
// https://httpd.apache.org/docs/current/mod/mod_mime.html#addhandler
|
||||||
|
// Before disabling it, make sure that files uploaded with multiple
|
||||||
|
// extensions cannot be executed by the webserver, e.g.
|
||||||
|
// "example.php.png" with embedded PHP code, nor executed by the
|
||||||
|
// browser when downloaded, e.g. "example.html.gif" with embedded
|
||||||
|
// JavaScript code.
|
||||||
|
'replace_dots_in_filenames' => '-',
|
||||||
// The php.ini settings upload_max_filesize and post_max_size
|
// The php.ini settings upload_max_filesize and post_max_size
|
||||||
// take precedence over the following max_file_size setting:
|
// take precedence over the following max_file_size setting:
|
||||||
'max_file_size' => null,
|
'max_file_size' => null,
|
||||||
'min_file_size' => 1,
|
'min_file_size' => 1,
|
||||||
// The maximum number of files for the upload directory:
|
// The maximum number of files for the upload directory:
|
||||||
'max_number_of_files' => null,
|
'max_number_of_files' => null,
|
||||||
// Defines which files are handled as image files:
|
// Reads first file bytes to identify and correct file extensions:
|
||||||
'image_file_types' => '/\.(gif|jpe?g|png)$/i',
|
|
||||||
// Use exif_imagetype on all files to correct file extensions:
|
|
||||||
'correct_image_extensions' => false,
|
'correct_image_extensions' => false,
|
||||||
// Image resolution restrictions:
|
// Image resolution restrictions:
|
||||||
'max_width' => null,
|
'max_width' => null,
|
||||||
@@ -443,9 +476,8 @@ class UploadHandler
|
|||||||
$min_width = @$this->options['min_width'];
|
$min_width = @$this->options['min_width'];
|
||||||
$min_height = @$this->options['min_height'];
|
$min_height = @$this->options['min_height'];
|
||||||
if (($max_width || $max_height || $min_width || $min_height)
|
if (($max_width || $max_height || $min_width || $min_height)
|
||||||
&& preg_match($this->options['image_file_types'], $file->name)) {
|
&& $this->is_valid_image_file($uploaded_file)) {
|
||||||
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
|
list($img_width, $img_height) = $this->get_image_size($uploaded_file);
|
||||||
|
|
||||||
// If we are auto rotating the image by default, do the checks on
|
// If we are auto rotating the image by default, do the checks on
|
||||||
// the correct orientation
|
// the correct orientation
|
||||||
if (
|
if (
|
||||||
@@ -459,7 +491,6 @@ class UploadHandler
|
|||||||
$img_height = $tmp;
|
$img_height = $tmp;
|
||||||
unset($tmp);
|
unset($tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!empty($img_width)) {
|
if (!empty($img_width)) {
|
||||||
if ($max_width && $img_width > $max_width) {
|
if ($max_width && $img_width > $max_width) {
|
||||||
@@ -521,16 +552,15 @@ class UploadHandler
|
|||||||
preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
|
preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) {
|
||||||
$name .= '.'.$matches[1];
|
$name .= '.'.$matches[1];
|
||||||
}
|
}
|
||||||
if ($this->options['correct_image_extensions'] &&
|
if ($this->options['correct_image_extensions']) {
|
||||||
function_exists('exif_imagetype')) {
|
switch ($this->imagetype($file_path)) {
|
||||||
switch (@exif_imagetype($file_path)){
|
case self::IMAGETYPE_JPEG:
|
||||||
case IMAGETYPE_JPEG:
|
|
||||||
$extensions = array('jpg', 'jpeg');
|
$extensions = array('jpg', 'jpeg');
|
||||||
break;
|
break;
|
||||||
case IMAGETYPE_PNG:
|
case self::IMAGETYPE_PNG:
|
||||||
$extensions = array('png');
|
$extensions = array('png');
|
||||||
break;
|
break;
|
||||||
case IMAGETYPE_GIF:
|
case self::IMAGETYPE_GIF:
|
||||||
$extensions = array('gif');
|
$extensions = array('gif');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -554,6 +584,16 @@ class UploadHandler
|
|||||||
// into different directories or replacing hidden system files.
|
// into different directories or replacing hidden system files.
|
||||||
// Also remove control characters and spaces (\x00..\x20) around the filename:
|
// Also remove control characters and spaces (\x00..\x20) around the filename:
|
||||||
$name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
|
$name = trim($this->basename(stripslashes($name)), ".\x00..\x20");
|
||||||
|
// Replace dots in filenames to avoid security issues with servers
|
||||||
|
// that interpret multiple file extensions, e.g. "example.php.png":
|
||||||
|
$replacement = $this->options['replace_dots_in_filenames'];
|
||||||
|
if (!empty($replacement)) {
|
||||||
|
$parts = explode('.', $name);
|
||||||
|
if (count($parts) > 2) {
|
||||||
|
$ext = array_pop($parts);
|
||||||
|
$name = implode($replacement, $parts).'.'.$ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Use a timestamp for empty filenames:
|
// Use a timestamp for empty filenames:
|
||||||
if (!$name) {
|
if (!$name) {
|
||||||
$name = str_replace('.', '-', microtime(true));
|
$name = str_replace('.', '-', microtime(true));
|
||||||
@@ -1048,6 +1088,7 @@ class UploadHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function create_scaled_image($file_name, $version, $options) {
|
protected function create_scaled_image($file_name, $version, $options) {
|
||||||
|
try {
|
||||||
if ($this->options['image_library'] === 2) {
|
if ($this->options['image_library'] === 2) {
|
||||||
return $this->imagemagick_create_scaled_image($file_name, $version, $options);
|
return $this->imagemagick_create_scaled_image($file_name, $version, $options);
|
||||||
}
|
}
|
||||||
@@ -1055,6 +1096,10 @@ class UploadHandler
|
|||||||
return $this->imagick_create_scaled_image($file_name, $version, $options);
|
return $this->imagick_create_scaled_image($file_name, $version, $options);
|
||||||
}
|
}
|
||||||
return $this->gd_create_scaled_image($file_name, $version, $options);
|
return $this->gd_create_scaled_image($file_name, $version, $options);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
error_log($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function destroy_image_object($file_path) {
|
protected function destroy_image_object($file_path) {
|
||||||
@@ -1063,15 +1108,30 @@ class UploadHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function is_valid_image_file($file_path) {
|
protected function imagetype($file_path) {
|
||||||
if (!preg_match($this->options['image_file_types'], $file_path)) {
|
$fp = fopen($file_path, 'r');
|
||||||
|
$data = fread($fp, 4);
|
||||||
|
fclose($fp);
|
||||||
|
// GIF: 47 49 46 38
|
||||||
|
if ($data === 'GIF8') {
|
||||||
|
return self::IMAGETYPE_GIF;
|
||||||
|
}
|
||||||
|
// JPG: FF D8 FF
|
||||||
|
if (bin2hex(substr($data, 0, 3)) === 'ffd8ff') {
|
||||||
|
return self::IMAGETYPE_JPEG;
|
||||||
|
}
|
||||||
|
// PNG: 89 50 4E 47
|
||||||
|
if (bin2hex(@$data[0]).substr($data, 1, 4) === '89PNG') {
|
||||||
|
return self::IMAGETYPE_PNG;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (function_exists('exif_imagetype')) {
|
|
||||||
return @exif_imagetype($file_path);
|
protected function is_valid_image_file($file_path) {
|
||||||
|
if (!preg_match('/\.(gif|jpe?g|png)$/i', $file_path)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
$image_info = $this->get_image_size($file_path);
|
return !!$this->imagetype($file_path);
|
||||||
return $image_info && $image_info[0] && $image_info[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handle_image_file($file_path, $file) {
|
protected function handle_image_file($file_path, $file) {
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ if($sAction!='')
|
|||||||
{
|
{
|
||||||
switch($sAction)
|
switch($sAction)
|
||||||
{
|
{
|
||||||
case 'messages':
|
case 'markers':
|
||||||
$sResult = $oSpot->getMessages();
|
$sResult = $oSpot->getMarkers();
|
||||||
break;
|
break;
|
||||||
case 'feed':
|
case 'feed':
|
||||||
$sResult = $oSpot->getNewsFeed($iChunk);
|
$sResult = $oSpot->getNewsFeed($iChunk);
|
||||||
@@ -54,6 +54,9 @@ if($sAction!='')
|
|||||||
/*case 'sql':
|
/*case 'sql':
|
||||||
$sResult = $oSpot->getDbBuildScript();
|
$sResult = $oSpot->getDbBuildScript();
|
||||||
break;*/
|
break;*/
|
||||||
|
case 'sync_pics':
|
||||||
|
$sResult = $oSpot->syncPics();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$sResult = Spot::getJsonResult(false, Spot::NOT_FOUND);
|
$sResult = Spot::getJsonResult(false, Spot::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,14 +69,15 @@ function initProject(sProjectCodeName){
|
|||||||
self.tmp('first_exec', false);
|
self.tmp('first_exec', false);
|
||||||
self.vars('project', self.vars(['projects', sProjectCodeName]));
|
self.vars('project', self.vars(['projects', sProjectCodeName]));
|
||||||
|
|
||||||
//Spot Messages
|
|
||||||
$.when(
|
$.when(
|
||||||
|
//Markers: Spot Messages & Pictures
|
||||||
self.get(
|
self.get(
|
||||||
'messages',
|
'markers',
|
||||||
function(){},
|
function(){},
|
||||||
{project_id: self.vars(['project', 'id'])},
|
{project_id: self.vars(['project', 'id'])},
|
||||||
function(e){console.log(e);}
|
function(e){console.log(e);}
|
||||||
),
|
),
|
||||||
|
//Project Geojson: Hike track
|
||||||
$.ajax({
|
$.ajax({
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
url: self.vars(['project', 'geofile']),
|
url: self.vars(['project', 'geofile']),
|
||||||
@@ -101,6 +102,8 @@ function initPosts() {
|
|||||||
};
|
};
|
||||||
getPost(asPoster).appendTo($Poster.show());
|
getPost(asPoster).appendTo($Poster.show());
|
||||||
|
|
||||||
|
autosize($('#post'));
|
||||||
|
|
||||||
$('#submit').click(function(){
|
$('#submit').click(function(){
|
||||||
if($Poster.checkForm())
|
if($Poster.checkForm())
|
||||||
{
|
{
|
||||||
@@ -167,7 +170,7 @@ function initSpotMessages(aoMessages, aoTracks) {
|
|||||||
}).addTo(oMap);
|
}).addTo(oMap);
|
||||||
|
|
||||||
//Centering map
|
//Centering map
|
||||||
if(self.vars(['project', 'mode'])==self.consts.modes.blog)
|
if(self.vars(['project', 'mode'])==self.consts.modes.blog && aoMessages.length > 0)
|
||||||
{
|
{
|
||||||
//Zoom on last message
|
//Zoom on last message
|
||||||
var oLastMsg = aoMessages[aoMessages.length-1];
|
var oLastMsg = aoMessages[aoMessages.length-1];
|
||||||
@@ -233,7 +236,7 @@ function initSpotMessages(aoMessages, aoTracks) {
|
|||||||
if(oMsg.pics) {
|
if(oMsg.pics) {
|
||||||
var $Pics = $('<div>', {'class':'pics'});
|
var $Pics = $('<div>', {'class':'pics'});
|
||||||
$.each(oMsg.pics, function(iKey, asPic){
|
$.each(oMsg.pics, function(iKey, asPic){
|
||||||
$Pics.append($('<a>', {href: asPic.path, 'data-lightbox': self.consts.title, 'data-title': asPic.formatted_time})
|
$Pics.append($('<a>', {href: asPic.pic_path, 'data-lightbox': self.consts.title, 'data-title': asPic.formatted_time})
|
||||||
.append($('<img>', {'src': asPic.thumb_path})));
|
.append($('<img>', {'src': asPic.thumb_path})));
|
||||||
});
|
});
|
||||||
$Tooltip
|
$Tooltip
|
||||||
@@ -385,7 +388,7 @@ function getPost(asPost) {
|
|||||||
break;
|
break;
|
||||||
case 'picture':
|
case 'picture':
|
||||||
var $Image = $('<img>', {'src': asPost.thumb_path/*, 'style':'transform:rotate('+asPost.rotate+'deg);'*/});
|
var $Image = $('<img>', {'src': asPost.thumb_path/*, 'style':'transform:rotate('+asPost.rotate+'deg);'*/});
|
||||||
$Body = $('<a>', {href: asPost.path, 'data-lightbox': self.consts.title, 'data-title': sAbsTime}).append($Image);
|
$Body = $('<a>', {href: asPost.pic_path, 'data-lightbox': self.consts.title, 'data-title': 'Photo ajouté le '+sAbsTime+' (prise le '+asPost.taken_on_formatted+')'}).append($Image);
|
||||||
break;
|
break;
|
||||||
case 'post':
|
case 'post':
|
||||||
$Body = $('<div>')
|
$Body = $('<div>')
|
||||||
@@ -394,7 +397,7 @@ function getPost(asPost) {
|
|||||||
break;
|
break;
|
||||||
case 'poster':
|
case 'poster':
|
||||||
$Body = $('<p>', {'class':'message'})
|
$Body = $('<p>', {'class':'message'})
|
||||||
.append($('<input>', {type:'text', id:'post', name:'post', placeholder:'Message'}))
|
.append($('<textarea>', {id:'post', name:'post', placeholder:'Message', 'class':'autoExpand', rows:'1'}))
|
||||||
.append($('<input>', {type:'text', id:'name', name:'name', placeholder:'Nom'}))
|
.append($('<input>', {type:'text', id:'name', name:'name', placeholder:'Nom'}))
|
||||||
.append($('<button>', {type:'button', id:'submit', name:'submit'}).addIcon('fa-send'));
|
.append($('<button>', {type:'button', id:'submit', name:'submit'}).addIcon('fa-send'));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -8,15 +8,17 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
oSpot.pageInit = function(asHash)
|
oSpot.pageInit = function(asHash)
|
||||||
{
|
{
|
||||||
|
var asProject = self.vars(['projects', self.vars('default_project_codename')]);
|
||||||
|
if(asProject.mode == self.consts.modes.blog) {
|
||||||
$('#fileupload')
|
$('#fileupload')
|
||||||
.attr('data-url', self.getActionLink('upload'))
|
.attr('data-url', self.getActionLink('upload'))
|
||||||
.fileupload({
|
.fileupload({
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
|
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
|
||||||
done: function (e, data) {
|
done: function (e, asResult) {
|
||||||
var $Status = $('#status');
|
var $Status = $('#status');
|
||||||
$.each(data.result.files, function(iKey, oFile) {
|
$.each(asResult.files, function(iKey, oFile) {
|
||||||
var sMsg = ('error' in oFile)?oFile.error:(oFile.name+" uploaded succesfully");
|
var sMsg = ('error' in oFile)?oFile.error:(oFile.name+" uploaded successfully");
|
||||||
$Status.append($('<p>').text(sMsg));
|
$Status.append($('<p>').text(sMsg));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -28,5 +30,7 @@ oSpot.pageInit = function(asHash)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else $('#messages').empty().append('Le projet "'+asProject.name+'" n\'est pas en mode blog. Aucun upload possible.');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
File diff suppressed because one or more lines are too long
@@ -27,3 +27,18 @@
|
|||||||
.flicker {
|
.flicker {
|
||||||
@include animate(fadeIn 0.8s infinite alternate);
|
@include animate(fadeIn 0.8s infinite alternate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fonts */
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Ubuntu:400,700&subset=latin-ext');
|
||||||
|
|
||||||
|
body, textarea, input, button {
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: 'Ubuntu', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Common objects */
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -64,7 +64,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 44px;
|
line-height: 44px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #888;
|
color: #999;
|
||||||
text-shadow: 0px 1px 1px rgba(0,0,0,0.8);
|
text-shadow: 0px 1px 1px rgba(0,0,0,0.8);
|
||||||
background: none;
|
background: none;
|
||||||
@extend .fa;
|
@extend .fa;
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
width: calc(30% - 1em);
|
width: calc(30% - 1em);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
|
||||||
input, button {
|
input, textarea, button {
|
||||||
border: none;
|
border: none;
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
background: #F7F7F7;
|
background: #F7F7F7;
|
||||||
@@ -129,7 +129,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#posts {
|
#posts {
|
||||||
font-family: Arial;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -137,7 +136,7 @@
|
|||||||
|
|
||||||
#poster {
|
#poster {
|
||||||
|
|
||||||
input, button {
|
input, textarea, button {
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: #d9deff;
|
background-color: #d9deff;
|
||||||
color: #323268;
|
color: #323268;
|
||||||
|
|||||||
2
todo
2
todo
@@ -1,8 +1,6 @@
|
|||||||
To Do List
|
To Do List
|
||||||
----------
|
----------
|
||||||
- Elevation chart
|
- Elevation chart
|
||||||
- Table for images
|
|
||||||
- Device/Spot Class
|
- Device/Spot Class
|
||||||
- Manage projects.timezone
|
- Manage projects.timezone
|
||||||
- Remove files2/ on server
|
- Remove files2/ on server
|
||||||
- replace message ID with project ID / Message ID on display
|
|
||||||
Reference in New Issue
Block a user