Просмотр исходного кода

Fixes #2713 - Knowledge Base does't support animated GIFs and embedded Video (Youtube/Vimeo) content.

Mantas Masalskis 5 лет назад
Родитель
Сommit
0a70711695

+ 7 - 48
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/_rich_text_tool_button.coffee

@@ -5,10 +5,13 @@ class App.UiElement.richtext.additions.RichTextToolButton
   @klass: ->
     # Needs implementation. Return constructor of RichTextToolPopup subclass.
 
+  @pickExisting: (sel, textEditor) ->
+    # needs implementation
+
   @initializeAttributes: {}
 
   @instantiateContent: (event, selection, delegate) ->
-    attrs = @initializeAttributes
+    attrs = $.extend(true, {}, @initializeAttributes)
 
     attrs['event']     = event
     attrs['selection'] = selection
@@ -35,46 +38,6 @@ class App.UiElement.richtext.additions.RichTextToolButton
 
     hash
 
-  @pickLinkInSingleContainer: (elem, containerToLookUpTo) ->
-    if elem.nodeName == 'A'
-      elem
-    else if innerLink = $(elem).find('a')[0]
-      innerLink
-    else if containerToLookUpTo and closestLink = $(elem).closest('a', containerToLookUpTo)[0]
-      closestLink
-    else
-      null
-
-  @pickLinkAt: (elem, container, direction, boundary = null) ->
-    for parent in App.UiElement.richtext.buildParentsListWithSelf(elem, container)
-      if parent.nodeName is 'A'
-        return parent
-
-      for elem in App.UiElement.richtext.allDirectionalSiblings(parent, direction, boundary)
-        if link = @pickLinkInSingleContainer(elem)
-          return link
-
-    null
-
-  @pickLink: (sel, textEditor) ->
-    range = sel.getRangeAt(0)
-
-    if range.startContainer == range.endContainer
-      return @pickLinkInSingleContainer(range.startContainer, textEditor)
-
-    if link = @pickLinkAt(range.startContainer, range.commonAncestorContainer, 1, range.endContainer)
-      return link
-
-    if startParent = App.UiElement.richtext.buildParentsList(range.startContainer, range.commonAncestorContainer).pop()
-      for elem in App.UiElement.richtext.allDirectionalSiblings(startParent, 1, range.endContainer)
-        if link = @pickLinkInSingleContainer(elem)
-          return link
-
-    if link = @pickLinkAt(range.endContainer, range.commonAncestorContainer, -1)
-      return link
-
-    return null
-
   # close other buttons' popovers
   @closeOtherPopovers: (event) ->
     $(event.currentTarget)
@@ -88,15 +51,10 @@ class App.UiElement.richtext.additions.RichTextToolButton
   @selectionSnapshot: (sel) ->
     textEditor = $(event.currentTarget).closest('.richtext.form-control').find('[contenteditable]')
 
-    if sel.isCollapsed and selectedLink = $(sel.anchorNode).closest('a')[0]
-      {
-        type: 'existing'
-        dom:  $(selectedLink)
-      }
-    else if !sel.isCollapsed and selectedLink = @pickLink(sel, textEditor)
+    if selected = @pickExisting(sel, textEditor)
       {
         type: 'existing'
-        dom:  $(selectedLink)
+        dom:  $(selected)
       }
     else if sel.type is 'Range' and $(sel.anchorNode).closest('[contenteditable]', textEditor)[0]
       range = sel.getRangeAt(0)
@@ -117,6 +75,7 @@ class App.UiElement.richtext.additions.RichTextToolButton
         dom:  textEditor
       }
 
+  # on clicking button above rich text area
   @onClick: (event, delegate) ->
     event.stopPropagation()
     event.preventDefault()

+ 46 - 0
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/_rich_text_tool_button_link.coffee

