PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/app/coffeescripts/str/TextHelper.coffee

https://gitlab.com/ykazemi/canvas-lms
CoffeeScript | 139 lines | 90 code | 18 blank | 31 comment | 19 complexity | 4208ae764c77ef6ecbc6f35d8531c8d6 MD5 | raw file
  1. #
  2. # Copyright (C) 2012 Instructure, Inc.
  3. #
  4. # This file is part of Canvas.
  5. #
  6. # Canvas is free software: you can redistribute it and/or modify it under
  7. # the terms of the GNU Affero General Public License as published by the Free
  8. # Software Foundation, version 3 of the License.
  9. #
  10. # Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
  11. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. # A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. # details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License along
  16. # with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #
  18. define [
  19. 'i18n!lib.text_helper'
  20. 'str/htmlEscape'
  21. ], (I18n, htmlEscape) ->
  22. AUTO_LINKIFY_PLACEHOLDER = "LINK-PLACEHOLDER"
  23. AUTO_LINKIFY_REGEX = ///
  24. \b
  25. ( # Capture 1: entire matched URL
  26. (?:
  27. https?:// # http or https protocol
  28. | # or
  29. www\d{0,3}[.] # "www.", "www1.", "www2." "www999."
  30. | # or
  31. [a-z0-9.\-]+[.][a-z]{2,4}/ # looks like domain name followed by a slash
  32. )
  33. (?:
  34. [^\s()<>]+ # Run of non-space, non-()<>
  35. | # or
  36. \([^\s()<>]*\) # balanced parens, single level
  37. )+
  38. (?:
  39. \([^\s()<>]*\) # balanced parens, single level
  40. | # or
  41. [^\s`!()\[\]{};:'".,<>?«»“”‘’] # End with: not a space or one of these punct chars
  42. )
  43. ) | (
  44. LINK-PLACEHOLDER
  45. )
  46. ///gi
  47. th =
  48. quoteClump: (lines) ->
  49. "<div class='quoted_text_holder'>
  50. <a href='#' class='show_quoted_text_link'>#{htmlEscape I18n.t("quoted_text_toggle", "show quoted text")}</a>
  51. <div class='quoted_text' style='display: none;'>
  52. #{$.raw lines.join "\n"}
  53. </div>
  54. </div>"
  55. formatMessage: (message) ->
  56. # replace any links with placeholders so we don't escape them
  57. links = []
  58. placeholderBlocks = []
  59. message = message.replace AUTO_LINKIFY_REGEX, (match, i) ->
  60. placeholderBlocks.push(if match == AUTO_LINKIFY_PLACEHOLDER
  61. AUTO_LINKIFY_PLACEHOLDER
  62. else
  63. link = match
  64. link = "http://" + link unless link[0..6] == 'http://' or link[0..7] == 'https://'
  65. links.push link
  66. "<a href='#{htmlEscape(link)}'>#{htmlEscape(match)}</a>"
  67. )
  68. AUTO_LINKIFY_PLACEHOLDER
  69. # now escape html
  70. message = htmlEscape message
  71. # now put the links back in
  72. message = message.replace new RegExp(AUTO_LINKIFY_PLACEHOLDER, 'g'), (match, i) ->
  73. placeholderBlocks.shift()
  74. # replace newlines
  75. message = message.replace /\n/g, '<br />\n'
  76. # generate quoting clumps
  77. processedLines = []
  78. quoteBlock = []
  79. for line in message.split("\n")
  80. if line.match /^(&gt;|>)/
  81. quoteBlock.push line
  82. else
  83. processedLines.push th.quoteClump(quoteBlock) if quoteBlock.length
  84. quoteBlock = []
  85. processedLines.push line
  86. processedLines.push th.quoteClump(quoteBlock) if quoteBlock.length
  87. message = processedLines.join "\n"
  88. delimit: (number) ->
  89. # only process real numbers
  90. return String(number) if isNaN number
  91. # capture sign and then start working with the absolute value. don't
  92. # process infinities.
  93. sign = if number < 0 then '-' else ''
  94. abs = Math.abs number
  95. return String(number) if abs is Infinity
  96. # break out the integer portion and initialize the result to just the
  97. # decimal (if any)
  98. integer = Math.floor abs
  99. result = if abs == integer then '' else String(abs).replace(/^\d+\./, '.')
  100. # for each comma'd chunk, prepend to the result and remove from integer
  101. while integer >= 1000
  102. mod = String(integer).replace(/\d+(\d\d\d)$/, ',$1')
  103. integer = Math.floor integer / 1000
  104. result = mod + result
  105. # integer is now either in [1, 999], or equal to 0 iff number in (-1, 1).
  106. # prepend it with the sign
  107. sign + String(integer) + result
  108. truncateText: (string, options = {}) ->
  109. max = options.max ? 30
  110. ellipsis = I18n.t('ellipsis', '...')
  111. wordSeparator = I18n.t('word_separator', ' ')
  112. string = (string ? "").replace(/\s+/g, wordSeparator).trim()
  113. return string if not string or string.length <= max
  114. truncateAt = 0
  115. while true
  116. pos = string.indexOf(wordSeparator, truncateAt + 1)
  117. break if pos < 0 || pos > max - ellipsis.length
  118. truncateAt = pos
  119. truncateAt or= max - ellipsis.length # first word > max, so we cut it
  120. string.substring(0, truncateAt) + ellipsis