2013-04-26 05:30:56 +04:00
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<title>ImageGrid.Viewer</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
|
|
|
|
|
.viewer {
|
|
|
|
|
position: relative;
|
|
|
|
|
width: 800px;
|
|
|
|
|
height: 600px;
|
2013-04-29 01:59:59 +04:00
|
|
|
overflow: hidden;
|
2013-04-26 05:30:56 +04:00
|
|
|
|
|
|
|
|
border: solid blue 1px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.ribbon-set {
|
2013-04-29 01:59:59 +04:00
|
|
|
position: absolute;
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
.ribbon-set:empty:after {
|
|
|
|
|
display: block;
|
|
|
|
|
top: 0px;
|
|
|
|
|
left: 0px;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
content: "Empty";
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.ribbon {
|
|
|
|
|
position: relative;
|
|
|
|
|
display: block;
|
|
|
|
|
height: auto;
|
|
|
|
|
min-width: 0px;
|
|
|
|
|
overflow: visible;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
font-size: 0;
|
|
|
|
|
|
|
|
|
|
margin-top: 20px;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
2013-04-30 00:28:47 +04:00
|
|
|
.ribbon:empty {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
2013-04-26 05:30:56 +04:00
|
|
|
.ribbon:first-child {
|
|
|
|
|
margin-top: 0px;
|
|
|
|
|
}
|
|
|
|
|
.ribbon:last-child {
|
|
|
|
|
margin-bottom: 0px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.image {
|
|
|
|
|
position: relative;
|
|
|
|
|
display: inline-block;
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
text-align;left;
|
2013-04-29 19:12:19 +04:00
|
|
|
width: 300px;
|
|
|
|
|
height: 300px;
|
2013-04-26 05:30:56 +04:00
|
|
|
font-size: 12pt;
|
2013-04-29 23:07:47 +04:00
|
|
|
overflow: hidden;
|
2013-04-26 05:30:56 +04:00
|
|
|
|
|
|
|
|
background: black;
|
2013-04-29 19:12:19 +04:00
|
|
|
box-sizing: border-box;
|
2013-04-26 05:30:56 +04:00
|
|
|
border: solid gray 1px;
|
|
|
|
|
color: white;
|
|
|
|
|
}
|
|
|
|
|
.current.image {
|
|
|
|
|
background: red;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-29 23:07:47 +04:00
|
|
|
/* dot mark... */
|
2013-04-29 19:12:19 +04:00
|
|
|
.marked.image:after {
|
|
|
|
|
display: block;
|
|
|
|
|
position: absolute;
|
|
|
|
|
content: "";
|
|
|
|
|
font-size: 0pt;
|
|
|
|
|
border: none;
|
|
|
|
|
|
2013-04-29 23:07:47 +04:00
|
|
|
width: 15px;
|
|
|
|
|
height: 15px;
|
2013-04-29 19:12:19 +04:00
|
|
|
|
|
|
|
|
bottom: 5px;
|
|
|
|
|
right: 5px;
|
|
|
|
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background: blue;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-29 23:07:47 +04:00
|
|
|
/* corner mark... (a-la bookmarks in PortableMag) */
|
|
|
|
|
/*
|
|
|
|
|
.marked.image:after {
|
|
|
|
|
display: block;
|
|
|
|
|
position: absolute;
|
|
|
|
|
content: "";
|
|
|
|
|
font-size: 0pt;
|
|
|
|
|
border: none;
|
|
|
|
|
|
|
|
|
|
width: 30px;
|
|
|
|
|
height: 30px;
|
|
|
|
|
|
|
|
|
|
top: -15px;
|
|
|
|
|
right: -15px;
|
|
|
|
|
|
|
|
|
|
background: blue;
|
|
|
|
|
|
|
|
|
|
-webkit-transform: rotate(45deg);
|
|
|
|
|
-moz-transform: rotate(45deg);
|
|
|
|
|
-o-transform: rotate(45deg);
|
|
|
|
|
-ms-transform: rotate(45deg);
|
|
|
|
|
transform: rotate(45deg);
|
|
|
|
|
}
|
|
|
|
|
*/
|
2013-04-26 05:30:56 +04:00
|
|
|
|
2013-04-30 00:28:47 +04:00
|
|
|
|
|
|
|
|
.marked-only.viewer:after {
|
|
|
|
|
display: block;
|
|
|
|
|
position: absolute;
|
|
|
|
|
content: "Showing marked images only";
|
|
|
|
|
font-size: 14pt;
|
|
|
|
|
border: none;
|
|
|
|
|
color: blue;
|
|
|
|
|
width: auto;
|
|
|
|
|
height: auto;
|
|
|
|
|
|
|
|
|
|
top: 10px;
|
|
|
|
|
right: 10px;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
.marked-only .image:not(.marked) {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
.marked-only .marked.image:after {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<script src="jquery.js"></script>
|
|
|
|
|
|
2013-04-26 23:07:07 +04:00
|
|
|
<script src="lib/jli.js"></script>
|
|
|
|
|
<script src="lib/keyboard.js"></script>
|
|
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
<script>
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
Viewer Generation III
|
|
|
|
|
|
|
|
|
|
Split the API into the following sections:
|
|
|
|
|
- main control actions
|
|
|
|
|
do main domain tasks like image and ribbon manipulation.
|
|
|
|
|
- serialization and deserialization
|
|
|
|
|
load and save data
|
|
|
|
|
- UI
|
|
|
|
|
basic align, animation and modes
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2013-04-29 19:12:19 +04:00
|
|
|
|
2013-04-30 00:28:47 +04:00
|
|
|
var toggleMarkedOnlyView = createCSSClassToggler('.viewer', 'marked-only',
|
|
|
|
|
function(){
|
|
|
|
|
var cur = $('.current.image')
|
|
|
|
|
// current is marked...
|
|
|
|
|
if(cur.hasClass('marked')){
|
|
|
|
|
centerImage(null, 'css')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// there is a marked image in this ribbon...
|
|
|
|
|
var target = getImageBefore(cur, null, true)
|
|
|
|
|
if(target.length > 0){
|
|
|
|
|
centerImage(focusImage(target), 'css')
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// get marked image from other ribbons...
|
|
|
|
|
prevRibbon()
|
|
|
|
|
if($('.current.image').hasClass('marked')){
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
nextRibbon()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XXX add ability to take all marked images and open them in a separate view...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-29 19:12:19 +04:00
|
|
|
var toggleImageMark = createCSSClassToggler('.current.image', 'marked')
|
|
|
|
|
|
2013-04-30 00:28:47 +04:00
|
|
|
// mode can be:
|
|
|
|
|
// - 'ribbon'
|
|
|
|
|
// - 'all'
|
|
|
|
|
function removeImageMarks(mode){
|
|
|
|
|
// remove marks from current ribbon (default)...
|
|
|
|
|
if(mode == 'ribbon' || mode == null){
|
|
|
|
|
return $('.current.image')
|
|
|
|
|
.closest('.ribbon')
|
|
|
|
|
.find('.marked')
|
|
|
|
|
.removeClass('marked')
|
|
|
|
|
|
|
|
|
|
// remove all marks...
|
|
|
|
|
} else if(mode == 'all'){
|
|
|
|
|
return $('.marked')
|
|
|
|
|
.removeClass('marked')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function markAll(mode){
|
|
|
|
|
// remove marks from current ribbon (default)...
|
|
|
|
|
if(mode == 'ribbon' || mode == null){
|
|
|
|
|
return $('.current.image')
|
|
|
|
|
.closest('.ribbon')
|
|
|
|
|
.find('.image:not(.marked)')
|
|
|
|
|
.addClass('marked')
|
|
|
|
|
|
|
|
|
|
// remove all marks...
|
|
|
|
|
} else if(mode == 'all'){
|
|
|
|
|
return $('.image:not(.marked)').addClass('marked')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-29 23:38:16 +04:00
|
|
|
function invertImageMarks(){
|
|
|
|
|
return $('.current.image')
|
|
|
|
|
.closest('.ribbon')
|
|
|
|
|
.find('.image')
|
|
|
|
|
.toggleClass('marked')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this will toggle marks in the current continuous section of marked
|
|
|
|
|
// or unmarked images...
|
|
|
|
|
function toggleImageMarkBlock(image){
|
|
|
|
|
if(image == null){
|
|
|
|
|
image = $('.current.image')
|
|
|
|
|
}
|
|
|
|
|
// we need to invert this...
|
|
|
|
|
var state = toggleImageMark()
|
|
|
|
|
var _convert = function(){
|
|
|
|
|
if(toggleImageMark(this, '?') == state){
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
toggleImageMark(this, state)
|
|
|
|
|
}
|
|
|
|
|
image.nextAll('.image').each(_convert)
|
|
|
|
|
image.prevAll('.image').each(_convert)
|
|
|
|
|
return state
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-30 00:28:47 +04:00
|
|
|
function nextMarkedImage(){
|
|
|
|
|
// XXX
|
|
|
|
|
}
|
|
|
|
|
function prevMarkedImage(){
|
|
|
|
|
// XXX
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-29 23:38:16 +04:00
|
|
|
|
2013-04-29 19:12:19 +04:00
|
|
|
|
2013-04-29 23:38:16 +04:00
|
|
|
// XXX should we use the createCSSClassToggler for this?
|
2013-04-29 22:54:04 +04:00
|
|
|
// XXX revise: does extra stuff...
|
|
|
|
|
function toggleImageProportions(mode){
|
|
|
|
|
var image = $('.image')
|
|
|
|
|
var h = image.outerHeight(true)
|
|
|
|
|
var w = image.outerWidth(true)
|
|
|
|
|
|
|
|
|
|
if(mode == '?'){
|
|
|
|
|
return h != w ? 'viewer' : 'square'
|
2013-04-29 19:12:19 +04:00
|
|
|
|
2013-04-29 22:54:04 +04:00
|
|
|
// square...
|
|
|
|
|
} else if(h != w || mode == 'square'){
|
|
|
|
|
var size = Math.min(w, h)
|
|
|
|
|
image.css({
|
|
|
|
|
width: size,
|
|
|
|
|
height: size
|
|
|
|
|
})
|
|
|
|
|
centerImage(null, 'css')
|
|
|
|
|
return 'square'
|
|
|
|
|
|
|
|
|
|
// viewer size...
|
|
|
|
|
} else {
|
|
|
|
|
var viewer = $('.viewer')
|
|
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
if(W > H){
|
|
|
|
|
image.css('width', W * h/H)
|
|
|
|
|
} else {
|
|
|
|
|
image.css('height', H * w/W)
|
|
|
|
|
}
|
|
|
|
|
centerImage(null, 'css')
|
|
|
|
|
return 'viewer'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: to avoid state sync problems this should clone an image if
|
|
|
|
|
// one is available...
|
2013-04-26 05:30:56 +04:00
|
|
|
function createImage(n){
|
|
|
|
|
if(n == null){
|
|
|
|
|
if(window._n == null){
|
|
|
|
|
window._n = 0
|
|
|
|
|
}
|
|
|
|
|
n = _n
|
|
|
|
|
_n += 1
|
|
|
|
|
}
|
2013-04-29 22:54:04 +04:00
|
|
|
var img = $('.image')
|
|
|
|
|
if(img.length > 0){
|
|
|
|
|
return img.first().clone()
|
|
|
|
|
.attr({
|
|
|
|
|
'order': n,
|
|
|
|
|
// need to strip extra classes...
|
|
|
|
|
'class': 'image'
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
return $('<div order="'+n+'" class="image"/>')
|
|
|
|
|
}
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
function createRibbon(){
|
|
|
|
|
return $('<div class="ribbon"/>')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: if this returns null, it means that the element is smallest in
|
|
|
|
|
// target ribbon -- first position.
|
2013-04-30 00:28:47 +04:00
|
|
|
function getImageBefore(image, ribbon, visible_only){
|
2013-04-26 05:30:56 +04:00
|
|
|
image = $(image)
|
2013-04-30 00:28:47 +04:00
|
|
|
if(ribbon == null){
|
|
|
|
|
ribbon = image.closest('.ribbon')
|
|
|
|
|
}
|
|
|
|
|
// pre marked-only mode...
|
|
|
|
|
//var images = $(ribbon).find('.image')
|
|
|
|
|
if(visible_only){
|
2013-04-30 00:33:49 +04:00
|
|
|
var images = $(ribbon).find('.image').filter(':visible')
|
2013-04-30 00:28:47 +04:00
|
|
|
} else {
|
|
|
|
|
var images = $(ribbon).find('.image')
|
|
|
|
|
}
|
2013-04-26 05:30:56 +04:00
|
|
|
var order = image.attr('order')
|
|
|
|
|
var prev = null
|
|
|
|
|
|
|
|
|
|
images.each(function(){
|
|
|
|
|
if(order < $(this).attr('order')){
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
prev = this
|
|
|
|
|
})
|
|
|
|
|
|
2013-04-29 22:54:04 +04:00
|
|
|
return $(prev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// basic navigation actions...
|
|
|
|
|
function nextImage(){
|
|
|
|
|
return centerImage(
|
|
|
|
|
focusImage(
|
2013-04-30 00:33:49 +04:00
|
|
|
// pre marked-only mode...
|
2013-04-30 00:28:47 +04:00
|
|
|
//$('.current.image').next('.image')))
|
|
|
|
|
$('.current.image').next('.image:visible')))
|
2013-04-29 22:54:04 +04:00
|
|
|
}
|
|
|
|
|
function prevImage(){
|
|
|
|
|
return centerImage(
|
|
|
|
|
focusImage(
|
2013-04-30 00:33:49 +04:00
|
|
|
// pre marked-only mode...
|
2013-04-30 00:28:47 +04:00
|
|
|
//$('.current.image').prev('.image')))
|
|
|
|
|
$('.current.image').prev('.image:visible')))
|
2013-04-29 22:54:04 +04:00
|
|
|
}
|
|
|
|
|
function firstImage(){
|
|
|
|
|
return centerImage(
|
|
|
|
|
focusImage(
|
2013-04-30 00:33:49 +04:00
|
|
|
// pre marked-only mode...
|
2013-04-30 00:28:47 +04:00
|
|
|
//$('.current.image').closest('.ribbon').find('.image').first()))
|
2013-04-30 00:33:49 +04:00
|
|
|
$('.current.image').closest('.ribbon').find('.image').filter(':visible').first()))
|
2013-04-29 22:54:04 +04:00
|
|
|
}
|
|
|
|
|
function lastImage(){
|
|
|
|
|
return centerImage(
|
|
|
|
|
focusImage(
|
2013-04-30 00:33:49 +04:00
|
|
|
// pre marked-only mode...
|
2013-04-30 00:28:47 +04:00
|
|
|
//$('.current.image').closest('.ribbon').find('.image').last()))
|
2013-04-30 00:33:49 +04:00
|
|
|
$('.current.image').closest('.ribbon').find('.image').filter(':visible').last()))
|
2013-04-29 22:54:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: if moving is 'next' these will chose the image after the current's order.
|
|
|
|
|
// NOTE: if an image with the same order is found, moving argument has no effect.
|
|
|
|
|
function prevRibbon(moving){
|
|
|
|
|
var cur = $('.current.image')
|
2013-04-30 00:28:47 +04:00
|
|
|
// pre marked-only mode...
|
|
|
|
|
//var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon'))
|
|
|
|
|
var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon:visible'), true)
|
2013-04-29 22:54:04 +04:00
|
|
|
if(moving == 'next' && cur.attr('order') != target.attr('order')){
|
|
|
|
|
var next = target.next('.image')
|
|
|
|
|
target = next.length > 0 ? next : target
|
|
|
|
|
}
|
|
|
|
|
return centerImage(focusImage(target))
|
|
|
|
|
}
|
|
|
|
|
function nextRibbon(moving){
|
|
|
|
|
var cur = $('.current.image')
|
2013-04-30 00:28:47 +04:00
|
|
|
// pre marked-only mode...
|
|
|
|
|
//var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon'))
|
|
|
|
|
var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon:visible'), true)
|
2013-04-29 22:54:04 +04:00
|
|
|
if(moving == 'next' && cur.attr('order') != target.attr('order')){
|
|
|
|
|
var next = target.next('.image')
|
|
|
|
|
target = next.length > 0 ? next : target
|
|
|
|
|
}
|
|
|
|
|
return centerImage(focusImage(target))
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 22:54:04 +04:00
|
|
|
|
|
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
function shiftTo(image, ribbon){
|
|
|
|
|
var target = getImageBefore(image, ribbon)
|
|
|
|
|
var cur_ribbon = image.closest('.ribbon')
|
|
|
|
|
|
|
|
|
|
// insert before the first image if nothing is before the target...
|
|
|
|
|
if(target == null){
|
|
|
|
|
image.insertBefore($(ribbon).find('.image').first())
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
image.insertAfter(target)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if removing last image out of a ribbon, remove the ribbon....
|
|
|
|
|
if(cur_ribbon.find('.image').length == 0){
|
|
|
|
|
cur_ribbon.remove()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function shiftImage(direction, image, force_create_ribbon){
|
|
|
|
|
if(image == null){
|
|
|
|
|
// XXX need to make this context specific...
|
|
|
|
|
image = $('.current.image')
|
|
|
|
|
} else {
|
|
|
|
|
image = $(image)
|
|
|
|
|
}
|
|
|
|
|
var ribbon = image.closest('.ribbon')[direction]('.ribbon')
|
|
|
|
|
|
|
|
|
|
// need to create a new ribbon...
|
|
|
|
|
if(ribbon.length == 0 || force_create_ribbon == true){
|
|
|
|
|
ribbon = createRibbon()['insert' + (direction == 'prev'
|
|
|
|
|
? 'Before'
|
|
|
|
|
: 'After')](image.closest('.ribbon'))
|
|
|
|
|
ribbon.append(image)
|
|
|
|
|
} else {
|
|
|
|
|
shiftTo(image, ribbon)
|
|
|
|
|
}
|
|
|
|
|
return image
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// short-hand methods...
|
|
|
|
|
function shiftImageUp(image){
|
|
|
|
|
return shiftImage('prev', image)
|
|
|
|
|
}
|
|
|
|
|
function shiftImageDown(image){
|
|
|
|
|
return shiftImage('next', image)
|
|
|
|
|
}
|
|
|
|
|
function shiftImageUpNewRibbon(image){
|
|
|
|
|
return shiftImage('prev', image, true)
|
|
|
|
|
}
|
|
|
|
|
function shiftImageDownNewRibbon(image){
|
|
|
|
|
return shiftImage('next', image, true)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO manual image ordering (shiftLeft/shiftRight functions)
|
|
|
|
|
// XXX
|
|
|
|
|
|
|
|
|
|
|
2013-04-26 05:33:38 +04:00
|
|
|
function focusImage(image){
|
|
|
|
|
image.closest('.viewer').find('.current.image').removeClass('current')
|
|
|
|
|
return image.addClass('current')
|
|
|
|
|
}
|
2013-04-26 05:30:56 +04:00
|
|
|
|
|
|
|
|
|
2013-04-26 23:07:07 +04:00
|
|
|
// Alignment API...
|
2013-04-29 01:59:59 +04:00
|
|
|
// ...tried to make this as brain-dead-stupidly-simple as possible...
|
|
|
|
|
function relativeVisualPosition(outer, inner){
|
|
|
|
|
outer = $(outer).offset()
|
|
|
|
|
inner = $(inner).offset()
|
|
|
|
|
return {
|
|
|
|
|
top: inner.top - outer.top,
|
|
|
|
|
left: inner.left - outer.left
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This appears to work well with scaling...
|
2013-04-29 02:31:01 +04:00
|
|
|
// XXX make this more configurable...
|
2013-04-29 02:57:11 +04:00
|
|
|
// XXX this only works for square images...
|
2013-04-29 01:59:59 +04:00
|
|
|
function centerImage(image, mode){
|
|
|
|
|
if(mode == null){
|
|
|
|
|
//mode = 'css'
|
|
|
|
|
mode = 'animate'
|
|
|
|
|
}
|
2013-04-29 22:54:04 +04:00
|
|
|
if(image == null || image.length == 0){
|
2013-04-29 01:59:59 +04:00
|
|
|
image = $('.current.image')
|
|
|
|
|
}
|
|
|
|
|
var viewer = $('.viewer')
|
2013-04-29 02:31:01 +04:00
|
|
|
// XXX should these be "inner"???
|
2013-04-29 01:59:59 +04:00
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
var ribbons = $('.ribbon-set')
|
|
|
|
|
var scale = getElementScale(ribbons)
|
2013-04-29 02:57:11 +04:00
|
|
|
// NOTE: these are scalable, this needs to get normalized...
|
2013-04-29 02:31:01 +04:00
|
|
|
var w = image.outerWidth()*scale
|
|
|
|
|
var h = image.outerHeight()*scale
|
2013-04-29 01:59:59 +04:00
|
|
|
|
|
|
|
|
var pos = relativeVisualPosition(viewer, image)
|
|
|
|
|
|
|
|
|
|
// zero out top/left if set to anything other than a specific number...
|
|
|
|
|
var t = parseFloat(ribbons.css('top'))
|
|
|
|
|
t = t ? t : 0
|
|
|
|
|
var l = parseFloat(ribbons.css('left'))
|
|
|
|
|
l = l ? l : 0
|
|
|
|
|
|
|
|
|
|
// do the actual work...
|
|
|
|
|
return ribbons[mode]({
|
|
|
|
|
'top': t - pos.top + (H - h)/2,
|
2013-04-29 02:57:11 +04:00
|
|
|
'left': l - pos.left + (W - w)/2
|
2013-04-29 01:59:59 +04:00
|
|
|
})
|
2013-04-26 23:07:07 +04:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 02:31:01 +04:00
|
|
|
function fitNImages(n){
|
|
|
|
|
var image = $('.current.image')
|
|
|
|
|
var size = image.outerHeight(true)
|
|
|
|
|
|
|
|
|
|
var viewer = $('.viewer')
|
|
|
|
|
var W = viewer.innerWidth()
|
|
|
|
|
var H = viewer.innerHeight()
|
|
|
|
|
|
|
|
|
|
var scale = Math.min(W / (size * n), H / size)
|
|
|
|
|
|
2013-04-29 02:57:11 +04:00
|
|
|
// XXX if animating, the next two likes must be animated together...
|
2013-04-29 02:31:01 +04:00
|
|
|
setElementScale($('.ribbon-set'), scale)
|
|
|
|
|
centerImage(image, 'css')
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
|
2013-04-29 01:59:59 +04:00
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
// NOTE: this is on purpose done relative...
|
|
|
|
|
function clickHandler(evt){
|
|
|
|
|
var img = $(evt.target).closest('.image')
|
2013-04-29 01:59:59 +04:00
|
|
|
|
|
|
|
|
centerImage(
|
|
|
|
|
focusImage(img))
|
2013-04-26 05:30:56 +04:00
|
|
|
}
|
|
|
|
|
|
2013-04-29 02:31:01 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-04-26 05:30:56 +04:00
|
|
|
// setup...
|
|
|
|
|
$(function(){
|
|
|
|
|
|
|
|
|
|
// populate the viewer...
|
|
|
|
|
var r = createRibbon()
|
|
|
|
|
var images = []
|
|
|
|
|
for(var i=0; i < 40; i++){
|
|
|
|
|
images.push(createImage().text(i)[0])
|
|
|
|
|
}
|
|
|
|
|
r.append($(images))
|
|
|
|
|
var rr = r.clone()
|
|
|
|
|
var rrr = r.clone()
|
|
|
|
|
|
|
|
|
|
$('.ribbon-set')
|
|
|
|
|
.append(r)
|
|
|
|
|
.append(rr)
|
|
|
|
|
.append(rrr)
|
|
|
|
|
|
|
|
|
|
// NOTE: this is global so as to not to add any extra complexity to
|
|
|
|
|
// the internal workings...
|
|
|
|
|
$('.viewer').click(clickHandler)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
|
|
|
|
|
<!-- This is the basic viewer structure...
|
|
|
|
|
|
|
|
|
|
Unpopulated
|
|
|
|
|
NOTE: there can be only .ribbon-set element.
|
|
|
|
|
|
|
|
|
|
<div class="viewer">
|
|
|
|
|
<div class="ribbon-set"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Populated
|
|
|
|
|
|
|
|
|
|
<div class="viewer">
|
|
|
|
|
<div class="ribbon-set">
|
|
|
|
|
<div class="ribbon">
|
|
|
|
|
<div class="image"></div>
|
|
|
|
|
<div class="image"></div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="ribbon">
|
|
|
|
|
<div class="image"></div>
|
|
|
|
|
<div class="current image"></div>
|
|
|
|
|
<div class="image"></div>
|
|
|
|
|
<div class="image"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
-->
|
|
|
|
|
|
|
|
|
|
<div class="viewer">
|
|
|
|
|
<div class="ribbon-set"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- vim:set ts=4 sw=4 spell : -->
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|