chourobin
6/18/2014 - 4:42 PM

CSS and JavaScript from Tumblr 3.0 for iOS (Summer 2012)

CSS and JavaScript from Tumblr 3.0 for iOS (Summer 2012)

/*  Copyright (c) 2012 Tumblr. All rights reserved. */
/*  License: Apache 2.0 */

/* General */

* {
    font-family: 'Helvetica Neue', sans-serif;
    margin: 0;
    padding: 0;
    word-wrap: break-word;
}

body {
    background-color: #2d4762;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

big {
    font-size: 100%;
	font: inherit;
}

ul,
ol {
    padding-left: 40px;
}

li {
    margin-top: 5px;
}

/* Shared */

.top-cap,
.photo,
.photo img,
.photoset,
.video,
.video img {
    border-radius: 6px 6px 0 0;
}

.audio,
.asker-container,
.source {
    overflow: auto;
}

#image-preload,
audio,
.more,
.read-more.hidden,
object {
    display: none;
}

.album-cover,
.avatar,
.answer-bubble,
.external-image-placeholder {
    border-radius: 6px;
}

.album-cover,
.avatar {
    box-shadow: 0 1px 2px 0 rgba(0,0,0,.45);
    float: left;
}

.post,
.photo img,
.video img {
    width: 302px;
}

.cached-image-container {
    display: none;
}

.gif-container.off:before {
    content: '';
    position: absolute;
    background-image: url(gif_button_resting.png);
    background-size: 72px;
    width: 72px;
    height: 72px;
    top: 50%;
    left: 50%;
    margin-top: -36px;
    margin-left: -36px;
}

.gif-container.off.active:before {
    background-image: url(gif_button_active.png);
}

/* Header, links */

header h2,
.post-body,
a:link,
a:visited,
a:hover {
    color: #333333;
}

.tag,
header h1,
.external-image-placeholder {
    color: #A8B1BA;
}

.tag.active,
.tumblelog.active,
a.active,
.external-image-placeholder.active {
    color: #619BCD;
}

header {
    padding-bottom: 0;
    margin-top: -2px
}

header h1,
.tags {
    font-size: 15px;
}

header h1 {
    margin-bottom: 0px;
}

header h2 {
    margin-top: 8px;
    font-size: 21px;
    line-height: 24px;
}

header h2:empty {
    display: none;
}

/* All post types */
/* For Future Bryan, this is to make Storyboard interviews look right. */
strong + p {
    margin-bottom: 8px;
}

p {
    margin-top: 8px;
    font-size: 15px;
    line-height: 1.3em;
}

.outer-post {
    padding-top: 2px;
    padding-bottom: 8px;
    
    margin: 7px auto 0 auto;
    width: 312px;
    
    background: url(post-top-shadow.png) no-repeat top, url(post-bottom-shadow.png) no-repeat bottom;
    background-size: 312px 15px;
}

.post {
    margin: auto;
    position: relative;
}

.post:before,
.post:after {
    content: '';
    position: absolute;
    bottom: 7px;
    top: 13px;
    width: 5px;
    background-size: 5px 1px;,
}

.post:before {
    left: -5px;
    background-image: url(post-left-shadow.png);
}

.post:after {
    right: -5px;
    background-image: url(post-right-shadow.png);
}

.top-cap,
.bottom-cap {
    height: 5px;
    background-color: white;
}

.top-cap + .post-body {
    padding-top: 10px;
}

.bottom-cap {
    border-radius: 0 0 6px 6px;
}

.post-body {
    background-color: white;
    padding: 15px 15px 15px 15px;
}

.post-body.no-actions {
    padding-bottom: 9px;
}

.content {
    overflow-x: hidden;
    -webkit-user-select: auto;
}

.read-more,
.external-image-container {
    -webkit-user-select: none;
}

blockquote:last-child{
    margin-bottom:0px;
}

.photoset .gif-container.off,
.content .gif-container.off {
    position: relative;
}

.content img,
.content iframe {
    max-width: 100%;
}

.content .cached-image-container,
.external-image-container {
    margin-top: 15px;
}

.external-image-container {
    margin-bottom: 15px;
}

.external-image-container,
.external-image-placeholder {
    display: block;
}

.external-image-placeholder {
    color: #ccc;
    border: 1px dashed #ccc;
    font-size: 16px;
    text-align: center;
}

.external-image-placeholder span {
    background-image: url(external_image_placeholder.png);
    background-repeat: no-repeat;
    background-size: 19px 38px;
    background-position-y: 1px;
    height: 16px;
    line-height: 44px;
    padding: 0 0 0 26px;
}

.external-image-placeholder.active {
    background-color: #bcdaf0;
    border-color: #619bcd;
    color: #619bcd;
}

.external-image-placeholder.active span {
    background-position: 0 -21px;
}

.external-image-placeholder.loading span {
    visibility: hidden;
}

pre {
    background-color: #E6E6E6;
    font-family: Courier, monospace;
    font-size: 11px;
    padding: 10px;
    margin-top: 10px;
}

.reblogged-post,
.asking-post {
    display: inline-block;
    vertical-align: text-top;
    margin: 0 4px 0 4px;
}

.reblogged-post {
    margin-top: 2px;
    width: 17px;
    height: 17px;
    background-size: 17px;
    background: url(reblogged_post_icon.png);
}

.asking-post {
    margin-top: 4px;
    width: 14px;
    height: 13px;
    background-size: 14px 13px;
    background: url(message_arrow.png);
}

blockquote {
    border-left: 4px solid #DCDCDC;
    margin: 13px 0 10px 10px;
    padding-left: 15px;
}

blockquote ul,
blockquote ol {
    padding-left: 15px;
}

.read-more {
    background: url(read_more_sprite.png);
    background-size: 272px;
    width: 272px;
    height: 44px;
    margin: 15px auto 0px auto;

    line-height: 44px;
    text-align: center;    
    font-weight: bold;    
    font-size: 16px;
    color: #A5A5A5;
    text-shadow: 0 1px 0 white;
}

.read-more:active {
    background-position-y: -54px;
}

.more.visible {
    display: block;
}

/* Highlighted posts */

.highlight {
    position: relative;
    height: 34px;
    color: white;
    text-transform: uppercase;
    text-align: center;
    line-height: 34px;
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.24);
}

