3

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

屏幕上是这样的,随着接近字数限制,文字逐渐变红,一旦微博超限,发帖按钮失效,就这样结束了。

当前的实现如下所示:

意见/共享/_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"

资产/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

资产/样式表/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;
}

配置/语言环境/en.yml

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

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

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

意见/共享/_micropost_form.html.haml

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

配置/语言环境/en.yml

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

但是,我不知道如何以.countdown可以将其传递给count参数的方式检索 div 中的值。我怎样才能做到这一点?

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

意见/共享/_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
...

配置/语言环境/en.yml

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

2 回答 2

2

我也在阅读本教程并找到了这篇文章,虽然我喜欢你添加的 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 %>

请让我知道你在想什么 :)

于 2013-03-21T10:17:18.030 回答
1

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

如果您想在深入研究细节之前先看看它是什么样子,您可以在 Heroku 的示例应用程序部署中亲自尝试一下。

配置

该解决方案使用i18n-js gem,它是“一个在 Javascript 上提供 Rails I18n 翻译的小型库”。这颗宝石很棒,但不幸的是,它并没有像我希望的那样与 Heroku 配合得很好,而且在可预见的未来似乎也不会。因此,需要更改以下配置:

配置/应用程序.rb

# ...
config.assets.initialize_on_precompile = true

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

更新

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

解决方案

宝石文件

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

应用程序/资产/javascripts/application.js

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

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

$ rake i18n:js:setup

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

应用程序/视图/布局/application.html.haml

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

应用程序/视图/布局/_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"

应用程序/资产/样式表/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."
于 2012-07-04T16:25:36.023 回答