diff --git a/app/assets/javascripts/actions.coffee b/app/assets/javascripts/actions.coffee new file mode 100644 index 0000000..759e4eb --- /dev/null +++ b/app/assets/javascripts/actions.coffee @@ -0,0 +1,23 @@ +$(document).delegate '.actions input[type=submit].watched', 'click', -> + $(this).closest('.actions').addClass('asking') + false + +$(document).delegate '.actions input[type=submit].watched', 'ajax:before', -> + false + +$(document).delegate '.actions .question a[href="#cancel"]', 'click', -> + $(this).blur().closest('.actions').removeClass('asking') + false + +$(document).delegate '.actions .button_to', 'ajax:success', (e, html) -> + replaceActions $(this).closest('.actions'), html + +$(document).delegate 'a.revert', 'ajax:success', (e, html) -> + replaceActions $(this).closest('.actions'), html + +# preserve the ".other-info" element while replacing ".actions" +replaceActions = (element, content) -> + parent = element.parent() + element.replaceWith(content) + preserve = element.find('.js-preserve') + parent.find('.actions').eq(0).prepend preserve diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 4593811..b092627 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,202 +1,3 @@ -//= require prototype -//= require rails -//*= require_tree . - -if ('createTouch' in document) { - try { - $A(document.styleSheets).each(function(stylesheet){ - var ignore = /:hover\b/, idxs = [] - $A(stylesheet.cssRules).each(function(rule, idx) { - if (rule.type == CSSRule.STYLE_RULE && ignore.test(rule.selectorText)) { - idxs.push(idx) - } - }) - idxs.reverse().each(function(idx) { stylesheet.deleteRule(idx) }) - }) - } catch (e) {} -} - -document.on('click', '.actions input[type=submit].watched', function(e, button) { - e.stop() - button.up('.actions').addClassNameTransition('asking') -}) -document.on('ajax:before', '.actions input[type=submit].watched', function(e) { e.stop() }) - -document.on('click', '.actions .question a[href="#cancel"]', function(e, link) { - e.stop() - link.blur() - link.up('.actions').removeClassNameTransition('asking') -}) - -document.on('ajax:success', '.actions .button_to', function(e, form) { - if (useTransitions && !Prototype.Browser.Opera) { - form.select('input[type=submit][data-disable-with]').invoke('removeAttribute', 'data-disable-with') - - form.up('.actions').addClassName('fadeout').transitionEnd(function() { - var parent = this.up() - this.replaceActions(e.memo.responseText) - var actions = parent.down('.actions') - actions.addClassName('hidden') - ;(function() { actions.removeClassName('hidden').addClassName('fadein') }).defer() - }) - } else { - form.up('.actions').replaceActions(e.memo.responseText) - } -}) - -document.on('ajax:success', 'a.revert', function(e, link) { - link.up('.actions').replaceActions(e.memo.responseText) -}) - -Element.addMethods({ - getText: function(element) { - element = $(element) - return element.textContent || element.innerHTML.stripTags() - }, - once: function(element, event, selector, fn) { - element = $(element) - if (!fn) { fn = selector, selector = null } - - var handler, executed = false, wrapper = function() { - if (!executed) { - fn.apply(this, arguments) - executed = true - handler.stop() - } - } - if (selector) handler = element.on(event, selector, wrapper) - else handler = element.on(event, wrapper) - - return handler - }, - // preserve the ".other-info" element while replacing ".actions" - replaceActions: function(element, content) { - element = $(element) - var parent = element.up() - element.replace(content) - parent.down('.actions').insert({ top: element.down('.js-preserve') }) - return element - } -}) - -var useTransitions = Modernizr.csstransitions, - transitionEvent = Prototype.Browser.WebKit ? 'webkitTransitionEnd' : - Prototype.Browser.Opera ? 'oTransitionEnd' : 'transitionend' - -if (useTransitions) { - Element.addMethods({ - addClassNameTransition: function(element, name) { - element = $(element) - tmpName = name + '-transition' - element.addClassName(tmpName).transitionEnd(function() { - element.removeClassName(tmpName).addClassName(name) - }) - return element - }, - removeClassNameTransition: function(element, name) { - element = $(element) - tmpName = name + '-transition-back' - element.removeClassName(name).addClassName(tmpName).transitionEnd(function() { - element.removeClassName(tmpName) - }) - return element - }, - transitionEnd: function(element, handler) { - element = $(element) - element.once(transitionEvent, handler) - return element - } - }) -} else { - Element.addMethods({ - addClassNameTransition: Element.addClassName, - removeClassNameTransition: Element.removeClassName - }) -} - -Function.prototype.throttle = function(t) { - var timeout, scope, args, fn = this, tick = function() { - fn.apply(scope, args) - timeout = null - } - return function() { - scope = this - args = arguments - if (!timeout) timeout = setTimeout(tick, t) - } -} - -var pagination = $$('.pagination').first() - -if (pagination) { - var page = parseInt(pagination.down('em').getText()), - lastPage = parseInt(pagination.select('a:not(.next_page)').last().getText()), - url = window.location.toString(), - container = $$('ol.movies').first(), - loading = false - - var scrollHandler = Element.on(Prototype.Browser.WebKit ? document : window, 'scroll', function() { - if (loading) return - var viewportHeight = document.viewport.getHeight() - - if (pagination.viewportOffset().top - viewportHeight < viewportHeight/2) { - loading = true - new Ajax.Request(url, { - method: 'get', parameters: {page: ++page}, - onSuccess: function(r) { - container.insert(r.responseText) - if (page == lastPage) { - scrollHandler.stop() - pagination.hide() - } - loading = false - } - }) - } - }) -} - -// Emulates HTML5 "placeholder" and "autofocus" attributes. -// from https://github.com/teambox/teambox/blob/master/app/javascripts/html5.js -document.on('dom:loaded', function() { - if (!window.Modernizr) return - - if (!Modernizr.input.placeholder) { - var selector = 'input[placeholder], textarea[placeholder]' - - function emulatePlaceholder(input) { - var val = input.getValue(), text = input.readAttribute('placeholder') - if (val.empty() || val === text) - input.setValue(text).addClassName('placeholder') - } - - document.on('focusin', selector, function(e, input) { - if (input.getValue() === input.readAttribute('placeholder')) - input.setValue('').removeClassName('placeholder') - }) - - document.on('focusout', selector, function(e, input) { - emulatePlaceholder(input) - }) - - // setup existing fields - $$(selector).each(emulatePlaceholder) - - // observe form submits and clear emulated placeholder values - $(document.body).on('submit', 'form:has(' + selector + ')', function(e, form) { - form.select(selector).each(function(field) { - if (field.getValue() == field.readAttribute('placeholder')) field.setValue('') - }) - }) - - // observe new forms inserted into document and setup fields inside - document.on('DOMNodeInserted', 'form', function(e) { - if (e.element().match('form')) e.element().select(selector).each(emulatePlaceholder) - }) - } - - if (!Modernizr.input.autofocus) { - var input = $(document.body).down('input[autofocus]') - if (input) input.activate() - } -}) +//= require zepto +//= require ujs +//= require_tree . diff --git a/app/assets/javascripts/html5.coffee b/app/assets/javascripts/html5.coffee new file mode 100644 index 0000000..7529bfc --- /dev/null +++ b/app/assets/javascripts/html5.coffee @@ -0,0 +1,43 @@ +# Emulates HTML5 "placeholder" and "autofocus" attributes. +# from https://github.com/teambox/teambox/blob/master/app/javascripts/html5.js +$ -> + return unless window.Modernizr + + unless Modernizr.input.placeholder + inputs = $('input[placeholder], textarea[placeholder]') + + emulatePlaceholder = (input) -> + val = input.val() + text = input.attr('placeholder') + if not val or val is text + input.val(text).addClass 'placeholder' + + inputs.live 'focusin', -> + input = $(this) + if input.val() is input.attr('placeholder') + input.val('').removeClass 'placeholder' + + inputs.live 'focusout', -> + emulatePlaceholder $(this) + + # setup existing fields + inputs.each -> + emulatePlaceholder $(this) + + $(document).delegate "form:has(#{inputs.selector})", 'submit', -> + $(this).find(inputs.selector).each -> + input = $(this) + input.val('') if input.val() is field.attr('placeholder') + + # observe new forms inserted into document and setup fields inside + $(document).delegate 'form', 'DOMNodeInserted', (e) -> + el = $(this) + if el.is('form') + el.find(inputs.selector).each -> + emulatePlaceholder $(this) + + unless Modernizr.input.autofocus + input = $('input[autofocus]').eq(0) + if input.size() + input.focus() + input.get(0).select() diff --git a/app/assets/javascripts/pagination.coffee b/app/assets/javascripts/pagination.coffee new file mode 100644 index 0000000..ff2ae31 --- /dev/null +++ b/app/assets/javascripts/pagination.coffee @@ -0,0 +1,30 @@ +pagination = $('.pagination').eq(0) + +viewportOffset = (el) -> + el.offset().top - document.body.scrollTop + +if pagination.size() + page = parseInt(pagination.find('.current').text()) + lastPage = parseInt(pagination.find('a:not(.next_page)').eq(-1).text()) + url = window.location.toString() + container = $('ol.movies').eq(0) + loading = false + scrollElement = if Zepto.browser.webkit then document else window + + $(scrollElement).bind 'scroll', -> + return if loading + viewportHeight = document.documentElement.clientHeight + paginationOffset = viewportOffset(pagination) - viewportHeight + + if paginationOffset < viewportHeight/2 + loading = true + $.ajax + method: 'get' + data: + page: ++page + success: (data) -> + container.append data + if page is lastPage + $(scrollElement).unbind 'scroll' + pagination.hide() + loading = false diff --git a/app/assets/javascripts/touch_nohover.coffee b/app/assets/javascripts/touch_nohover.coffee new file mode 100644 index 0000000..6c35d3e --- /dev/null +++ b/app/assets/javascripts/touch_nohover.coffee @@ -0,0 +1,12 @@ +if 'createTouch' of document + ignore = /:hover\b/ + try + for stylesheet in document.styleSheets + idxs = [] + # detect hover rules + for rule, idx in stylesheet.cssRules + if rule.type is CSSRule.STYLE_RULE and ignore.test(rule.selectorText) + idxs.unshift idx + + # delete hover rules + stylesheet.deleteRule idx for idx in idxs diff --git a/app/assets/javascripts/ujs.coffee b/app/assets/javascripts/ujs.coffee new file mode 100644 index 0000000..5228352 --- /dev/null +++ b/app/assets/javascripts/ujs.coffee @@ -0,0 +1,111 @@ +fire = (el, name, data) -> + event = $.Event(name) + el.trigger(event, data) + not event.defaultPrevented + +handleRemote = (element) -> + return unless fire(element, 'ajax:before') + if element.is('form') + method = element.attr('method') + url = element.attr('action') + data = element.serializeArray() + # memoized value from clicked submit button + # TODO: revisit when Zepto data() method supports JS objects + button = element.get(0)._submitButton + if button + data.push button + element.get(0)._submitButton = null + else + method = element.data('method') + url = element.attr('href') + data = element.data('params') || null + + ajaxOptions = + type: method || 'GET' + data: data + headers: + Accept: '*/*;q=0.5, ' + $.ajaxSettings.accepts.script + beforeSend: (xhr, settings) -> + element.trigger('ajax:beforeSend', [xhr, settings]) + success: (data, status, xhr) -> + element.trigger('ajax:success', [data, status, xhr]) + complete: (xhr, status) -> + element.trigger('ajax:complete', [xhr, status]) + error: (xhr, status, error) -> + element.trigger('ajax:error', [xhr, status, error]) + + ajaxOptions.url = url if url + + token = $('meta[name="csrf-token"]').attr('content') + ajaxOptions.headers['X-CSRF-Token'] = token if token + + $.ajax(ajaxOptions) + +handleMethod = (link) -> + href = link.attr('href') + method = link.data('method') + csrf_token = $('meta[name=csrf-token]').attr('content') + csrf_param = $('meta[name=csrf-param]').attr('content') + form = $("
") + hidden = "" + + if csrf_param? and csrf_token? + hidden += "" + + form.hide().append(hidden).appendTo('body') + form.submit() + +disableSelector = 'input[data-disable-with], button[data-disable-with], textarea[data-disable-with]' +enableSelector = 'input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled' + +disableFormElements = (form) -> + form.find(disableSelector).each -> + element = $(this) + method = if element.is('button') then 'html' else 'val' + element.data('enable-with', element[method]()) + element[method](element.data('disable-with')) + element.attr('disabled', 'disabled') + +enableFormElements = (form) -> + form.find(enableSelector).each -> + element = $(this) + method = if element.is('button') then 'html' else 'val' + element[method](element.data('enable-with')) if element.data('enable-with') + element.removeAttr('disabled') + +allowAction = (element) -> + message = element.data('confirm') + not message or confirm(message) + +$(document).delegate 'form[data-remote]', 'submit', (e) -> + element = $(this) + handleRemote element if allowAction element + false + +$(document).delegate 'form', 'ajax:beforeSend', (e) -> + disableFormElements $(this) if this is e.target + +$(document).delegate 'form', 'ajax:complete', (e) -> + enableFormElements $(this) if this is e.target + +submitSelector = 'form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])' + +$(document).delegate submitSelector, 'click', -> + button = $(this) + name = button.attr('name') + data = + if name + name: name + value: button.val() + + # TODO: revisit when Zepto data() method supports JS objects + button.closest('form').get(0)._submitButton = data + +$(document).delegate 'a[data-remote], a[data-method]', 'click', (e) -> + element = $(this) + if allowAction element + if element.data('remote') + handleRemote element + else + handleMethod element + false diff --git a/vendor/assets/javascripts/prototype.js b/vendor/assets/javascripts/prototype.js deleted file mode 100644 index 474b223..0000000 --- a/vendor/assets/javascripts/prototype.js +++ /dev/null @@ -1,6082 +0,0 @@ -/* Prototype JavaScript framework, version 1.7 - * (c) 2005-2010 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://www.prototypejs.org/ - * - *--------------------------------------------------------------------------*/ - -var Prototype = { - - Version: '1.7', - - Browser: (function(){ - var ua = navigator.userAgent; - var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; - return { - IE: !!window.attachEvent && !isOpera, - Opera: isOpera, - WebKit: ua.indexOf('AppleWebKit/') > -1, - Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, - MobileSafari: /Apple.*Mobile/.test(ua) - } - })(), - - BrowserFeatures: { - XPath: !!document.evaluate, - - SelectorsAPI: !!document.querySelector, - - ElementExtensions: (function() { - var constructor = window.Element || window.HTMLElement; - return !!(constructor && constructor.prototype); - })(), - SpecificElementExtensions: (function() { - if (typeof window.HTMLDivElement !== 'undefined') - return true; - - var div = document.createElement('div'), - form = document.createElement('form'), - isSupported = false; - - if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { - isSupported = true; - } - - div = form = null; - - return isSupported; - })() - }, - - ScriptFragment: '