.outer-highlight {
    background-color: #ffffff;
}

.photoset + .outer-highlight  {
    padding-top: 15px;
}

.highlight-icon {
    height: 20px;
    width: 20px;
    display: inline-block;
    background-size: 20px 20px;
    margin-left: 5px;
    vertical-align: text-top;    
}
    
.highlight:after {
    left: 0;
    content: '';
    width: 100%;
    height: 1px;
    position: absolute;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.24);
}

/* Video posts */
.video {
    position: relative;
    background-color: black;
    min-height: 226px;
}

.video .cached-image-container:before {
    content: '';
    position: absolute;
    background-image: url(play_button_resting.png);
    background-size: 72px;
    width: 72px;
    height: 72px;
    top: 50%;
    left: 50%;
    margin-top: -36px;
    margin-left: -36px;
}

.video .cached-image-container.active:before {
    background-image: url(play_button_active.png);
}

.incompatible-video {
    background: url(unsupported_video_icon.png) left center no-repeat;
    background-size: 27px 16px;
    height: 18px;
    padding-left: 34px;
    line-height: 18px;
    color: #BBBDBE;
    font-weight: bold;
}

/* Photo posts */
.photo {
    position: relative;
    overflow: hidden;
}

.photo:before,
.video:before {
    content: '';
    position: absolute;
    background-image: url(post_top_gloss.png);
    background-size: 302px 6px;
    width: 302px;
    height: 6px;
    top: 0;
    left: 0;
}

.photo:after {
    content: '';
    position: absolute;
    bottom: 0;
    width: 100%;
    height: 1px;
    background-color: rgba(0, 0, 0, 0.20);
}

