【问题标题】:Micropost character countdown (Rails Tutorial, 2nd Ed, Chapter 10, Exercise 7)Micropost 字符倒计时(Rails 教程,第 2 版,第 10 章,练习 7)
【发布时间】:2012-06-12 22:14:03
【问题描述】:

我在 Rails 教程(第 10 章,练习 7)中尝试使用信息 here 作为基础,并在 StackOverflow 的答案 herehere 的帮助下,尝试了 micropost 字符倒计时。

屏幕上看起来像this,随着接近字数限制,文字逐渐变红,一旦微博超限,发帖按钮失效,完成like so

当前的实现如下:

views/shared/_micropost_form.html.haml

= form_for @micropost do |f|
  = render 'shared/error_messages', object: f.object
  .field= f.text_area :content, placeholder: t('.compose_micropost')
  %span
    .remaining= t('.characters_remaining').html_safe
    .countdown
  = f.submit t('.post'), class: "btn btn-large btn-primary"

assets/javascripts/microposts.js.coffee

updateCountdownAttributes = (toRemove, toAdd = null) ->
  for attr in toRemove
    $(".remaining, .countdown").removeClass attr
  if toAdd
    $(".remaining, .countdown").addClass toAdd
    if toAdd is "overlimit"
      $("input.btn.btn-large.btn-primary").attr("disabled", "true")
    else
      $("input.btn.btn-large.btn-primary").removeAttr("disabled")

updateCountdown = ->
  remaining = 140 - $("#micropost_content").val().length
  toRemove = ["nearlimit", "almostlimit", "overlimit"]
  if remaining > 19
    updateCountdownAttributes(toRemove)
  if remaining < 20
    toAdd = (toRemove.filter (attr) -> attr is "nearlimit").toString()
    updateCountdownAttributes(toRemove, toAdd)
  if remaining < 11
    toAdd = (toRemove.filter (attr) -> attr is "almostlimit").toString()
    updateCountdownAttributes(toRemove, toAdd)
  if remaining < 0
    toAdd = (toRemove.filter (attr) -> attr is "overlimit").toString()
    updateCountdownAttributes(toRemove, toAdd)
  $(".countdown").text remaining

$(document).ready ->
  $(".countdown").text 140
  $("#micropost_content").change updateCountdown
  $("#micropost_content").keyup updateCountdown
  $("#micropost_content").keydown updateCountdown
  $("#micropost_content").keypress updateCountdown

assets/stylesheets/custom.css.scss

...
/* Micropost character countdown */

.remaining, .countdown {
  display: inline;
  color: $grayLight;
  float: right;
}

.overlimit {
  color: $red;
}

.almostlimit {
  color: hsl(360, 57%, 21%);
}

.nearlimit {
  color: $gray;
}

config/locales/en.yml

en:
  ...
  shared:
    ...
    micropost_form:
      compose_micropost: "Compose new micropost..."
      post: "Post"
      characters_remaining: "&nbsp;characters remaining."

从这里,我有两个问题/问题:

首先,如果可能的话,我希望能够对“剩余字符”字符串进行适当的复数。也许是这样的:

views/shared/_micropost_form.html.haml

...
%span
  .remaining= t('.characters_remaining', count: [[.countdown value]]).html_safe
  .countdown
...

config/locales/en.yml

...
micropost_form:
  ...
  characters_remaining: 
    one: "&nbsp;character remaining."
    other: "&nbsp;characters remaining."

但是,我不知道如何检索.countdown div 中的值,以便将其传递给count 参数。我该怎么做?

假设第一个问题可以解决,我也想去掉负数字符,而是将“-2 个字符剩余”改为“2 个字符以上”。也许在视图中使用某种分支逻辑和一些 javascript 将负数更改为正数......?我不确定这里,所以任何帮助将不胜感激。

views/shared/_micropost_form.html.haml

...
%span
  - [[ if .countdown value < 0 ]]
    .remaining= t('.characters_over', 
                  count: [[positive .countdown value]]).html_safe
  - [[ else ]]
    .remaining= t('.characters_remaining', count: [[.countdown value]]).html_safe
  .countdown
...

config/locales/en.yml

...
micropost_form:
  ...
  characters_remaining: 
    one: "&nbsp;character remaining."
    other: "&nbsp;characters remaining."
  characters_over: 
    one: "&nbsp;character over."
    other: "&nbsp;characters over."

