UNPKG

kdf

Version:

KD: a non-document focused UI Framework for web applications.

200 lines (154 loc) 5.99 kB
KDView = require './../../core/view.coffee' KDNotificationView = require './../notifications/notificationview.coffee' module.exports = class KDContentEditableView extends KDView constructor: (options = {}, data) -> options.cssClass = KD.utils.curry "kdcontenteditableview", options.cssClass options.bind = KD.utils.curry "click input paste drop focus blur", options.bind options.type or= "text" options.multiline ?= off options.placeholder or= "" options.tabNavigation ?= no super options, data @getDelegate()?.on "EditingModeToggled", (state) => @setEditingMode state # we shouldn't do per instance # quick hack unf - SY document.addEventListener 'focus', (event)=> @focus() if event.target is @editableElement , yes document.addEventListener 'blur', (event)=> @blur() if event.target is @editableElement , yes @validationNotifications = {} viewAppended: -> @setEditingMode off super getEditableElement: -> unless @editableElement if @getData() @editableElement = @getElement().children[0] else @editableElement = document.createElement "div" @getDomElement().append @editableElement return @editableElement getEditableDomElement: -> @editableDomElement = $ @getEditableElement() unless @editableDomElement return @editableDomElement setEditingMode: (state) -> @editingMode = state @getEditableElement().setAttribute "contenteditable", state if @getValue() is "" if @editingMode and @getOptions().placeholder then @setPlaceholder() else @unsetPlaceholder() getValue: (forceType) -> {type, placeholder} = @getOptions() element = @getEditableElement() type = forceType if forceType switch type when "text" then value = element.textContent when "html" then value = element.innerHTML if value is Encoder.htmlDecode(placeholder) then "" else value.trim() setContent: (content) -> {type} = @getOptions() element = @getEditableElement() if content switch type when "text" then element.textContent = content when "html" then element.innerHTML = content else if @editingMode and content is "" then @setPlaceholder() focus: -> @unsetPlaceholder() if @getValue().length is 0 @getEditableDomElement().trigger 'focus' {windowController} = KD.singletons windowController.addLayer this @setKeyView() @once "ReceivedClickElsewhere", @bound 'blur' unless @focused @focused = yes @getOptions().focus?() blur: -> @focused = no {windowController} = KD.singletons windowController.removeLayer this @unsetKeyView() if @getValue('text').length is 0 @setPlaceholder() else @setContent @getValue() if @getOptions().type isnt 'html' @emit 'BlurHappened' click: => @focus() if @editingMode and not @focused input: (event) => @emit "ValueChanged", event keyDown: (event) => {tabNavigation, multiline, validate} = @getOptions() switch event.which when 9 then KD.utils.stopDOMEvent event if tabNavigation when 13 then KD.utils.stopDOMEvent event switch event.which when 9 # Tab key break unless tabNavigation @blur() if event.shiftKey then @emit "PreviousTabStop" else @emit "NextTabStop" when 13 # Enter key if @getOptions().multiline then @appendNewline() else @emit "EnterPressed" value = @getValue() maxLength = @getOptions().validate?.rules?.maxLength or 0 if event.which is 13 or (maxLength > 0 and value.length == maxLength) event.preventDefault() else if value.length is 0 @unsetPlaceholder() @focus() if event.target isnt @getEditableElement() paste: (event) -> event.preventDefault() text = event.originalEvent.clipboardData.getData "text/plain" document.execCommand "insertText", no, text drop: (event) -> event.preventDefault() text = event.originalEvent.dataTransfer.getData "text/plain" {originalEvent: {clientX, clientY}} = event if @getValue() is "" startOffset = 0 @unsetPlaceholder() {commonAncestorContainer, startOffset, endOffset} = document.caretRangeFromPoint clientX, clientY @utils.replaceRange commonAncestorContainer, text, startOffset setPlaceholder: -> @setClass "placeholder" placeholder = @getOptions().placeholder @setContent placeholder if placeholder unsetPlaceholder: -> @unsetClass "placeholder" content = "" defaultValue = @getOptions().defaultValue value = @getValue() if @editingMode then content = value or "" else content = value or defaultValue or "" element = @getEditableDomElement() element.text "" element.append document.createTextNode content validate: (event) -> valid = yes for own name, rule of @getOptions().validate?.rules or {} validator = KDInputValidator["rule#{name.capitalize()}"] if validator and message = validator @, event valid = no @notify message, title : message type : "mini" cssClass : "error" duration : 2500 break return valid notify: (message, options) -> @validationNotifications[message] = notice = new KDNotificationView options notice.on "KDObjectWillBeDestroyed", => message = notice.getOptions().title delete @validationNotifications[message] appendNewline: -> selection = window.getSelection() count = if selection.baseNode.length is selection.focusOffset then 1 else 0 range = selection.getRangeAt 0 range.insertNode newline = document.createElement "br" for i in [0..count] @utils.selectEnd newline viewAppended: -> super @unsetPlaceholder() if not @editingMode and @getValue().length is 0