.photo img,
.video img {
    display: block;
    background-color: white;
    height: 100%;
}

.photo img.placeholder {
    background: url(post_photo_empty_shadow.png) #F5F5F5 repeat-x bottom;
    background-size: 1px 6px;
}

.photoset {
    padding: 15px 15px 0px 15px;
    background-color: white;
}

.photoset img {
    width: 100%;
}

.photoset-image-container {
    float: left;
    box-shadow: 0 1px 2px 0 rgba(0,0,0,.45);
}


.photoset-image-container,
.photoset-image-container .cached-image-inner-container {
    border-radius: 3px;
    overflow: hidden;
}

.photoset-image-container,
.photoset-image-container .cached-image-container {
    height: 100%;
}

.photoset .row {
    line-height: 0;
    margin-bottom: 10px;
}

.photoset .row:last-child {
    margin-bottom: 0;
}

.photoset .row1 .photoset-image-container {
    width: 272px;
}

.photoset .row2 .photoset-image-container {
    width: 131px;
}

.photoset .row2 .photoset-image-container .gif-container.off:before {
    background-image: url(gif_button_half_resting.png);
    background-size: 36px;
    width: 36px;
    height: 36px;
    margin-top: -18px;
    margin-left: -18px;
}

.photoset .row2 .photoset-image-container .gif-container.off.active:before {
    background-image: url(gif_button_half_active.png);
}

.photoset .row3 .photoset-image-container {
    width: 84px;
}

.photoset .row3 .photoset-image-container .gif-container.off:before {
    background-image: url(gif_button_third_resting.png);
    background-size: 24px;
    width: 24px;
    height: 24px;
    margin-top: -12px;
    margin-left: -12px;
}

.photoset .row3 .photoset-image-container .gif-container.active.off:before {
    background-image: url(gif_button_third_active.png);
}

.photoset .row2 .photoset-image-container,
.photoset .row3 .photoset-image-container {
    margin-right: 10px;
}

.photoset .photoset-image-container:last-child {
    margin-right: 0;
}

/* Answer posts */

.answer-bubble {
    position: relative;
    padding: 10px;
    border: 1px solid #BFBFBF;
    background: rgba(0, 0, 0, 0.05);
    margin: 15px 0 0 0;
}

.answer-bubble:before {
    content: "";
    position: absolute;
    bottom: -10px;
    left: 40px;
    border-width: 10px 10px 0;
    border-style: solid;
    border-color: #B6B6B6 transparent;
}

.answer-bubble:after {
    content: "";
    position: absolute;
    bottom: -9px;
    left: 41px;
    border-width: 9px 9px 0;
    border-style: solid;
    border-color: #F2F2F2 transparent;
}

.avatar {
    width: 44px;
    height: 44px;
    background-size: 44px;
    margin-right: 10px;
    margin-left: 30px;
    background-color: rgba(0, 0, 0, 0.05);
}

.asker-container {
    margin-top: 20px;
    font-weight: bold;
    line-height: 44px;
    padding-bottom: 3px;
    overflow: auto;
}

/* Quote posts */

.quote {
    font-weight: bold;
    margin: 10px 0 0 0;
}

.quote :first-child, .quote :last-child {
    display: inline;
}

.quote:before {
    content: '\201C';
}

.quote:after {
    content: '\201D';
}

.dash {
    float: left;
}

.source {
    margin-left: 20px;
}

.dash, 
.source {
    margin-top: 10px;
}

.source p:first-child {
    margin-top: 0;
}

/* Chat posts */

.speaker {
    font-weight: bold;
    padding-right: 4px;
}

p.line {
    margin: 10px 0 0 0;
}

/* Audio posts */

.audio {
    overflow-x: hidden;
    margin: 10px 0 0 -2px;  
    padding: 1px 0 3px 2px;
}

.album-cover,
.audio-player {
    height: 72px;
}

.album-cover {
    width: 72px;
    margin-right: 15px;
    background-size: 72px;
}

