scratch

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 138  →  ?path2? @ 139
/css/gallery/style.css
@@ -22,4 +22,5 @@
.swiper-container {
width: auto;
height: auto;
margin-top: 1em;
}
/file.html
@@ -17,7 +17,7 @@
<link href="bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- DropZone -->
<link href="bower_components/dropzone/dist/min/dropzone.min.css" rel="stylesheet">
<!-- TagsInput -->
<!-- Bootstrap TokenField -->
<link href="bower_components/bootstrap-tokenfield/dist/css/bootstrap-tokenfield.min.css" rel="stylesheet">
<!-- Site-wide style CCS -->
@@ -165,8 +165,6 @@
<script src="bower_components/dropzone/dist/min/dropzone.min.js"></script>
<!-- Clipboard -->
<script src="bower_components/clipboard/dist/clipboard.min.js"></script>
<!-- TagsInput -->
<!-- <script src="bower_components/bootstrap-tagsinput/dist/bootstrap-tagsinput.min.js"></script> -->
<!-- BootStrap TokenField -->
<script src="bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.min.js"></script>
<!-- Angular Initialization. -->
/view.html
@@ -22,6 +22,8 @@
<link rel="stylesheet" href="bower_components/blueimp-gallery/css/blueimp-gallery.min.css">
<!-- Swiper -->
<link rel="stylesheet" href="bower_components/swiper/dist/css/swiper.min.css">
<!-- Bootstrap TokenField -->
<link href="bower_components/bootstrap-tokenfield/dist/css/bootstrap-tokenfield.min.css" rel="stylesheet">
 