@@ -0,0 +1,46 @@
+class App.UiElement.richtext.additions.RichTextToolButtonLink extends App.UiElement.richtext.additions.RichTextToolButton
+  @pickLinkInSingleContainer: (elem, containerToLookUpTo) ->
+    if elem.nodeName == 'A'
+      elem
+    else if innerLink = $(elem).find('a')[0]
+      innerLink
+    else if containerToLookUpTo and closestLink = $(elem).closest('a', containerToLookUpTo)[0]
+      closestLink
+    else
+      null
+
+  @pickLinkAt: (elem, container, direction, boundary = null) ->
+    for parent in App.UiElement.richtext.buildParentsListWithSelf(elem, container)
+      if parent.nodeName is 'A'
+        return parent
+
+      for elem in App.UiElement.richtext.allDirectionalSiblings(parent, direction, boundary)
+        if link = @pickLinkInSingleContainer(elem)
+          return link
+
+    null
+
+  @pickExisting: (sel, textEditor) ->
+    if sel.isCollapsed and link = $(sel.anchorNode).closest('a')[0]
+      return link
+
+    if sel.isCollapsed
+      return null
+
+    range = sel.getRangeAt(0)
+
+    if range.startContainer == range.endContainer
+      return @pickLinkInSingleContainer(range.startContainer, textEditor)
+
+    if link = @pickLinkAt(range.startContainer, range.commonAncestorContainer, 1, range.endContainer)
+      return link
+
+    if startParent = App.UiElement.richtext.buildParentsList(range.startContainer, range.commonAncestorContainer).pop()
+      for elem in App.UiElement.richtext.allDirectionalSiblings(startParent, 1, range.endContainer)
+        if link = @pickLinkInSingleContainer(elem)
+          return link
+
+    if link = @pickLinkAt(range.endContainer, range.commonAncestorContainer, -1)
+      return link
+
+    return null

+ 18 - 13
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/_rich_text_tool_popup.coffee

@@ -1,7 +1,11 @@
 class App.UiElement.richtext.additions.RichTextToolPopup extends App.ControllerForm
   events:
     'submit form':      'onSubmit'
-    'click .js-unlink': 'onUnlink'
+    'click .js-clear': 'onClear'
+
+  labelNew:      'Link'
+  labelExisting: 'Update'
+  labelClear:    'Remove'
 
   formParams: (params) ->
     # needs implementation
@@ -9,13 +13,13 @@ class App.UiElement.richtext.additions.RichTextToolPopup extends App.ControllerF
   constructor: (params) ->
     if params.selection.type is 'existing'
       url        = params.selection.dom.attr('href')
-      label      = 'Update'
+      label      = @labelExisting
       additional = [{
-        className: 'btn btn--danger js-unlink'
-        text:      'Remove'
+        className: 'btn btn--danger js-clear'
+        text:      @labelClear
       }]
     else
-      label = 'Link'
+      label = @labelNew
 
     defaultParams =
       params: @formParams(params)
@@ -39,16 +43,17 @@ class App.UiElement.richtext.additions.RichTextToolPopup extends App.ControllerF
   getAjaxAttributes: (field, attributes) ->
     @delegate?.getAjaxAttributes?(field, attributes)
 
-  onUnlink: (e) ->
+  onClear: (e) =>
     e.preventDefault()
     e.stopPropagation()
 
-    switch @selection.type
-      when 'existing'
-        $(@selection.dom).contents().unwrap()
+    @clear()
 
     $(@event.currentTarget).popover('hide')
 
+  clear: ->
+    # needs implementation
+
   @wrapElement: (wrapper, selection) ->
     topLevelOriginals = App.UiElement.richtext.buildParentsList(selection.range.startContainer, selection.range.commonAncestorContainer).reverse()
 
@@ -114,15 +119,15 @@ class App.UiElement.richtext.additions.RichTextToolPopup extends App.ControllerF
 
     wrapper.insertAfter(topLevelOriginalStart)
 
-  wrapLink: ->
+  apply: (callback) ->
     # needs implementation
+    callback()
 
   onSubmit: (e) ->
     e.preventDefault()
 