.audio-player .audio-player-inner {
    position: absolute;
    top: 50%;
    
    width: 93%;
    height: 40px;
    
    margin-left: 10px;
    margin-right: 10px;
    margin-top: -20px;
}

.audio-player .audio-player-inner.single-line {
    height: 20px;
    margin-top: -10px;
}

.audio-player p {
    margin: 0;
    
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;    
}

.audio-player p.song-title {
    font-weight: bold;
}

.audio-player {
    overflow: hidden;
    position: relative;
    
    border-width: 0px 6px 0px 36px;
    -webkit-border-image: url(dashboard_audio_post_play_button_sprite.png) 0 6 77 36 stretch stretch;
}

.audio-player.spotify {
    -webkit-border-image: url(dashboard_audio_post_spotify_sprite.png) 0 6 77 36 stretch stretch;
}

.audio-player.active {
    -webkit-border-image: url(dashboard_audio_post_play_button_sprite.png) 77 6 0 36 stretch stretch;
}

.audio-player.spotify.active {
    -webkit-border-image: url(dashboard_audio_post_spotify_sprite.png) 77 6 0 36 stretch stretch;
}

.audio-player.playing {
    -webkit-border-image: url(dashboard_audio_post_pause_button_sprite.png) 0 6 77 36 stretch stretch;
}

.audio-player.playing.active {
    -webkit-border-image: url(dashboard_audio_post_pause_button_sprite.png) 77 6 0 36 stretch stretch;
}

/* Tags */

.tags {
    margin-top: 10px;
    white-space: nowrap;
    overflow: scroll;
    -webkit-mask-image: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(0,0,0,0)), color-stop(2%,rgba(0,0,0,1)), color-stop(97%,rgba(0,0,0,1)), color-stop(100%,rgba(0,0,0,0)));
    padding-left: 3px;
    margin-left: -3px;
}
.tags:empty {
    margin-top: 0;
}

.tag {
    margin: 0 10px 5px 0;
}

.tag:before {
    content: '#';
}

.tag.featured {
    color: #FFFFFF;
    font-weight: bold;
    font-size: 13px;
    
    display: inline-block;
    padding: 1px 3px 2px 3px;
    border-width: 0 5px 0 5px;
    
    -webkit-border-image: url(featured_tag_sprite.png) 0 5 24 5;
}

.tag.featured.active {
    -webkit-border-image: url(featured_tag_sprite.png) 24 5 0 5;
}

/* Post controls */
footer {
    clear: both;
    height: 46px;
    line-height: 45px; /* Vertically center text */
    border-top: 1px solid #D1D1D1;
    overflow: hidden;
    font-weight: bold;    
    font-size: 16px;
    color: #A5A5A5;
    text-shadow: 0 1px 0 white;
    text-align: center;
}

.post-controls {
    width: 100%;
    display: table;
    table-layout: fixed;
}

.post-controls-row {
    display: table-row;
}

.post-control-text-cropper {
    display: block;
    overflow: hidden;
    height: 45px;
}

.control {
    position: relative;
    height: 45px;
    overflow: hidden;
    
    background-color: #E9E9E9;
    border-right: 2px solid #F6F6F6;
    border-left: 1px solid #F6F6F6;
    border-top: 1px solid #F6F6F6;
    outline: 1px solid #C7C7C7;
    
    display: table-cell;
}

.control.like{
    border-right: 1px solid #F6F6F6;
    padding-right: 1px;
}

.control.active {
    background-color: #CACACA;
    border-color: #CACACA;
}

.control:first-child {
    border-bottom-left-radius: 6px;
}

.control:last-child {
    border-bottom-right-radius: 6px;
}

.post-controls-row2 .control.notes {
    width: 151px;
}

.post-controls-row3 .control.notes {
    width: 148px;
}

.post-controls-row4 .control.notes {
    width: 138px;
}

.control.notes .notes-label {
    display: none;
}

.control.notes .notes-label.current {
    display: inline;
}

