PageRenderTime 50ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/src/quill.coffee

https://github.com/alarie/quill
CoffeeScript | 216 lines | 176 code | 35 blank | 5 comment | 12 complexity | 0a02e94522011abac242c636b0652a0e MD5 | raw file
Possible License(s): BSD-3-Clause
  1. _ = require('lodash')
  2. _.str = require('underscore.string')
  3. pkg = require('../package.json')
  4. EventEmitter2 = require('eventemitter2').EventEmitter2
  5. DOM = require('./dom')
  6. Editor = require('./editor')
  7. Format = require('./format')
  8. Range = require('./lib/range')
  9. Tandem = require('tandem-core')
  10. Modules =
  11. Authorship : require('./modules/authorship')
  12. ImageTooltip : require('./modules/image-tooltip')
  13. Keyboard : require('./modules/keyboard')
  14. LinkTooltip : require('./modules/link-tooltip')
  15. MultiCursor : require('./modules/multi-cursor')
  16. PasteManager : require('./modules/paste-manager')
  17. Toolbar : require('./modules/toolbar')
  18. UndoManager : require('./modules/undo-manager')
  19. Themes =
  20. Default : require('./themes/default')
  21. Snow : require('./themes/snow')
  22. class Quill extends EventEmitter2
  23. @version: pkg.version
  24. @editors: []
  25. @Module: Modules
  26. @Theme: Themes
  27. @DEFAULTS:
  28. formats: ['align', 'bold', 'italic', 'strike', 'underline', 'color', 'background', 'font', 'size', 'link', 'image', 'bullet', 'list']
  29. modules:
  30. 'keyboard': true
  31. 'paste-manager': true
  32. 'undo-manager': true
  33. pollInterval: 100
  34. readOnly: false
  35. theme: 'default'
  36. @events:
  37. MODULE_INIT : 'module-init'
  38. POST_EVENT : 'post-event'
  39. PRE_EVENT : 'pre-event'
  40. SELECTION_CHANGE : 'selection-change'
  41. TEXT_CHANGE : 'text-change'
  42. @sources:
  43. API : 'api'
  44. SILENT : 'silent'
  45. USER : 'user'
  46. constructor: (container, options = {}) ->
  47. container = document.querySelector(container) if _.isString(container)
  48. throw new Error('Invalid Quill container') unless container?
  49. moduleOptions = _.defaults(options.modules or {}, Quill.DEFAULTS.modules)
  50. html = container.innerHTML
  51. @options = _.defaults(options, Quill.DEFAULTS)
  52. @options.modules = moduleOptions
  53. @options.id = @id = "quill-#{Quill.editors.length + 1}"
  54. @options.emitter = this
  55. @modules = {}
  56. @editor = new Editor(container, this, @options)
  57. @root = @editor.doc.root
  58. Quill.editors.push(this)
  59. this.setHTML(html, Quill.sources.SILENT)
  60. themeClass = _.str.capitalize(_.str.camelize(@options.theme))
  61. @theme = new Quill.Theme[themeClass](this, @options)
  62. _.each(@options.modules, (option, name) =>
  63. this.addModule(name, option)
  64. )
  65. addContainer: (className, before = false) ->
  66. @editor.renderer.addContainer(className, before)
  67. addFormat: (name, format) ->
  68. @editor.doc.addFormat(name, format)
  69. addModule: (name, options) ->
  70. className = _.str.capitalize(_.str.camelize(name))
  71. moduleClass = Quill.Module[className]
  72. throw new Error("Cannot load #{name} module. Are you sure you included it?") unless moduleClass?
  73. options = {} unless _.isObject(options) # Allow for addModule('module', true)
  74. options = _.defaults(options, @theme.constructor.OPTIONS[name] or {}, moduleClass.DEFAULTS or {})
  75. @modules[name] = new moduleClass(this, options)
  76. this.emit(Quill.events.MODULE_INIT, name, @modules[name])
  77. return @modules[name]
  78. addStyles: (styles) ->
  79. @editor.renderer.addStyles(styles)
  80. deleteText: (start, end, source = Quill.sources.API) ->
  81. [start, end, formats, source] = this._buildParams(start, end, {}, source)
  82. return unless end > start
  83. delta = Tandem.Delta.makeDeleteDelta(this.getLength(), start, end - start)
  84. @editor.applyDelta(delta, source)
  85. emit: (eventName, args...) ->
  86. super(Quill.events.PRE_EVENT, eventName, args...)
  87. super(eventName, args...)
  88. super(Quill.events.POST_EVENT, eventName, args...)
  89. focus: ->
  90. @root.focus()
  91. formatLine: (start, end, name, value, source) ->
  92. [start, end, formats, source] = this._buildParams(start, end, name, value, source)
  93. [line, offset] = @editor.doc.findLineAt(end)
  94. end += (line.length - offset) if line?
  95. this.formatText(start, end, formats, source)
  96. formatText: (start, end, name, value, source) ->
  97. [start, end, formats, source] = this._buildParams(start, end, name, value, source)
  98. formats = _.reduce(formats, (formats, value, name) =>
  99. format = @editor.doc.formats[name]
  100. # TODO warn if no format
  101. formats[name] = null unless value and value != format.config.default # false will be composed and kept in attributes
  102. return formats
  103. , formats)
  104. delta = Tandem.Delta.makeRetainDelta(this.getLength(), start, end - start, formats)
  105. @editor.applyDelta(delta, source)
  106. getContents: (start = 0, end = null) ->
  107. if _.isObject(start)
  108. end = start.end
  109. start = start.start
  110. else
  111. end = this.getLength() unless end?
  112. ops = @editor.getDelta().getOpsAt(start, end - start)
  113. return new Tandem.Delta(0, ops)
  114. getHTML: ->
  115. return @root.innerHTML
  116. getLength: ->
  117. return @editor.getDelta().endLength
  118. getModule: (name) ->
  119. return @modules[name]
  120. getSelection: ->
  121. @editor.checkUpdate() # Make sure we access getRange with editor in consistent state
  122. return @editor.selection.getRange()
  123. getText: (start = 0, end = null) ->
  124. return _.pluck(this.getContents(start, end).ops, 'value').join('')
  125. insertEmbed: (index, type, url, source) ->
  126. this.insertText(index, DOM.EMBED_TEXT, type, url, source)
  127. insertText: (index, text, name, value, source) ->
  128. [index, end, formats, source] = this._buildParams(index, 0, name, value, source)
  129. return unless text.length > 0
  130. delta = Tandem.Delta.makeInsertDelta(this.getLength(), index, text, formats)
  131. @editor.applyDelta(delta, source)
  132. onModuleLoad: (name, callback) ->
  133. if (@modules[name]) then return callback(@modules[name])
  134. this.on(Quill.events.MODULE_INIT, (moduleName, module) ->
  135. callback(module) if moduleName == name
  136. )
  137. prepareFormat: (name, value) ->
  138. format = @editor.doc.formats[name]
  139. return unless format? # TODO warn
  140. range = this.getSelection()
  141. return unless range?.isCollapsed()
  142. if format.isType(Format.types.LINE)
  143. this.formatLine(range, name, value, Quill.sources.USER)
  144. else
  145. format.prepare(value)
  146. setContents: (delta, source = Quill.sources.API) ->
  147. if _.isArray(delta)
  148. delta =
  149. startLength: this.getLength()
  150. ops: delta
  151. else
  152. delta.startLength = this.getLength()
  153. this.updateContents(delta, source)
  154. setHTML: (html, source = Quill.sources.API) ->
  155. html = "<#{DOM.DEFAULT_BLOCK_TAG}><#{DOM.DEFAULT_BREAK_TAG}></#{DOM.DEFAULT_BLOCK_TAG}>" unless html
  156. @editor.doc.setHTML(html)
  157. @editor.checkUpdate(source)
  158. setSelection: (start, end, source = Quill.sources.API) ->
  159. if _.isNumber(start) and _.isNumber(end)
  160. range = new Range(start, end)
  161. else
  162. range = start
  163. source = end or source
  164. @editor.selection.setRange(range, source)
  165. updateContents: (delta, source = Quill.sources.API) ->
  166. delta = Tandem.Delta.makeDelta(delta)
  167. @editor.applyDelta(delta, source)
  168. # fn(Number start, Number end, String name, String value, String source)
  169. # fn(Number start, Number end, Object formats, String source)
  170. # fn(Object range, String name, String value, String source)
  171. # fn(Object range, Object formats, String source)
  172. _buildParams: (params...) ->
  173. if _.isObject(params[0])
  174. params.splice(0, 1, params[0].start, params[0].end)
  175. if _.isString(params[2])
  176. formats = {}
  177. formats[params[2]] = params[3]
  178. params.splice(2, 2, formats)
  179. params[3] ?= Quill.sources.API
  180. return params
  181. module.exports = Quill