-    @wrapLink()
-
-    $(@event.currentTarget).popover('destroy')
+    @apply =>
+      $(@event.currentTarget).popover('destroy')
 
   didInitialize: ->
     switch @selection.type

+ 63 - 0
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/embed_video_button.coffee

@@ -0,0 +1,63 @@
+# coffeelint: disable=camel_case_classes
+class App.UiElement.richtext.toolButtons.embed_video extends App.UiElement.richtext.additions.RichTextToolButton
+  @icon: 'cloud'
+  @text: 'Video'
+  @klass: -> App.UiElement.richtext.additions.RichTextToolPopupVideo
+  @initializeAttributes:
+    model:
+      configure_attributes: [
+        {
+          name: 'link'
+          display: 'Link'
+          tag: 'input'
+          placeholder: 'Youtube or Vimeo address'
+        }
+      ]
+
+  @pickExisting: (sel, textEditor) ->
+    startNode = null
+    startOffset = null
+
+    endNode = null
+    endOffset = null
+
+    return if !textEditor[0].contains(sel.anchorNode)
+
+    walker = document.createTreeWalker(textEditor[0])
+
+    walker.currentNode = sel.anchorNode
+
+    while !startNode and (walker.currentNode.nodeName == '#text' || walker.currentNode.nodeName == 'SPAN') and walker.currentNode
+      if walker.currentNode instanceof Text
+        offset = walker.currentNode.textContent.indexOf '('
+      if offset? and offset > -1
+        startNode = walker.currentNode
+        startOffset = offset
+
+      walker.previousNode()
+
+    walker.currentNode = sel.anchorNode # back to start
+
+    while !endNode and (walker.currentNode.nodeName == '#text' || walker.currentNode.nodeName == 'SPAN') and walker.currentNode
+      if walker.currentNode instanceof Text
+        offset = walker.currentNode.textContent.indexOf ')'
+      if offset? and offset > -1 and (walker.currentNode != sel.anchorNode || offset > startOffset)
+        endNode = walker.currentNode
+        endOffset = offset + 1
+
+      walker.nextNode()
+
+    if startNode and endNode
+      range = document.createRange()
+      range.setStart(startNode, startOffset)
+      range.setEnd(endNode, endOffset)
+
+      copy = range.cloneContents()
+
+      wrapper = document.createElement('span')
+      wrapper.append(copy)
+
+      range.deleteContents()
+      range.insertNode(wrapper)
+
+      wrapper

+ 18 - 0
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/insert_image_button.coffee

@@ -0,0 +1,18 @@
+# coffeelint: disable=camel_case_classes
+class App.UiElement.richtext.toolButtons.insert_image extends App.UiElement.richtext.additions.RichTextToolButton
+  @icon: 'web'
+  @text: 'Image'
+  @klass: -> App.UiElement.richtext.additions.RichTextToolPopupImage
+  @initializeAttributes:
+    model:
+      configure_attributes: [
+        {
+          name: 'link'
+          display: 'Image'
+          tag: 'input'
+          type: 'file'
+        }
+      ]
+
+  @pickExisting: (sel, textEditor) ->
+    selectedImage = textEditor.find('img.objectResizingEditorActive')[0]

+ 1 - 1
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/link_answer_button.coffee

@@ -1,5 +1,5 @@
 # coffeelint: disable=camel_case_classes
-class App.UiElement.richtext.toolButtons.link_answer extends App.UiElement.richtext.additions.RichTextToolButton
+class App.UiElement.richtext.toolButtons.link_answer extends App.UiElement.richtext.additions.RichTextToolButtonLink
   @icon: 'knowledge-base-answer'
   @text: 'Link Answer'
   @klass: -> App.UiElement.richtext.additions.RichTextToolPopupAnswer

+ 1 - 1
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/link_button.coffee

@@ -1,5 +1,5 @@
 # coffeelint: disable=camel_case_classes