.post-control-icon {
    left: 50%;
    margin-left: -11px;
    position: absolute;
    
    height: 100%;
    width: 100%;
    
    background-image: url(dashboard_post_controls_sprite.png);
    background-repeat: no-repeat;
    background-size: 375px 200px;
}
.control.publish {
    width: 85px;
    border-right: 1px solid #F6F6F6;
    padding-right: 1px;
}

.control.publish.active {
    border-color: #CACACA;
}

.control.answer {
    width: 151px;
    border-right: 1px solid #F6F6F6;
    padding-right: 1px;
}

.control.answer.active {
    border-color: #CACACA;
}

.control.edit {
    border-right: 1px solid #F6F6F6;
    padding-right: 1px;
}

.control.edit.active {
    border-color: #CACACA;
}

.edit .post-control-icon,
.delete .post-control-icon,
.queue .post-control-icon {
    top: 50%;
}

.edit .post-control-icon {
    margin-left: -10px;    
    margin-top: -11px;
    background-image: url(post_control_edit.png);
    background-size: 23px 22px;
}

.delete .post-control-icon {
    margin-left: -8px;    
    margin-top: -11px;
    background-image: url(post_control_delete.png);
    background-size: 16px 22px;
}

.queue .post-control-icon {
    margin-left: -11px;
    margin-top: -11px;
    background-image: url(post_control_queue.png);
    background-size: 21px 22px;
}

/* Retina display */
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
    .post-control-icon {
        background-image: url(dashboard_post_controls_sprite@2x.png);
    }
    
    .tag.featured {
        -webkit-border-image: url(featured_tag_sprite@2x.png) 0 9 48 9;
    }
    
    .tag.featured.active {
        -webkit-border-image: url(featured_tag_sprite@2x.png) 48 9 0 9;
    }
    
    .external-image-placeholder span {
        background-image: url(external_image_placeholder@2x.png);
    }
    
    .read-more {
        background: url(read_more_sprite@2x.png);
    }
    
    .audio-player {
        -webkit-border-image: url(dashboard_audio_post_play_button_sprite@2x.png) 0 12 154 74 stretch stretch;
    }
    
    .audio-player.spotify {
        -webkit-border-image: url(dashboard_audio_post_spotify_sprite@2x.png) 0 12 154 74 stretch stretch;
    }    
    
    .audio-player.active {
        -webkit-border-image: url(dashboard_audio_post_play_button_sprite@2x.png) 154 12 0 74 stretch stretch;
    }
    
    .audio-player.spotify.active {
        -webkit-border-image: url(dashboard_audio_post_spotify_sprite@2x.png) 154 12 0 74 stretch stretch;
    }    
    
    .audio-player.playing {
        -webkit-border-image: url(dashboard_audio_post_pause_button_sprite@2x.png) 0 12 154 74 stretch stretch;
    }
    
    .audio-player.playing.active {
        -webkit-border-image: url(dashboard_audio_post_pause_button_sprite@2x.png) 154 12 0 72 stretch stretch;
    }
    
    .reblogged-post {
        background: url(reblogged_post_icon@2x.png);
    }
    
    .asking-post {
        background: url(message_arrow@2x.png);
    }    
    
    .photo img.placeholder {
        background: url(post_photo_empty_shadow@2x.png) #F5F5F5 repeat-x bottom;
    }
    
    .gif-container.off:before {
        background-image: url(gif_button_resting@2x.png);
    }
    
    .gif-container.off.active:before {
        background-image: url(gif_button_active@2x.png);
    }
    
    .photoset .row2 .photoset-image-container .gif-container.off:before {
        background-image: url(gif_button_half_resting@2x.png);
    }
    
    .photoset .row2 .photoset-image-container .gif-container.off.active:before {
        background-image: url(gif_button_half_active@2x.png);
    }
    
    .photoset .row3 .photoset-image-container .gif-container.off:before {
        background-image: url(gif_button_third_resting@2x.png);
    }
    
    .photoset .row3 .photoset-image-container .gif-container.active.off:before {
        background-image: url(gif_button_third_active@2x.png);
    }
    
    .video .cached-image-container:before {
        background-image: url(play_button_resting@2x.png);
    }
    
    .video .cached-image-container.active:before {
        background-image: url(play_button_active@2x.png);
    }
    
    .post:before {
        background-image: url(post-left-shadow@2x.png);
    }
    
    .post:after {
        background-image: url(post-right-shadow@2x.png);
    }
    
    .outer-post {
        background: url(post-top-shadow@2x.png) no-repeat top, url(post-bottom-shadow@2x.png) no-repeat bottom;
    }
    
    .edit .post-control-icon {
        background-image: url(post_control_edit@2x.png);
    }
    
    .delete .post-control-icon {
        background-image: url(post_control_delete@2x.png);
    }
    
    .queue .post-control-icon {
        background-image: url(post_control_queue@2x.png);
    }
    
    .photo:before,
    .video:before {
        background-image: url(post_top_gloss@2x.png);
    }
    
    .incompatible-video {
        background: url(unsupported_video_icon@2x.png) left center no-repeat;
    }
}