<!-- Site-wide style CCS -->
<link href="css/style.css" rel="stylesheet">
@@ -67,6 +69,21 @@
<button id="btn-facebook" class="btn btn-default" type="button" disabled><i class="fa fa-facebook"></i></button>
</span>
</div>
<div class="input-group">
<input type="text" class="form-control tokenfield file-tags" id="file-tags" data-minLength="3" data-delimiter=" "/>
<span class="input-group-btn">
<button id="btn-filter" class="btn btn-default" type="button"><i class="fa fa-remove"></i></button>
</span>
</div>
<!-- Create swiper container -->
<div class="swiper-container">
<div id="links" class="swiper-wrapper">
</div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
<!-- The Gallery as inline carousel, can be positioned anywhere on the page -->
<div id="blueimp-gallery-carousel" class="blueimp-gallery blueimp-gallery-carousel">
@@ -78,13 +95,6 @@
<!-- <ol class="indicator"></ol> -->
</div>
<div class="swiper-container">
<div id="links" class="swiper-wrapper">
</div>
<!-- If we need navigation buttons -->
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</div>
</div>
@@ -108,6 +118,8 @@
<script src="bower_components/blueimp-gallery/js/blueimp-gallery.min.js"></script>
<!-- Clipboard -->
<script src="bower_components/clipboard/dist/clipboard.min.js"></script>
<!-- BootStrap TokenField -->
<script src="bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.min.js"></script>
<!-- YAML -->
<script src="bower_components/yaml.js/dist/yaml.min.js"></script>
<!-- Swiper -->
@@ -144,114 +156,149 @@
return $element[0];
};
$.getJSON('view.php', {
timestamp: window.performance.now()
}).then((data) => {
// Create slides.
var indexPage = 0;
data.chunk(50).forEach((page) => {
document.getElementById('links')
.insertAdjacentHTML(
'beforeend',
'<div id="swiper-slide-' + indexPage + '" class="swiper-slide"></div>'
);
page.forEach((link) => {
// Generic icon for text / html items.
switch(link.type) {
case 'text/plain':
link.preview ='img/text.png';
break;
}
document.getElementById('swiper-slide-' + indexPage)
.insertAdjacentHTML(
'beforeend',
'<a href="' +
link.url +
'" type="' +
link.type +
'"><img src="' +
link.preview +
'" width="60" height="40"></a>'
);
});
function createGallery(tags, swiper) {
$.getJSON('view.php', {
tags: JSON.stringify(tags),
timestamp: window.performance.now()
}).then((data) => {
// Remove current links.
document.getElementById('links').innerHTML = '';
// Create slides.
var indexPage = 0;
data.chunk(50).forEach((page) => {
document.getElementById('links')
.insertAdjacentHTML(
'beforeend',
'<div id="swiper-slide-' + indexPage + '" class="swiper-slide"></div>'
);
page.forEach((link) => {
// Generic icon for text / html items.
switch(link.type) {
case 'text/plain':
link.preview ='img/text.png';
break;
}
document.getElementById('swiper-slide-' + indexPage)
.insertAdjacentHTML(
'beforeend',
'<a class="swiper-thumb" href="' +
link.url +
'" type="' +
link.type +
'"><img src="' +
link.preview +
'" width="60" height="40"></a>'
);
});
++indexPage;
});
++indexPage;
});
// Initialize gallery.
document.getElementById('links').onclick = function (event) {
event = event || window.event;
var target = event.target || event.srcElement,
link = target.src ? target.parentNode : target,
options = {
index: link,
event: event,
carousel: true,
container: '#blueimp-gallery-carousel',
stretchImages: true,
startSlideshow: false,
onslideend: function(index, slide) {
// Set the URL.
$('#URL').val(
location.protocol
.concat("//")
.concat(window.location.hostname)
.concat("/").concat(data[index].url)
);
// Initialize gallery.
document.getElementById('links').onclick = function (event) {
event = event || window.event;
var target = event.target || event.srcElement,
link = target.src ? target.parentNode : target,
options = {
index: link,
event: event,
carousel: true,
container: '#blueimp-gallery-carousel',
stretchImages: true,
startSlideshow: false,
onslideend: function(index, slide) {
// Set the URL.
$('#URL').val(
location.protocol
.concat("//")
.concat(window.location.hostname)
.concat("/").concat(data[index].url)
);
// Check if OpenGraph should be enabled.
switch(data[index].opengraph) {
case true:
// Enable the facebook button.
$('#btn-facebook')
.prop("disabled", false);
break;
default:
// Disable the facebook button.
$('#btn-facebook')
.prop("disabled", true);
break;
// Check if OpenGraph should be enabled.
switch(data[index].opengraph) {
case true:
// Enable the facebook button.
$('#btn-facebook')
.prop("disabled", false);
break;
default:
// Disable the facebook button.
$('#btn-facebook')
.prop("disabled", true);
break;
}
// Change the URL to OpenGraph when the user clicks the button.
$('#btn-facebook').on('click', () => {
$('#URL')
.val(
location.protocol.concat("//")
.concat(window.location.hostname)
.concat("/")
.concat("og")
.concat("/")
.concat(data[index].url)
);
});
}
// Change the URL to OpenGraph when the user clicks the button.
$('#btn-facebook').on('click', () => {
$('#URL')
.val(
location.protocol.concat("//")
.concat(window.location.hostname)
.concat("/")
.concat("og")
.concat("/")
.concat(data[index].url)
);
});
}
},
links = this.getElementsByTagName('a');
blueimp.Gallery(links, options);
};
new Swiper ('.swiper-container', {
// Optional parameters
direction: 'horizontal',
// Creates duplicate element IDs if set to true.
loop: false,
// If we need pagination
//pagination: '.swiper-pagination',
// Navigation arrows
nextButton: '.swiper-button-next',
prevButton: '.swiper-button-prev',
// And if we need scrollbar
//scrollbar: '.swiper-scrollbar',
});
// Enable the Clipboard button.
new Clipboard('#copy-url');
},
links = this.getElementsByTagName('a');
blueimp.Gallery(links, options);
};
swiper.update();
swiper.slideTo(1, 0, false);
});
}
// Create swiper.
var swiper = new Swiper ('.swiper-container', {
// Optional parameters
direction: 'horizontal',
// Creates duplicate element IDs if set to true.
loop: false,
 
// If we need pagination
//pagination: '.swiper-pagination',
 
// Navigation arrows
nextButton: '.swiper-button-next',
prevButton: '.swiper-button-prev',
 
// And if we need scrollbar
//scrollbar: '.swiper-scrollbar'
});
// Enable the Clipboard button.
new Clipboard('#copy-url');
// Create token field.
$('#file-tags').tokenfield();
// Bind to token field tag add and remove events.
$('#file-tags')
.on('tokenfield:createdtoken', function (e) {
createGallery($('#file-tags').tokenfield('getTokens'), swiper);
})
.on('tokenfield:removedtoken', function (e) {
// Happens when all the tags are removed.
if(e.attrs.value == null || typeof e.attrs.value === undefined) {
createGallery([], swiper);
return;
}
createGallery($('#file-tags').tokenfield('getTokens'));
});
// Create clear button for tags.
$('#btn-filter').click(() => {
$('#file-tags').tokenfield('setTokens', []);
createGallery([], swiper);
});
// Generate the gallery.
createGallery([], swiper);
});
</script>
<!-- Jumbotron parallax effect -->
/view.php
@@ -14,6 +14,52 @@
### Load configuration.
$config = spyc_load_file('config.yaml');
 
### If tags were specified then check whether the hash matches any tags.
$tags = array();
if(isset($_GET['tags']) && !empty($_GET['tags'])) {
## Extract the token field values.
$tags = array_filter(
array_map(
function($item) {
return $item->value;
},
array_values(
json_decode(
stripslashes(
$_GET['tags']
)
)
)
)
);
## Connect or create the scratch database.
$db = new PDO('sqlite:db/scratch.sqlite3');
 
## Set the error mode to exceptions.
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 
try {
$db->beginTransaction();
## Create tags table if it does not exist.
$db->query('CREATE TABLE IF NOT EXISTS "tags" ("hash" text NOT NULL COLLATE NOCASE, "tag" text COLLATE NOCASE, UNIQUE("hash", "tag") ON CONFLICT REPLACE)');
## Select all the hashes that match supplied tags.
$q = $db->prepare('SELECT "hash" FROM "tags" WHERE tag IN ('.implode(',', array_fill(0, count($tags), '?')).')');
foreach($tags as $i => $tag)
$q->bindValue($i+1, $tag);
$result = $q->execute();
$tags = $q->fetchAll(PDO::FETCH_COLUMN, 0);
$db->commit();
} catch(Exception $e) {
error_log($e);
## Rollback.
$db->rollback();
}
}
 
### Open MIME.
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (!$finfo) {
@@ -25,10 +71,10 @@
array_values(
array_filter(
array_map(
function ($file) use ($config, $finfo) {
function ($file) use ($config, $finfo, $tags) {
#### Get the file hash.
$fileHash = array_shift(explode('.', $file));
#### Build the user path.
$userPath = join(
DIRECTORY_SEPARATOR,
@@ -37,7 +83,7 @@
$file
)
);
#### If the extension is not allowed then skip this file.
$fileExtension = pathinfo($userPath, PATHINFO_EXTENSION);
if (!isset($fileExtension) ||
@@ -44,7 +90,7 @@
!in_array(strtoupper($fileExtension),
array_map('strtoupper', $config['ALLOWED_FILE_EXTENSIONS'])))
return null;
#### Hook for various file extensions.
$opengraph = FALSE;
switch (strtoupper($fileExtension)) {
@@ -63,7 +109,7 @@
$config['ASSET_HASH_SIZE']
)
);
### Build the user path.
$previewFile = join(
DIRECTORY_SEPARATOR,
@@ -72,13 +118,13 @@
$previewHash
)
);
### Do not re-create the thumbnail if it already exists.
if (file_exists($previewFile.'.'.'jpg')) {
$opengraph = TRUE;
break;
}
### Extract thumbnail.
$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open($userPath);
@@ -104,6 +150,11 @@
default:
return null;
}
if(!empty($tags) && !in_array($fileHash, $tags)) {
return array();
}
return array(
'url' => $fileHash,
'type' => finfo_file($finfo, $userPath),
@@ -131,4 +182,4 @@
)
);
 
finfo_close($finfo);
finfo_close($finfo);