【问题讨论】:

    标签: jquery ruby-on-rails-3 internationalization coffeescript railstutorial.org


    【解决方案1】:

    我也在阅读本教程并找到了这篇文章,虽然我喜欢你添加的 CSS 以使其看起来统一(我已将其用作我自己的 :))我认为你的解决方案过于复杂.对我来说,这只是两个变化:js 脚本和将脚本添加到我的视图中。

    我的 JS 文件:character_countdown.js

    function updateCountdown() {
      // 140 characters max
      var left = 140 - jQuery('.micropost_text_area').val().length;
      if(left == 1) {
        var charactersLeft = ' character left.'
      }
      else if(left < 0){
        var charactersLeft = ' characters too many.'
      }
      else{
        var charactersLeft = ' characters left.'
      }
      jQuery('.countdown').text(Math.abs(left) + charactersLeft);
    }
    
    jQuery(document).ready(function($) {
      updateCountdown();
      $('.micropost_text_area').change(updateCountdown);
      $('.micropost_text_area').keyup(updateCountdown);
    });
    

    这是我将其添加到视图中的位置

    <script src="app/assets/javascripts/character_countdown.js"></script>
    <%= form_for(@micropost) do |f| %>
      <%= render 'shared/error_messages', object: f.object %>
    

    请告诉我你的想法:)

    【讨论】:

    • 很高兴看到其他人对此有所了解,所以 +1 :-) 我有一段时间没有查看我的代码了,所以我确信有更好的方法可以做到这一点。对于您的解决方案,我突然想到了两件事:1)似乎没有一个单一的“1 个字符太多”字符串和 2)考虑refactoring your Javascript to be unobtrusive(即不在视图中)。如果您在 Heroku 上部署了此代码,请分享链接!
    • 我有兴趣让 js 不显眼,但如何让脚本标签脱离视图?感谢您提到“1 个字符太多”,我会尽快解决这个问题 :)
    • 您可以通过将您的 javascript 放入资产管道中适当的 coffeescript/js 文件中来将其移出视图。 Here's a quite long but informative way to organize your assets.
    【解决方案2】:

    我已经找到了我认为非常好的两个问题(复数化和消除所有语言环境中的负数)的解决方案,所以我将在这里详细解释它,希望有人会发现它有用。

    如果您想在深入了解细节之前先看看它的外观,可以在my Sample App deployment at Heroku 亲自尝试一下。

    配置

    此解决方案使用i18n-js gem,它是“一个小型库,用于在 Javascript 上提供 Rails I18n 翻译”。这颗宝石很棒,但不幸的是,它不能像我希望的那样与 Heroku 和doesn't seem like it will for the foreseeable future 配合得很好。因此,需要更改以下配置:

    config/application.rb

    # ...
    config.assets.initialize_on_precompile = true
    

    这意味着在每次部署到 Heroku 之前,都需要运行 rake assets:precompile,一旦您确认部署成功,运行 rake assets:clean 以再次开始开发资产。如果这太烦人了,您将需要其他解决方案。

    更新

    如果您在 Heroku 环境中启用 user-env-compile,您可以让 Heroku 预编译您的资产并仍然使用 i18n-js gem。有关如何执行此操作的说明是 here,我认为只要 Heroku 支持该功能,就值得这样做。

    解决办法

    宝石文件

    # ...
    gem 'i18n-js', '2.1.2'
    

    app/assets/javascripts/application.js

    // ...
    //= require i18n
    //= require i18n/translations
    

    由于上面的 Heroku 设置,此时我需要运行

    $ rake i18n:js:setup
    

    将 i18n-js.yml 复制到 config 文件夹。

    app/views/layouts/application.html.haml

    %html
      %head
        # ...
        = render 'layouts/i18n_js'
    

    app/views/layouts/_i18n_js.html.haml

    :javascript
      I18n.defaultLocale = "#{I18n.default_locale}";
      I18n.locale = "#{I18n.locale}";
    

    app/views/shared/_micropost_form.html.haml

    # ...
    .field= f.text_area :content, placeholder: t('.compose_micropost')
    %span.countdown
    = f.submit t('.post'), class: "btn btn-large btn-primary"
    

    app/assets/stylesheets/custom.css.scss

    /* Micropost character countdown */
    
    .countdown {
      display: inline;
      color: $grayLight;
      float: right;
    }
    // ...
    

    app/assets/javascripts/microposts.js.coffee
    (我对 javascript/coffeescript 不太擅长,所以这里可能有改进/重构的空间)

    updateCountdownString = (remaining) ->
      if remaining > 1 or remaining is 0
      $(".countdown").text I18n.t('shared.micropost_form.characters_remaining.other',
                                  count: remaining)
      else if remaining is 1
        $(".countdown").text I18n.t('shared.micropost_form.characters_remaining.one',
                                    count: remaining)
      else if remaining is -1
        $(".countdown").text I18n.t('shared.micropost_form.characters_over.one',
                                    count: -remaining)
      else
        $(".countdown").text I18n.t('shared.micropost_form.characters_over.other',
                                    count: -remaining)
    
    takeFromCollection = (collection, className) ->
      (collection.filter (attr) -> attr is className).toString()
    
    updateCountdownAttributes = (remaining) ->
      toRemove = ["nearlimit", "almostlimit", "overlimit"]
      if remaining < 20
        toAdd = takeFromCollection(toRemove, "nearlimit")
      if remaining < 11
        toAdd = takeFromCollection(toRemove, "almostlimit")
      if remaining < 0
        toAdd = takeFromCollection(toRemove, "overlimit")
    
      if toAdd isnt null
        for attr in toRemove
          $(".countdown").removeClass attr
        $(".countdown").addClass toAdd
      if toAdd is "overlimit"
        $("input.btn.btn-large.btn-primary").attr("disabled", "true")
      else
        $("input.btn.btn-large.btn-primary").removeAttr("disabled")
    
    updateCountdown = ->
      remaining = 140 - $("#micropost_content").val().length
      updateCountdownString(remaining)
      updateCountdownAttributes(remaining)
    
    $(document).ready ->
      $(".countdown").text I18n.t('shared.micropost_form.characters_remaining.other',
                                  count: 140)
      $("#micropost_content").on("change keyup keydown keypress paste drop",
                                 updateCountdown)
    

    config/locales/en.yml(其他语言环境具有相同样式的相同键)

    shared:
      # ...
      micropost_form:
        characters_remaining:
          one: "%{count} character remaining."
          other: "%{count} characters remaining."
        characters_over:
          one: "%{count} character over limit."
          other: "%{count} characters over limit."
    

    【讨论】:

    • 您好,请您使用 jsfiddle,您的 heroku 应用已关闭。
    • @JGonzalezD,晚了,但 Heroku 应用程序又恢复了。
    猜你喜欢
    • 1970-01-01
    • 2012-05-02
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多