/* Mobile WebKit apparently wants these to be defined after the retina background property */

.reply .post-control-icon {
    background-position: -1px 12px;
}

.reblog .post-control-icon {
    background-position: -1px -49px;
}

.reply.activated  .post-control-icon,
.reblog.activated .post-control-icon {
    background-position-x: -341px;
}

.like .post-control-icon {
    background-position: 0 -126px;
}

.like.activated .post-control-icon {
    background-position-x: -340px;
}
//  Copyright (c) 2012 Tumblr. All rights reserved.
//  License: Apache 2.0

// We're using an 'active' class instead of the default :active pseudo selector because we can add/remove it easily
var elementsWithActiveStateSelector = ['.tumblelog', '.control', '.audio-player', '.tag', 'a', '.video', 
                                       '.gif-container', '.external-image-placeholder'].join(',');

$('#content').on('touchstart', elementsWithActiveStateSelector, function() {
    var $el = $(this);

    $el.addClass('touched');
                 
    // When an element is touched, wait to make sure we don't start scrolling, then add the active state
    setTimeout(function() {
        if (!scrolling) {
            $el.addClass('active');
        }
    }, 75);
});

$('#content').on('touchend', elementsWithActiveStateSelector, function() {
    var $el = $(this);             
                 
    if ($el.hasClass('touched')) {
        $el.removeClass('touched');
        
        // Hack - handle likes in 'touchend' since we want them to be noticeably faster than they were previously
        if ($el.hasClass('like') && !scrolling) {
            $el.toggleClass('activated');

            var postID = $el.data('post-id');
            var reblogKey = $el.data('reblog-key');
            var like = $el.hasClass('activated');
                 
            objectCallback({
                action: 'likePost',
                reblogKey: reblogKey,
                postID: postID,
                like: like
            });

            var $notesLabel = $el.siblings('.notes').first().find('.notes-label.current').first();
            
            $notesLabel.removeClass('current');
                 
            if (like) {
                 $notesLabel.next().addClass('current');
            } else {
                 $notesLabel.prev().addClass('current');
            }
        }

        $el.removeClass('active'); // Clear active state when user stops touching an element
    }

    return false;
});

$('#content').on('touchmove', '.active', function() {
    $(this).removeClass('active').removeClass('touched'); // Clear active state when user moves their touch (e.g. scrolls)
});




// Tap handler registration

var registerTapHandler = function(selector, handler) {
    var tapHandler = function(event) {
        if (scrolling) {
            return;
        }

        // Make sure active states are cleared before handling a tap
        $('.active').removeClass('active').removeClass('touched');

        handler.call(this, event);
    };
    
    $('#content').on('tap', selector, tapHandler);
};

registerTapHandler('.tumblelog', function() {
    var tumblelogID = $(this).text();
                  
    return objectCallback({
        action: 'viewTumblelog',
        tumblelogID: tumblelogID
    });
});