-class App.UiElement.richtext.toolButtons.link extends App.UiElement.richtext.additions.RichTextToolButton
+class App.UiElement.richtext.toolButtons.link extends App.UiElement.richtext.additions.RichTextToolButtonLink
   @icon: 'chain'
   @text: 'Weblink'
   @klass: -> App.UiElement.richtext.additions.RichTextToolPopupLink

+ 8 - 1
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/popup_answer.coffee

@@ -18,7 +18,7 @@ class App.UiElement.richtext.additions.RichTextToolPopupAnswer extends App.UiEle
 
     dom
 
-  wrapLink: ->
+  apply: (callback) ->
     id = @el.find('input').val()
     object = App.KnowledgeBaseAnswerTranslation.find(id)
     textEditor = $(@event.currentTarget).closest('.richtext.form-control').find('[contenteditable]')
@@ -41,3 +41,10 @@ class App.UiElement.richtext.additions.RichTextToolPopupAnswer extends App.UiEle
         @applyOnto(newElem, object)
         placeholder.wrap(newElem)
         placeholder.contents()
+
+    callback()
+
+  clear: ->
+    switch @selection.type
+      when 'existing'
+        $(@selection.dom).contents().unwrap()

+ 58 - 0
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/popup_image.coffee

@@ -0,0 +1,58 @@
+class App.UiElement.richtext.additions.RichTextToolPopupImage extends App.UiElement.richtext.additions.RichTextToolPopup
+  labelNew:      'Insert'
+  labelExisting: 'Replace'
+
+  apply: (callback) ->
+    @el.find('btn--create').attr('disabled', true)
+
+    file = @el.find('input')[0].files[0]
+
+    reader = new FileReader()
+
+    reader.addEventListener('load', =>
+      @insertImage(reader.result)
+      callback()
+    , false)
+
+    reader.readAsDataURL(file)
+
+  applyOnto: (dom, base64) ->
+    dom.attr('src', base64)
+
+  insertImage: (base64) ->
+    textEditor = $(@event.currentTarget).closest('.richtext.form-control').find('[contenteditable]')
+
+    switch @selection.type
+      when 'existing'
+        @applyOnto(@selection.dom, base64)
+      when 'append'
+        newElem = $('<img>')[0]
+        newElem.src = base64
+        newElem.style = 'width: 1000px; max-width: 100%;'
+        @selection.dom.append(newElem)
+      when 'caret'
+        newElem = $('<img>')
+        newElem.attr('src', base64)
+        newElem.attr('style', 'width: 1000px; max-width: 100%;')
+
+        surroundingDom = @selection.dom[0]
+
+        if surroundingDom instanceof Text
+          @selection.dom[0].splitText(@selection.offset)
+
+        newElem.insertAfter(@selection.dom)
+      when 'range'
+        newElem = $('<img>')
+        newElem.attr('src', base64)
+        newElem.attr('style', 'width: 1000px; max-width: 100%;')
+
+        placeholder = textEditor.find('span.highlight-emulator')
+
+        placeholder.empty()
+        placeholder.append(newElem)
+
+  clear: ->
+    switch @selection.type
+      when 'existing'
+        @selection.dom.closest('.enableObjectResizingShim').remove()
+        @selection.dom.remove() # just in case shim was lost while the dialog was open

+ 8 - 1
app/assets/javascripts/app/controllers/_ui_element/richtext_additions/popup_link.coffee

@@ -26,7 +26,7 @@ class App.UiElement.richtext.additions.RichTextToolPopupLink extends App.UiEleme
     else
       input
 
-  wrapLink: ->
+  apply: (callback) ->
     input = @el.find('input').val()
     url = @ensureProtocol(input)
 
@@ -50,3 +50,10 @@ class App.UiElement.richtext.additions.RichTextToolPopupLink extends App.UiEleme
         @applyOnto(newElem, url)
         placeholder.wrap(newElem)
         placeholder.contents()
+
+    callback()
+
+  clear: ->
+    switch @selection.type
+      when 'existing'
+        $(@selection.dom).contents().unwrap()

Некоторые файлы не были показаны из-за большого количества измененных файлов