registerTapHandler('.tag', function() {
    var tag = $(this).text();

    console.log('Tag: ' + tag);
                   
    return objectCallback({
        action: 'viewTag',
        tagName: tag
    });
});

registerTapHandler('.external-image-container', function() {
    var $el = $(this);
    var $placeholder = $el.find('.external-image-placeholder').eq(0);

    if ($el.hasClass('on')) {
        $el.find('img').remove();
        $placeholder.find('.spinner').remove();
        $placeholder.show();
        $el.removeClass('on');

    } else {
        newSpinner({
            length: 5,
            radius: 7,
            color: '#000',
        }).spin($placeholder.get(0));

        $placeholder.addClass('loading');

        $('<img>')
                .attr('src', $el.data('image-url'))
                .one('load', function() {
                    $placeholder.hide();
                    $placeholder.removeClass('loading');
                    $el.append(this);
                    $el.addClass('on');
                });
    }
});

registerTapHandler('.photo .gif-container, .content .gif-container', function() {
    var $el = $(this);
    var $img = $el.find('img').eq(0);
    var newURL = $el.hasClass('off') ? $el.data('gif-url') : $el.data('image-url');
                 
    $('<img>')
            .attr('src', 'file://' + newURL)
            .one('load', function() {
                $img.replaceWith(this);
                $el.toggleClass('off');
            });
});

registerTapHandler('.read-more', function() {
    $(this).hide().siblings('.more').show();    
});

/*
 * Apparently Zepto's 'tap' event doesn't satisfy Mobile Safari's user-initiation policy. Monitor touchend instead.
 * I filed this as an issue here: https://github.com/madrobby/zepto/issues/479
 */
$('#content').on('touchend', '.audio-player', function() {
    if (scrolling) {
        return; // Prevent inadvertent audio play when user is dragging
    }

    var $el = $(this);

    var audioPlayer = $el.find('audio').get(0);

    var audioURL = audioPlayer.src;

    if (audioURL.indexOf('open.spotify.com') === -1) {
        if (audioPlayer.paused) {
            pauseAudioPlayers();
            audioPlayer.play();
        } else {
            audioPlayer.pause();
        }
                 
        $el.toggleClass('playing');
    } else {
        return objectCallback({ 
            action: 'openURL', 
            url: audioURL
        });
    }
});

var spinnerDefaults = {
    lines: 12,
    width: 2,
    rotate: 0,
    speed: 1,
    trail: 60,
    shadow: false,
    hwaccel: false,
    className: 'spinner',
    zIndex: 2e9,
    top: 'auto',
    left: 'auto'
};

function newSpinner(customProperties) {
    var spinnerProperties = {};

    for (var property in spinnerDefaults) {
        spinnerProperties[property] = spinnerDefaults[property];
    }

    for (var property in customProperties) {
        spinnerProperties[property] = customProperties[property];
    }

    return new Spinner(spinnerProperties);
}

registerTapHandler('.photo, .photoset', function(event) {
    var $el = $(this);

    // Don't show modal for single photo GIFs
    if ($el.hasClass('photo') && $el.find('.gif-container').size() != 0) {
        return;
    }

    var postID = $el.data('post-id');
                 
    var payload = {
        action: 'viewPhoto',
        postID: postID
    };
                 
    var $photosetContainer = $(event.target).closest('.photoset-image-container');

    if ($photosetContainer.size() > 0) {
        payload.index = $photosetContainer.data('index');
    }

    return objectCallback(payload);
});

registerTapHandler('.video', function() {
    var $el = $(this);
    var postID = $el.data('post-id');
                 
    return objectCallback({
        action: 'playVideo',
        postID: postID
    });                 
});

registerTapHandler('.notes', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var tumblelogID = $el.data('blog-name');

    return objectCallback({
        action: 'viewNotes',
        postID: postID,
        tumblelogID:tumblelogID
    });
});

registerTapHandler('.reblog', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var reblogKey = $el.data('reblog-key');
    
    return objectCallback({
        action: 'reblogPost',
        postID: postID,
        reblogKey: reblogKey
    });
});

registerTapHandler('.reply', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var reblogKey = $el.data('reblog-key');
                 
    return objectCallback({
        action: 'replyToPost',
        postID: postID,
        reblogKey: reblogKey
    });
});

registerTapHandler('.like', function() {
    /*
     * Since we delay turning on the active state on touchstart to see if the user scrolls, it's possible for the 
     * touchend code which removes the active state to fire before the active state is added. When this happens, the 
     * active state will be stuck and we rely on code in the tap handler to clear it.
     *
     * We are handling likes in the touchend handler to ensure they happen as fast as possible, but want to keep this 
     * tap handler around to ensure that the active state is properly cleaned up.
     */
});

registerTapHandler('.delete', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var tumblelogID = $el.data('blog-name');

    return objectCallback({
        action: 'deletePost',
        postID: postID,
        tumblelogID:tumblelogID                          
    });
});

registerTapHandler('.queue', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var tumblelogID = $el.data('blog-name');                 

    return objectCallback({
        action: 'queuePost',
        postID: postID,
        tumblelogID:tumblelogID                          
    });
});

registerTapHandler('.publish', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var tumblelogID = $el.data('blog-name');                 

    return objectCallback({
        action: 'publishPost',
        postID: postID,
        tumblelogID:tumblelogID                          
    });
});

registerTapHandler('.edit', function() {
    var $el = $(this);

    var postID = $el.data('post-id');

    return objectCallback({
        action: 'editPost',
        postID: postID
    });
});

registerTapHandler('.answer', function() {
    var $el = $(this);

    var postID = $el.data('post-id');
    var askingName = $el.data('asking-name');

    return objectCallback({
        action: 'editPost',
        postID: postID
    });
});

registerTapHandler('a', function() {
    var $el = $(this);
    var url = $el.attr('href');

    var matches = url.match(/post\/([0-9]+)/);

    if (matches && matches.length > 0) {
        var postID = matches[1];
        var tumblelogID = $el.text();

        return objectCallback({
            action: 'viewPost',
            postID: postID,
            tumblelogID: tumblelogID
        });
    } else {
        return objectCallback({
            action: 'openURL',
            url: url
        });
    }
});




// Spinner implementation from: http://fgnass.github.com/spin.js/

var loadingSpinner = newSpinner({
    length: 3.2,
    radius: 5,
    color: '#FFF',
});

// Methods called by native code

// There doesn't seem to be a great way to tell when scrolling stops/ends via JavaScript, so we let native code tell us

var scrolling = false;

function scrollingBegan() {
    scrolling = true;
}

function scrollingEnded() {
    setTimeout(function() {
        scrolling = false;
    }, 250);
}

var $contentRoot = $('#content');

function appendContent(newContent) {
    $contentRoot.append(newContent);
    
    stopLoading();
}

function loadCachedImage(payload) {
    var imageID = payload.id;
    var imageURL = payload.url;
    var imageGIFURL = payload.gifURL;
    
    $('div.cached-image-container[data-image-id="' + imageID + '"]').each(function() {
        var $container = $(this);
        
        $container.data('image-url', imageURL);

        if (imageGIFURL) {
            $container
                    .addClass('gif-container')
                    .addClass('off')
                    .data('gif-url', imageGIFURL);
        }
        
        $container
                .find('.cached-image')
                .on('load', function() {
                    $container.siblings('img.placeholder').first().remove();
                    $container.show();
                })
                .attr('src', 'file://' + imageURL);
    });
}

function pauseAudioPlayers() {
    $('.audio-player.playing').each(function() {
        var $player = $(this);
        $player.removeClass('playing');
        $player.find('audio').get(0).pause();
    });    
}

function repliedToPost(postID) {
    $('div.control.reply[data-post-id="' + postID + '"]').addClass('activated');
}

function removePost(postID) {
    $('.outer-post[data-post-id="' + postID + '"]').remove(); 
}