formagic 0.3.9 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/assets/javascripts/formagic.coffee +5 -2
  4. data/app/assets/javascripts/formagic/form.coffee +4 -1
  5. data/app/assets/javascripts/formagic/inputs/ace-css.coffee +25 -0
  6. data/app/assets/javascripts/formagic/inputs/ace-html.coffee +25 -0
  7. data/app/assets/javascripts/formagic/inputs/ace-js.coffee +25 -0
  8. data/app/assets/javascripts/formagic/inputs/ace-markdown.coffee +51 -0
  9. data/app/assets/javascripts/formagic/inputs/{markdown_toolbar.coffee → ace-markdown_toolbar.coffee} +27 -7
  10. data/app/assets/javascripts/formagic/inputs/{html.coffee → ace.coffee} +27 -29
  11. data/app/assets/javascripts/formagic/inputs/documents_reorder.coffee +3 -0
  12. data/app/assets/javascripts/formagic/inputs/list_reorder.coffee +2 -0
  13. data/app/assets/javascripts/formagic/inputs/url.coffee +1 -1
  14. data/app/assets/javascripts/vendor/ace.js +264 -123
  15. data/app/assets/javascripts/vendor/mode-css.js +1008 -0
  16. data/app/assets/javascripts/vendor/mode-html.js +488 -129
  17. data/app/assets/javascripts/vendor/mode-javascript.js +1154 -0
  18. data/app/assets/javascripts/vendor/mode-markdown.js +489 -129
  19. data/app/assets/javascripts/vendor/slip.js +792 -0
  20. data/app/assets/stylesheets/formagic.scss +9 -1
  21. data/app/assets/stylesheets/formagic/{nested-form.scss → documents.scss} +0 -0
  22. data/app/assets/stylesheets/formagic/markdown.scss +4 -1
  23. data/app/assets/stylesheets/formagic/switch.scss +1 -1
  24. data/lib/formagic/version.rb +1 -1
  25. metadata +12 -6
  26. data/app/assets/javascripts/formagic/inputs/markdown.coffee +0 -94
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79015f55a3f1cfacca4bee34191aa33b1fb3f745
4
- data.tar.gz: a76c54dbe60f720d3dcb4cd91d1e3bb8cf005767
3
+ metadata.gz: 6c17147c1c2a4a84bee088722eea1cb2d27622fb
4
+ data.tar.gz: 6dcc25eaed38bdc251b3837e2eb088b08a38d105
5
5
  SHA512:
6
- metadata.gz: 5a1dfef367302b2b09eef3e03d463ba029ffd355663ef8647e34e7f8e7d5ce184c81170286608143144cec3d83b24a2e185e3d8a788f3bbc9404091513f094b2
7
- data.tar.gz: a3d522aafd769bd9bd9670ada5b00597ef4c4ed460b0eb3dc49e596b93afbaeb8ec513469c1f97ad1cf38223978c1520701d3f592e2ae09348472ca060a72d1a
6
+ metadata.gz: 40fca5873df0a180ffe38b1cc7329f5cb06d1070d4b1fe40de5a833030ff50a6d136fd2213588284ba8b62829adae27d892d06f2c140cab510b8f251f5bbe8d8
7
+ data.tar.gz: d3ecd7856db1be847f9cae39f56616c07d324618d207cc4743a4a9f6fded67aec181938c92e22e7f98d8c4fe952e3f5385005e827a569692bff8b9bb89d0fc61
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- formagic (0.3.9)
4
+ formagic (0.3.10)
5
5
  bourbon (>= 3.2)
6
6
  normalize-rails (>= 3.0)
7
7
 
@@ -26,8 +26,11 @@
26
26
 
27
27
  ## OPTIONAL
28
28
  # require ./formagic/inputs/redactor
29
- # require ./formagic/inputs/html
30
- # require ./formagic/inputs/markdown
29
+ # require ./formagic/inputs/ace-html
30
+ # require ./formagic/inputs/ace-css
31
+ # require ./formagic/inputs/ace-js
32
+ # require ./formagic/inputs/ace-coffee
33
+ # require ./formagic/inputs/ace-markdown
31
34
 
32
35
  @Icons ?= {}
33
36
  @Icons.reorderDocuments = "<i class='fa fa-ellipsis-v'></i>"
@@ -83,7 +83,10 @@ class @Form
83
83
  if groupConfig.inputs
84
84
  @_build_schema(groupConfig.inputs, $group)
85
85
 
86
- group = { $el: $group, klassName: klassName, onInitialize: groupConfig.onInitialize }
86
+ group =
87
+ $el: $group
88
+ klassName: klassName
89
+ onInitialize: groupConfig.onInitialize
87
90
  @groups.push group
88
91
 
89
92
  return group
@@ -0,0 +1,25 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ # -----------------------------------------------------------------------------
5
+ # INPUT CSS
6
+ # -----------------------------------------------------------------------------
7
+ # Config options:
8
+ # label - Input label
9
+ # pluginConfig - Custom options for overriding default ones
10
+ #
11
+ # Input config example:
12
+ # css_field: { type: 'css', label: 'Styles' }
13
+ #
14
+ # Dependencies:
15
+ #= require ./ace
16
+ #= require vendor/mode-css
17
+ # -----------------------------------------------------------------------------
18
+ class @InputCss extends InputAce
19
+
20
+ # PRIVATE ===================================================================
21
+
22
+ _set_mode: ->
23
+ @session.setMode("ace/mode/css")
24
+
25
+ chr.formInputs['css'] = InputCss
@@ -0,0 +1,25 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ # -----------------------------------------------------------------------------
5
+ # INPUT HTML
6
+ # -----------------------------------------------------------------------------
7
+ # Config options:
8
+ # label - Input label
9
+ # pluginConfig - Custom options for overriding default ones
10
+ #
11
+ # Input config example:
12
+ # body_html: { type: 'html', label: 'Article' }
13
+ #
14
+ # Dependencies:
15
+ #= require ./ace
16
+ #= require vendor/mode-html
17
+ # -----------------------------------------------------------------------------
18
+ class @InputHtml extends InputAce
19
+
20
+ # PRIVATE ===================================================================
21
+
22
+ _set_mode: ->
23
+ @session.setMode("ace/mode/html")
24
+
25
+ chr.formInputs['html'] = InputHtml
@@ -0,0 +1,25 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ # -----------------------------------------------------------------------------
5
+ # INPUT JS
6
+ # -----------------------------------------------------------------------------
7
+ # Config options:
8
+ # label - Input label
9
+ # pluginConfig - Custom options for overriding default ones
10
+ #
11
+ # Input config example:
12
+ # js_field: { type: 'js', label: 'JavaScript' }
13
+ #
14
+ # Dependencies:
15
+ #= require ./ace
16
+ #= require vendor/mode-javascript
17
+ # -----------------------------------------------------------------------------
18
+ class @InputJs extends InputAce
19
+
20
+ # PRIVATE ===================================================================
21
+
22
+ _set_mode: ->
23
+ @session.setMode("ace/mode/javascript")
24
+
25
+ chr.formInputs['js'] = InputJs
@@ -0,0 +1,51 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Author: Alexander Kravets <alex@slatestudio.com>,
3
+ # Slate Studio (http://www.slatestudio.com)
4
+ # -----------------------------------------------------------------------------
5
+ # INPUT MARKDOWN
6
+ # -----------------------------------------------------------------------------
7
+ # Markdown input supports syntax highlighting and optional compilation to html.
8
+ #
9
+ # Config options:
10
+ # label - Input label
11
+ # pluginConfig - Custom options for overriding default ones
12
+ # getHtmlInput - return input so store generated HTML content
13
+ # disableToolbar - Do not show shorcuts panel
14
+ #
15
+ # Input config example:
16
+ # body_md:
17
+ # type: 'markdown'
18
+ # label: 'Article'
19
+ # getHtmlInput: -> chr.module.view.form.inputs.body_html
20
+ #
21
+ # Dependencies:
22
+ #= require ./ace
23
+ #= require vendor/marked
24
+ #= require vendor/ace
25
+ #= require vendor/mode-markdown
26
+ #= require ./ace-markdown_toolbar
27
+ # -----------------------------------------------------------------------------
28
+ class @InputMarkdown extends InputAce
29
+ # PRIVATE ===================================================================
30
+
31
+ _before_initialize: ->
32
+ @config.imageSize ||= "large"
33
+ if ! @config.disableToolbar
34
+ @_add_toolbar()
35
+
36
+ _update_inputs: ->
37
+ markdown = @session.getValue()
38
+ @$input.val(markdown)
39
+ @$input.trigger('change')
40
+
41
+ if @config.getHtmlInput
42
+ html = marked(markdown)
43
+ input = @config.getHtmlInput()
44
+ input.updateValue(html)
45
+
46
+ _set_mode: ->
47
+ @session.setMode("ace/mode/markdown")
48
+
49
+ include(InputMarkdown, inputMarkdownToolbar)
50
+
51
+ chr.formInputs['markdown'] = InputMarkdown
@@ -15,6 +15,9 @@ class @InputMarkdownToolbar
15
15
 
16
16
  # PRIVATE ===================================================================
17
17
 
18
+ _is_visible: ->
19
+ @$el.is(":visible")
20
+
18
21
  _bind_window_scroll: ->
19
22
  @$window =$ ".content:visible"
20
23
  @$window.on "scroll", => @_check_offset()
@@ -32,9 +35,8 @@ class @InputMarkdownToolbar
32
35
  if isBelowAceTop && isAboveAceBottom then @_fix() else @_unfix()
33
36
 
34
37
  _fix: ->
35
- if @isFixed
36
- return
37
- # some legacy workaround for mobile:
38
+ if @isFixed || ! @_is_visible() then return
39
+ # TODO: make this work on mobile ...
38
40
  # webkit does not recalc top: 0 when focused on contenteditable
39
41
  # if chr.isMobile() && @isFocused
40
42
  # @$el.css
@@ -51,7 +53,7 @@ class @InputMarkdownToolbar
51
53
  @isFixed = true
52
54
 
53
55
  _unfix: ->
54
- if ! @isFixed then return
56
+ if ! @isFixed || ! @_is_visible() then return
55
57
 
56
58
  @$ace = @input.$editor
57
59
  @$el.css
@@ -72,6 +74,7 @@ class @InputMarkdownToolbar
72
74
  @buttons[title] = $btn
73
75
 
74
76
  @inputMarkdownToolbar =
77
+
75
78
  # PRIVATE ===================================================================
76
79
 
77
80
  _add_toolbar: ->
@@ -80,6 +83,7 @@ class @InputMarkdownToolbar
80
83
 
81
84
  @toolbar.addButton "Link", $.proxy(@_insert_link, this)
82
85
  @toolbar.addButton "Image", $.proxy(@_insert_images, this)
86
+ @toolbar.addButton "File", $.proxy(@_insert_files, this)
83
87
 
84
88
  _insert_link: (editor) ->
85
89
  url = prompt("URL", "")
@@ -90,7 +94,23 @@ class @InputMarkdownToolbar
90
94
  editor.focus()
91
95
 
92
96
  _insert_images: (editor) ->
93
- chr.modules.loft.showModal "images", true, (objects) ->
97
+ # TODO: add workaround when loft is not available
98
+ onAccept = (objects) =>
94
99
  for image in objects
95
- editor.insert "![#{image.name}](#{image.file.url})\n"
96
- editor.focus()
100
+ name = image.name
101
+ url = image.file[@config.imageSize].url
102
+ editor.insert "![#{name}](#{url})\n"
103
+ editor.focus()
104
+ onCancel = -> editor.focus()
105
+ chr.modules.loft.showImages true, onAccept, onCancel
106
+
107
+ _insert_files: (editor) ->
108
+ # TODO: add workaround when loft is not available
109
+ onAccept = (objects) =>
110
+ for file in objects
111
+ name = file.name
112
+ url = file.file.url
113
+ editor.insert "[#{name}](#{url})\n"
114
+ editor.focus()
115
+ onCancel = -> editor.focus()
116
+ chr.modules.loft.showDocuments true, onAccept, onCancel
@@ -2,20 +2,12 @@
2
2
  # Author: Alexander Kravets <alex@slatestudio.com>,
3
3
  # Slate Studio (http://www.slatestudio.com)
4
4
  # -----------------------------------------------------------------------------
5
- # INPUT HTML
5
+ # ABSTRACT ACE EDITOR
6
6
  # -----------------------------------------------------------------------------
7
- # Config options:
8
- # label - Input label
9
- # aceOptions - Custom options for overriding default ones
10
- #
11
- # Input config example:
12
- # body_html: { type: 'html', label: 'Article' }
13
- #
14
7
  # Dependencies:
15
8
  #= require vendor/ace
16
- #= require vendor/mode-html
17
9
  # -----------------------------------------------------------------------------
18
- class @InputHtml extends InputString
10
+ class @InputAce extends InputString
19
11
 
20
12
  # PRIVATE ===================================================================
21
13
 
@@ -23,17 +15,32 @@ class @InputHtml extends InputString
23
15
  @$input =$ "<input type='hidden' name='#{ @name }' value='#{ @_safe_value() }' />"
24
16
  @$el.append @$input
25
17
 
26
- @$editor =$ "<div></div>"
18
+ @$editor =$ "<div>"
27
19
  @$el.append @$editor
28
20
 
29
21
  _update_inputs: ->
30
- @value = @editor.getSession().getValue()
22
+ @value = @session.getValue()
31
23
  @$input.val(@value)
32
- @$input.trigger('change')
24
+ @$input.trigger("change")
25
+
26
+ _set_mode: ->
27
+
28
+ # ace options: https://github.com/ajaxorg/ace/wiki/Configuring-Ace
29
+ _default_options: ->
30
+ autoScrollEditorIntoView: true
31
+ minLines: 8
32
+ maxLines: Infinity
33
+ showLineNumbers: false
34
+ showGutter: false
35
+ highlightActiveLine: false
36
+ showPrintMargin: false
37
+ tabSize: 2
33
38
 
34
39
  # PUBLIC ====================================================================
35
40
 
36
41
  initialize: ->
42
+ @_before_initialize?()
43
+ @config.pluginConfig ||= {}
37
44
  @config.beforeInitialize?(this)
38
45
 
39
46
  @editor = ace.edit(@$editor.get(0))
@@ -43,24 +50,15 @@ class @InputHtml extends InputString
43
50
  @session.setUseWorker(false)
44
51
  @session.setValue(@$input.val())
45
52
  @session.setUseWrapMode(true)
46
- @session.setMode("ace/mode/html")
47
-
48
- # ace options: https://github.com/ajaxorg/ace/wiki/Configuring-Ace
49
- @editor.setOptions
50
- autoScrollEditorIntoView: true
51
- minLines: 5
52
- maxLines: Infinity
53
- showLineNumbers: false
54
- showGutter: false
55
- highlightActiveLine: false
56
- showPrintMargin: false
53
+ @_set_mode()
57
54
 
58
- @session.on 'change', (e) => @_update_inputs()
55
+ aceOptions = @_default_options()
56
+ $.merge(aceOptions, @config.pluginConfig)
57
+ @editor.setOptions(aceOptions)
59
58
 
59
+ @session.on "change", (e) => @_update_inputs()
60
+ @_after_initialize?()
60
61
  @config.onInitialize?(this)
61
62
 
62
63
  updateValue: (@value) ->
63
- @editor.getSession().setValue(@value)
64
- @$input.val(@value)
65
-
66
- chr.formInputs['html'] = InputHtml
64
+ @session.setValue(@value)
@@ -4,6 +4,9 @@
4
4
  # -----------------------------------------------------------------------------
5
5
  # INPUT "NESTED" FORM REORDER
6
6
  # -----------------------------------------------------------------------------
7
+ # Dependencies:
8
+ #= require vendor/slip
9
+ # -----------------------------------------------------------------------------
7
10
  @inputFormReorder =
8
11
  # PRIVATE ===================================================================
9
12
 
@@ -3,6 +3,8 @@
3
3
  # Slate Studio (http://www.slatestudio.com)
4
4
  # -----------------------------------------------------------------------------
5
5
  # INPUT LIST REORDER
6
+ # Dependencies:
7
+ #= require vendor/slip
6
8
  # -----------------------------------------------------------------------------
7
9
  @inputListReorder =
8
10
  # PRIVATE ===================================================================
@@ -15,7 +15,7 @@ class @InputUrl extends InputString
15
15
  @$actions.append @$chooseBtn
16
16
 
17
17
  @$chooseBtn.on 'click', (e) =>
18
- chr.modules.loft.showModal 'all', false, (objects) =>
18
+ chr.modules.loft.showAll false, (objects) =>
19
19
  url = objects[0].file.url
20
20
  @updateValue(url)
21
21
 
@@ -960,7 +960,7 @@ exports.getDocumentHead = function(doc) {
960
960
  if (!doc)
961
961
  doc = document;
962
962
  return doc.head || doc.getElementsByTagName("head")[0] || doc.documentElement;
963
- }
963
+ };
964
964
 
965
965
  exports.createElement = function(tag, ns) {
966
966
  return document.createElementNS ?
@@ -999,7 +999,7 @@ exports.toggleCssClass = function(el, name) {
999
999
  add = false;
1000
1000
  classes.splice(index, 1);
1001
1001
  }
1002
- if(add)
1002
+ if (add)
1003
1003
  classes.push(name);
1004
1004
 
1005
1005
  el.className = classes.join(" ");
@@ -1044,10 +1044,7 @@ exports.importCssString = function importCssString(cssText, id, doc) {
1044
1044
  if (id)
1045
1045
  style.owningElement.id = id;
1046
1046
  } else {
1047
- style = doc.createElementNS
1048
- ? doc.createElementNS(XHTML_NS, "style")
1049
- : doc.createElement("style");
1050
-
1047
+ style = exports.createElement("style");
1051
1048
  style.appendChild(doc.createTextNode(cssText));
1052
1049
  if (id)
1053
1050
  style.id = id;
@@ -1287,7 +1284,7 @@ var Keys = (function() {
1287
1284
  80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
1288
1285
  87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
1289
1286
  186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`',
1290
- 219: '[', 220: '\\',221: ']', 222: '\''
1287
+ 219: '[', 220: '\\',221: ']', 222: "'", 111: '/', 106: '*'
1291
1288
  }
1292
1289
  };
1293
1290
  var name, i;
@@ -1385,6 +1382,9 @@ define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/use
1385
1382
  var keys = require("./keys");
1386
1383
  var useragent = require("./useragent");
1387
1384
 
1385
+ var pressedKeys = null;
1386
+ var ts = 0;
1387
+
1388
1388
  exports.addListener = function(elem, type, callback) {
1389
1389
  if (elem.addEventListener) {
1390
1390
  return elem.addEventListener(type, callback, false);
@@ -1593,7 +1593,7 @@ function normalizeCommandKeys(callback, e, keyCode) {
1593
1593
  var hashId = getModifierHash(e);
1594
1594
 
1595
1595
  if (!useragent.isMac && pressedKeys) {
1596
- if (pressedKeys[91] || pressedKeys[92])
1596
+ if (pressedKeys.OSKey)
1597
1597
  hashId |= 8;
1598
1598
  if (pressedKeys.altGr) {
1599
1599
  if ((3 & hashId) != 3)
@@ -1617,8 +1617,7 @@ function normalizeCommandKeys(callback, e, keyCode) {
1617
1617
  if (keyCode in keys.MODIFIER_KEYS) {
1618
1618
  keyCode = -1;
1619
1619
  }
1620
-
1621
- if (hashId & 8 && (keyCode === 91 || keyCode === 93)) {
1620
+ if (hashId & 8 && (keyCode >= 91 && keyCode <= 93)) {
1622
1621
  keyCode = -1;
1623
1622
  }
1624
1623
 
@@ -1645,8 +1644,7 @@ function normalizeCommandKeys(callback, e, keyCode) {
1645
1644
  return callback(e, hashId, keyCode);
1646
1645
  }
1647
1646
 
1648
- var pressedKeys = null;
1649
- var ts = 0;
1647
+
1650
1648
  exports.addCommandKeyListener = function(el, callback) {
1651
1649
  var addListener = exports.addListener;
1652
1650
  if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) {
@@ -1661,8 +1659,18 @@ exports.addCommandKeyListener = function(el, callback) {
1661
1659
  var lastDefaultPrevented = null;
1662
1660
 
1663
1661
  addListener(el, "keydown", function(e) {
1664
- pressedKeys[e.keyCode] = (pressedKeys[e.keyCode] || 0) + 1;
1665
- var result = normalizeCommandKeys(callback, e, e.keyCode);
1662
+ var keyCode = e.keyCode;
1663
+ pressedKeys[keyCode] = (pressedKeys[keyCode] || 0) + 1;
1664
+ if (keyCode == 91 || keyCode == 92) {
1665
+ pressedKeys.OSKey = true;
1666
+ } else if (pressedKeys.OSKey) {
1667
+ if (e.timeStamp - pressedKeys.lastT > 200 && pressedKeys.count == 1)
1668
+ resetPressedKeys();
1669
+ }
1670
+ if (pressedKeys[keyCode] == 1)
1671
+ pressedKeys.count++;
1672
+ pressedKeys.lastT = e.timeStamp;
1673
+ var result = normalizeCommandKeys(callback, e, keyCode);
1666
1674
  lastDefaultPrevented = e.defaultPrevented;
1667
1675
  return result;
1668
1676
  });
@@ -1675,7 +1683,16 @@ exports.addCommandKeyListener = function(el, callback) {
1675
1683
  });
1676
1684
 
1677
1685
  addListener(el, "keyup", function(e) {
1678
- pressedKeys[e.keyCode] = null;
1686
+ var keyCode = e.keyCode;
1687
+ if (!pressedKeys[keyCode]) {
1688
+ resetPressedKeys();
1689
+ } else {
1690
+ pressedKeys.count = Math.max(pressedKeys.count - 1, 0);
1691
+ }
1692
+ if (keyCode == 91 || keyCode == 92) {
1693
+ pressedKeys.OSKey = false;
1694
+ }
1695
+ pressedKeys[keyCode] = null;
1679
1696
  });
1680
1697
 
1681
1698
  if (!pressedKeys) {
@@ -1684,8 +1701,10 @@ exports.addCommandKeyListener = function(el, callback) {
1684
1701
  }
1685
1702
  }
1686
1703
  };
1687
- function resetPressedKeys(e) {
1704
+ function resetPressedKeys() {
1688
1705
  pressedKeys = Object.create(null);
1706
+ pressedKeys.count = 0;
1707
+ pressedKeys.lastT = 0;
1689
1708
  }
1690
1709
 
1691
1710
  if (typeof window == "object" && window.postMessage && !useragent.isOldIE) {
@@ -2749,7 +2768,7 @@ function GutterHandler(mouseHandler) {
2749
2768
  if (mouseHandler.$tooltipFollowsMouse) {
2750
2769
  moveTooltip(mouseEvent);
2751
2770
  } else {
2752
- var gutterElement = gutter.$cells[editor.session.documentToScreenRow(row, 0)].element;
2771
+ var gutterElement = mouseEvent.domEvent.target;
2753
2772
  var rect = gutterElement.getBoundingClientRect();
2754
2773
  var style = tooltip.getElement().style;
2755
2774
  style.left = rect.right + "px";
@@ -3766,6 +3785,8 @@ var MouseHandler = function(editor) {
3766
3785
  if (!document.hasFocus || !document.hasFocus())
3767
3786
  window.focus();
3768
3787
  editor.focus();
3788
+ if (!editor.isFocused())
3789
+ window.focus();
3769
3790
  };
3770
3791
 
3771
3792
  var mouseTarget = editor.renderer.getMouseEventTarget();
@@ -4067,7 +4088,7 @@ var KeyBinding = function(editor) {
4067
4088
  if (toExecute.command == "null") {
4068
4089
  success = true;
4069
4090
  } else {
4070
- success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
4091
+ success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
4071
4092
  }
4072
4093
  if (success && e && hashId != -1 &&
4073
4094
  toExecute.passEvent != true && toExecute.command.passEvent != true
@@ -4077,6 +4098,15 @@ var KeyBinding = function(editor) {
4077
4098
  if (success)
4078
4099
  break;
4079
4100
  }
4101
+
4102
+ if (!success && hashId == -1) {
4103
+ toExecute = {command: "insertstring"};
4104
+ success = commands.exec("insertstring", this.$editor, keyString);
4105
+ }
4106
+
4107
+ if (success)
4108
+ this.$editor._signal("keyboardActivity", toExecute);
4109
+
4080
4110
  return success;
4081
4111
  };
4082
4112
 
@@ -4086,9 +4116,7 @@ var KeyBinding = function(editor) {
4086
4116
  };
4087
4117
 
4088
4118
  this.onTextInput = function(text) {
4089
- var success = this.$callKeyboardHandlers(-1, text);
4090
- if (!success)
4091
- this.$editor.commands.exec("insertstring", this.$editor, text);
4119
+ this.$callKeyboardHandlers(-1, text);
4092
4120
  };
4093
4121
 
4094
4122
  }).call(KeyBinding.prototype);
@@ -4827,8 +4855,10 @@ var Selection = function(session) {
4827
4855
  var docPos = this.session.screenToDocumentPosition(screenPos.row + rows, screenPos.column);
4828
4856
 
4829
4857
  if (rows !== 0 && chars === 0 && docPos.row === this.lead.row && docPos.column === this.lead.column) {
4830
- if (this.session.lineWidgets && this.session.lineWidgets[docPos.row])
4831
- docPos.row++;
4858
+ if (this.session.lineWidgets && this.session.lineWidgets[docPos.row]) {
4859
+ if (docPos.row > 0 || rows > 0)
4860
+ docPos.row++;
4861
+ }
4832
4862
  }
4833
4863
  this.moveCursorTo(docPos.row, docPos.column + chars, chars === 0);
4834
4864
  };
@@ -5108,6 +5138,9 @@ var Tokenizer = function(rules) {
5108
5138
  if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
5109
5139
  src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
5110
5140
  }
5141
+ if (src.charAt(0) != "^") src = "^" + src;
5142
+ if (src.charAt(src.length - 1) != "$") src += "$";
5143
+
5111
5144
  return new RegExp(src, (flag||"").replace("g", ""));
5112
5145
  };
5113
5146
  this.getLineTokens = function(line, startState) {
@@ -5280,13 +5313,12 @@ var TextHighlightRules = function() {
5280
5313
  for (var i = 0; i < state.length; i++) {
5281
5314
  var rule = state[i];
5282
5315
  if (rule.next || rule.onMatch) {
5283
- if (typeof rule.next != "string") {
5284
- if (rule.nextState && rule.nextState.indexOf(prefix) !== 0)
5285
- rule.nextState = prefix + rule.nextState;
5286
- } else {
5316
+ if (typeof rule.next == "string") {
5287
5317
  if (rule.next.indexOf(prefix) !== 0)
5288
5318
  rule.next = prefix + rule.next;
5289
5319
  }
5320
+ if (rule.nextState && rule.nextState.indexOf(prefix) !== 0)
5321
+ rule.nextState = prefix + rule.nextState;
5290
5322
  }
5291
5323
  }
5292
5324
  this.$rules[prefix + key] = state;
@@ -6435,7 +6467,7 @@ var Document = function(textOrLines) {
6435
6467
  }
6436
6468
  };
6437
6469
  this.replace = function(range, text) {
6438
- if (!range instanceof Range)
6470
+ if (!(range instanceof Range))
6439
6471
  range = Range.fromPoints(range.start, range.end);
6440
6472
  if (text.length === 0 && range.isEmpty())
6441
6473
  return range.start;
@@ -7336,7 +7368,7 @@ function Folding() {
7336
7368
  var folds = this.getFoldsInRange(ranges);
7337
7369
  }
7338
7370
  return folds;
7339
- }
7371
+ };
7340
7372
  this.getAllFolds = function() {
7341
7373
  var folds = [];
7342
7374
  var foldLines = this.$foldData;
@@ -7421,15 +7453,15 @@ function Folding() {
7421
7453
  end = foldLine.end.row,
7422
7454
  start = foldLine.start.row;
7423
7455
  if (end >= last) {
7424
- if(start < last) {
7425
- if(start >= first)
7456
+ if (start < last) {
7457
+ if (start >= first)
7426
7458
  rowCount -= last-start;
7427
7459
  else
7428
- rowCount = 0;//in one fold
7460
+ rowCount = 0; // in one fold
7429
7461
  }
7430
7462
  break;
7431
- } else if(end >= first){
7432
- if (start >= first) //fold inside range
7463
+ } else if (end >= first){
7464
+ if (start >= first) // fold inside range
7433
7465
  rowCount -= end-start;
7434
7466
  else
7435
7467
  rowCount -= end-first+1;
@@ -7514,7 +7546,7 @@ function Folding() {
7514
7546
  else
7515
7547
  this.$updateRowLengthCache(foldLine.start.row, foldLine.start.row);
7516
7548
  this.$modified = true;
7517
- this._emit("changeFold", { data: fold, action: "add" });
7549
+ this._signal("changeFold", { data: fold, action: "add" });
7518
7550
 
7519
7551
  return fold;
7520
7552
  };
@@ -7563,7 +7595,7 @@ function Folding() {
7563
7595
  this.$updateRowLengthCache(startRow, endRow);
7564
7596
  }
7565
7597
  this.$modified = true;
7566
- this._emit("changeFold", { data: fold, action: "remove" });
7598
+ this._signal("changeFold", { data: fold, action: "remove" });
7567
7599
  };
7568
7600
 
7569
7601
  this.removeFolds = function(folds) {
@@ -7742,7 +7774,7 @@ function Folding() {
7742
7774
  var placeholder = "...";
7743
7775
  if (!range.isMultiLine()) {
7744
7776
  placeholder = this.getTextRange(range);
7745
- if(placeholder.length < 4)
7777
+ if (placeholder.length < 4)
7746
7778
  return;
7747
7779
  placeholder = placeholder.trim().substring(0, 2) + "..";
7748
7780
  }
@@ -7759,7 +7791,7 @@ function Folding() {
7759
7791
  if (dir != 1) {
7760
7792
  do {
7761
7793
  token = iterator.stepBackward();
7762
- } while(token && re.test(token.type));
7794
+ } while (token && re.test(token.type));
7763
7795
  iterator.stepForward();
7764
7796
  }
7765
7797
 
@@ -7771,7 +7803,7 @@ function Folding() {
7771
7803
  if (dir != -1) {
7772
7804
  do {
7773
7805
  token = iterator.stepForward();
7774
- } while(token && re.test(token.type));
7806
+ } while (token && re.test(token.type));
7775
7807
  token = iterator.stepBackward();
7776
7808
  } else
7777
7809
  token = iterator.getCurrentToken();
@@ -7840,7 +7872,7 @@ function Folding() {
7840
7872
 
7841
7873
  this.off('change', this.$updateFoldWidgets);
7842
7874
  this.off('tokenizerUpdate', this.$tokenizerUpdateFoldWidgets);
7843
- this._emit("changeAnnotation");
7875
+ this._signal("changeAnnotation");
7844
7876
 
7845
7877
  if (!foldMode || this.$foldStyle == "manual") {
7846
7878
  this.foldWidgets = null;
@@ -7882,7 +7914,7 @@ function Folding() {
7882
7914
  range: i !== -1 && range,
7883
7915
  firstRange: firstRange
7884
7916
  };
7885
- }
7917
+ };
7886
7918
 
7887
7919
  this.onFoldWidgetClick = function(row, e) {
7888
7920
  e = e.domEvent;
@@ -7894,7 +7926,7 @@ function Folding() {
7894
7926
 
7895
7927
  var range = this.$toggleFoldWidget(row, options);
7896
7928
  if (!range) {
7897
- var el = (e.target || e.srcElement)
7929
+ var el = (e.target || e.srcElement);
7898
7930
  if (el && /ace_fold-widget/.test(el.className))
7899
7931
  el.className += " ace_invalid";
7900
7932
  }
@@ -7989,7 +8021,7 @@ function Folding() {
7989
8021
  if (this.foldWidgets.length > rows.first)
7990
8022
  this.foldWidgets.splice(rows.first, this.foldWidgets.length);
7991
8023
  }
7992
- }
8024
+ };
7993
8025
  }
7994
8026
 
7995
8027
  exports.Folding = Folding;
@@ -9753,6 +9785,29 @@ var EditSession = function(text, mode) {
9753
9785
  return screenRows;
9754
9786
  };
9755
9787
  this.$setFontMetrics = function(fm) {
9788
+ if (!this.$enableVarChar) return;
9789
+ this.$getStringScreenWidth = function(str, maxScreenColumn, screenColumn) {
9790
+ if (maxScreenColumn === 0)
9791
+ return [0, 0];
9792
+ if (!maxScreenColumn)
9793
+ maxScreenColumn = Infinity;
9794
+ screenColumn = screenColumn || 0;
9795
+
9796
+ var c, column;
9797
+ for (column = 0; column < str.length; column++) {
9798
+ c = str.charAt(column);
9799
+ if (c === "\t") {
9800
+ screenColumn += this.getScreenTabSize(screenColumn);
9801
+ } else {
9802
+ screenColumn += fm.getCharacterWidth(c);
9803
+ }
9804
+ if (screenColumn > maxScreenColumn) {
9805
+ break;
9806
+ }
9807
+ }
9808
+
9809
+ return [screenColumn, column];
9810
+ };
9756
9811
  };
9757
9812
 
9758
9813
  this.destroy = function() {
@@ -10394,6 +10449,7 @@ MultiHashHandler.prototype = HashHandler.prototype;
10394
10449
  };
10395
10450
 
10396
10451
  this.handleKeyboard = function(data, hashId, keyString, keyCode) {
10452
+ if (keyCode < 0) return;
10397
10453
  var key = KEY_MODS[hashId] + keyString;
10398
10454
  var command = this.commandKeyBinding[key];
10399
10455
  if (data.$keyChain) {
@@ -13092,7 +13148,7 @@ var UndoManager = function() {
13092
13148
  var deltaSets = this.$undoStack.pop();
13093
13149
  var undoSelectionRange = null;
13094
13150
  if (deltaSets) {
13095
- undoSelectionRange = this.$doc.undoChanges(this.$deserializeDeltas(deltaSets), dontSelect);
13151
+ undoSelectionRange = this.$doc.undoChanges(deltaSets, dontSelect);
13096
13152
  this.$redoStack.push(deltaSets);
13097
13153
  this.dirtyCounter--;
13098
13154
  }
@@ -13898,7 +13954,7 @@ var Text = function(parentEl) {
13898
13954
 
13899
13955
  this.$renderToken = function(stringBuilder, screenColumn, token, value) {
13900
13956
  var self = this;
13901
- var replaceReg = /\t|&|<|>|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g;
13957
+ var replaceReg = /\t|&|<|>|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF\uFFF9-\uFFFC])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g;
13902
13958
  var replaceFunc = function(c, a, b, tabIdx, idx4) {
13903
13959
  if (a) {
13904
13960
  return self.showInvisibles
@@ -14644,7 +14700,7 @@ var FontMetrics = exports.FontMetrics = function(parentEl, interval) {
14644
14700
  this.getCharacterWidth = function(ch) {
14645
14701
  var w = this.charSizes[ch];
14646
14702
  if (w === undefined) {
14647
- this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width;
14703
+ w = this.charSizes[ch] = this.$measureCharWidth(ch) / this.$characterSize.width;
14648
14704
  }
14649
14705
  return w;
14650
14706
  };
@@ -16550,7 +16606,7 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
16550
16606
 
16551
16607
  this.$pos = pos;
16552
16608
  var undoStack = session.getUndoManager().$undoStack || session.getUndoManager().$undostack || {length: -1};
16553
- this.$undoStackDepth = undoStack.length;
16609
+ this.$undoStackDepth = undoStack.length;
16554
16610
  this.setup();
16555
16611
 
16556
16612
  session.selection.on("changeCursor", this.$onCursorChange);
@@ -16563,103 +16619,97 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
16563
16619
  var _self = this;
16564
16620
  var doc = this.doc;
16565
16621
  var session = this.session;
16566
- var pos = this.$pos;
16567
16622
 
16568
16623
  this.selectionBefore = session.selection.toJSON();
16569
16624
  if (session.selection.inMultiSelectMode)
16570
16625
  session.selection.toSingleRange();
16571
16626
 
16572
- this.pos = doc.createAnchor(pos.row, pos.column);
16573
- this.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false);
16574
- this.pos.on("change", function(event) {
16575
- session.removeMarker(_self.markerId);
16576
- _self.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.mainClass, null, false);
16577
- });
16627
+ this.pos = doc.createAnchor(this.$pos.row, this.$pos.column);
16628
+ var pos = this.pos;
16629
+ pos.$insertRight = true;
16630
+ pos.detach();
16631
+ pos.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column + this.length), this.mainClass, null, false);
16578
16632
  this.others = [];
16579
16633
  this.$others.forEach(function(other) {
16580
16634
  var anchor = doc.createAnchor(other.row, other.column);
16635
+ anchor.$insertRight = true;
16636
+ anchor.detach();
16581
16637
  _self.others.push(anchor);
16582
16638
  });
16583
16639
  session.setUndoSelect(false);
16584
16640
  };
16585
16641
  this.showOtherMarkers = function() {
16586
- if(this.othersActive) return;
16642
+ if (this.othersActive) return;
16587
16643
  var session = this.session;
16588
16644
  var _self = this;
16589
16645
  this.othersActive = true;
16590
16646
  this.others.forEach(function(anchor) {
16591
16647
  anchor.markerId = session.addMarker(new Range(anchor.row, anchor.column, anchor.row, anchor.column+_self.length), _self.othersClass, null, false);
16592
- anchor.on("change", function(event) {
16593
- session.removeMarker(anchor.markerId);
16594
- anchor.markerId = session.addMarker(new Range(event.value.row, event.value.column, event.value.row, event.value.column+_self.length), _self.othersClass, null, false);
16595
- });
16596
16648
  });
16597
16649
  };
16598
16650
  this.hideOtherMarkers = function() {
16599
- if(!this.othersActive) return;
16651
+ if (!this.othersActive) return;
16600
16652
  this.othersActive = false;
16601
16653
  for (var i = 0; i < this.others.length; i++) {
16602
16654
  this.session.removeMarker(this.others[i].markerId);
16603
16655
  }
16604
16656
  };
16605
16657
  this.onUpdate = function(delta) {
16658
+ if (this.$updating)
16659
+ return this.updateAnchors(delta);
16660
+
16606
16661
  var range = delta;
16607
- if(range.start.row !== range.end.row) return;
16608
- if(range.start.row !== this.pos.row) return;
16609
- if (this.$updating) return;
16662
+ if (range.start.row !== range.end.row) return;
16663
+ if (range.start.row !== this.pos.row) return;
16610
16664
  this.$updating = true;
16611
16665
  var lengthDiff = delta.action === "insert" ? range.end.column - range.start.column : range.start.column - range.end.column;
16666
+ var inMainRange = range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1;
16667
+ var distanceFromStart = range.start.column - this.pos.column;
16668
+
16669
+ this.updateAnchors(delta);
16612
16670
 
16613
- if(range.start.column >= this.pos.column && range.start.column <= this.pos.column + this.length + 1) {
16614
- var distanceFromStart = range.start.column - this.pos.column;
16671
+ if (inMainRange)
16615
16672
  this.length += lengthDiff;
16616
- if(!this.session.$fromUndo) {
16617
- if(delta.action === 'insert') {
16618
- for (var i = this.others.length - 1; i >= 0; i--) {
16619
- var otherPos = this.others[i];
16620
- var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
16621
- if(otherPos.row === range.start.row && range.start.column < otherPos.column)
16622
- newPos.column += lengthDiff;
16623
- this.doc.insertMergedLines(newPos, delta.lines);
16624
- }
16625
- } else if(delta.action === 'remove') {
16626
- for (var i = this.others.length - 1; i >= 0; i--) {
16627
- var otherPos = this.others[i];
16628
- var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
16629
- if(otherPos.row === range.start.row && range.start.column < otherPos.column)
16630
- newPos.column += lengthDiff;
16631
- this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff));
16632
- }
16633
- }
16634
- if(range.start.column === this.pos.column && delta.action === 'insert') {
16635
- setTimeout(function() {
16636
- this.pos.setPosition(this.pos.row, this.pos.column - lengthDiff);
16637
- for (var i = 0; i < this.others.length; i++) {
16638
- var other = this.others[i];
16639
- var newPos = {row: other.row, column: other.column - lengthDiff};
16640
- if(other.row === range.start.row && range.start.column < other.column)
16641
- newPos.column += lengthDiff;
16642
- other.setPosition(newPos.row, newPos.column);
16643
- }
16644
- }.bind(this), 0);
16673
+
16674
+ if (inMainRange && !this.session.$fromUndo) {
16675
+ if (delta.action === 'insert') {
16676
+ for (var i = this.others.length - 1; i >= 0; i--) {
16677
+ var otherPos = this.others[i];
16678
+ var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
16679
+ this.doc.insertMergedLines(newPos, delta.lines);
16645
16680
  }
16646
- else if(range.start.column === this.pos.column && delta.action === 'remove') {
16647
- setTimeout(function() {
16648
- for (var i = 0; i < this.others.length; i++) {
16649
- var other = this.others[i];
16650
- if(other.row === range.start.row && range.start.column < other.column) {
16651
- other.setPosition(other.row, other.column - lengthDiff);
16652
- }
16653
- }
16654
- }.bind(this), 0);
16681
+ } else if (delta.action === 'remove') {
16682
+ for (var i = this.others.length - 1; i >= 0; i--) {
16683
+ var otherPos = this.others[i];
16684
+ var newPos = {row: otherPos.row, column: otherPos.column + distanceFromStart};
16685
+ this.doc.remove(new Range(newPos.row, newPos.column, newPos.row, newPos.column - lengthDiff));
16655
16686
  }
16656
16687
  }
16657
- this.pos._emit("change", {value: this.pos});
16658
- for (var i = 0; i < this.others.length; i++) {
16659
- this.others[i]._emit("change", {value: this.others[i]});
16660
- }
16661
16688
  }
16689
+
16662
16690
  this.$updating = false;
16691
+ this.updateMarkers();
16692
+ };
16693
+
16694
+ this.updateAnchors = function(delta) {
16695
+ this.pos.onChange(delta);
16696
+ for (var i = this.others.length; i--;)
16697
+ this.others[i].onChange(delta);
16698
+ this.updateMarkers();
16699
+ };
16700
+
16701
+ this.updateMarkers = function() {
16702
+ if (this.$updating)
16703
+ return;
16704
+ var _self = this;
16705
+ var session = this.session;
16706
+ var updateMarker = function(pos, className) {
16707
+ session.removeMarker(pos.markerId);
16708
+ pos.markerId = session.addMarker(new Range(pos.row, pos.column, pos.row, pos.column+_self.length), className, null, false);
16709
+ };
16710
+ updateMarker(this.pos, this.mainClass);
16711
+ for (var i = this.others.length; i--;)
16712
+ updateMarker(this.others[i], this.othersClass);
16663
16713
  };
16664
16714
 
16665
16715
  this.onCursorChange = function(event) {
@@ -16674,20 +16724,16 @@ var PlaceHolder = function(session, length, pos, others, mainClass, othersClass)
16674
16724
  }
16675
16725
  };
16676
16726
  this.detach = function() {
16677
- this.session.removeMarker(this.markerId);
16727
+ this.session.removeMarker(this.pos && this.pos.markerId);
16678
16728
  this.hideOtherMarkers();
16679
16729
  this.doc.removeEventListener("change", this.$onUpdate);
16680
16730
  this.session.selection.removeEventListener("changeCursor", this.$onCursorChange);
16681
- this.pos.detach();
16682
- for (var i = 0; i < this.others.length; i++) {
16683
- this.others[i].detach();
16684
- }
16685
16731
  this.session.setUndoSelect(true);
16686
16732
  this.session = null;
16687
16733
  };
16688
16734
  this.cancel = function() {
16689
- if(this.$undoStackDepth === -1)
16690
- throw Error("Canceling placeholders only supported with undo manager attached to session.");
16735
+ if (this.$undoStackDepth === -1)
16736
+ return;
16691
16737
  var undoManager = this.session.getUndoManager();
16692
16738
  var undosRequired = (undoManager.$undoStack || undoManager.$undostack).length - this.$undoStackDepth;
16693
16739
  for (var i = 0; i < undosRequired; i++) {
@@ -18007,6 +18053,7 @@ function LineWidgets(session) {
18007
18053
  this.$onChangeEditor = this.$onChangeEditor.bind(this);
18008
18054
 
18009
18055
  this.session.on("change", this.updateOnChange);
18056
+ this.session.on("changeFold", this.updateOnFold);
18010
18057
  this.session.on("changeEditor", this.$onChangeEditor);
18011
18058
  }
18012
18059
 
@@ -18027,8 +18074,8 @@ function LineWidgets(session) {
18027
18074
  this.$getWidgetScreenLength = function() {
18028
18075
  var screenRows = 0;
18029
18076
  this.lineWidgets.forEach(function(w){
18030
- if (w && w.rowCount)
18031
- screenRows +=w.rowCount;
18077
+ if (w && w.rowCount && !w.hidden)
18078
+ screenRows += w.rowCount;
18032
18079
  });
18033
18080
  return screenRows;
18034
18081
  };
@@ -18072,6 +18119,32 @@ function LineWidgets(session) {
18072
18119
  });
18073
18120
  };
18074
18121
 
18122
+ this.updateOnFold = function(e, session) {
18123
+ var lineWidgets = session.lineWidgets;
18124
+ if (!lineWidgets || !e.action)
18125
+ return;
18126
+ var fold = e.data;
18127
+ var start = fold.start.row;
18128
+ var end = fold.end.row;
18129
+ var hide = e.action == "add";
18130
+ for (var i = start + 1; i < end; i++) {
18131
+ if (lineWidgets[i])
18132
+ lineWidgets[i].hidden = hide;
18133
+ }
18134
+ if (lineWidgets[end]) {
18135
+ if (hide) {
18136
+ if (!lineWidgets[start])
18137
+ lineWidgets[start] = lineWidgets[end];
18138
+ else
18139
+ lineWidgets[end].hidden = hide;
18140
+ } else {
18141
+ if (lineWidgets[start] == lineWidgets[end])
18142
+ lineWidgets[start] = undefined;
18143
+ lineWidgets[end].hidden = hide;
18144
+ }
18145
+ }
18146
+ };
18147
+
18075
18148
  this.updateOnChange = function(delta) {
18076
18149
  var lineWidgets = this.session.lineWidgets;
18077
18150
  if (!lineWidgets) return;
@@ -18102,6 +18175,10 @@ function LineWidgets(session) {
18102
18175
  if (w) {
18103
18176
  noWidgets = false;
18104
18177
  w.row = i;
18178
+ while (w.$oldWidget) {
18179
+ w.$oldWidget.row = i;
18180
+ w = w.$oldWidget;
18181
+ }
18105
18182
  }
18106
18183
  });
18107
18184
  if (noWidgets)
@@ -18112,8 +18189,19 @@ function LineWidgets(session) {
18112
18189
  if (!this.session.lineWidgets)
18113
18190
  this.session.lineWidgets = new Array(this.session.getLength());
18114
18191
 
18192
+ var old = this.session.lineWidgets[w.row];
18193
+ if (old) {
18194
+ w.$oldWidget = old;
18195
+ if (old.el && old.el.parentNode) {
18196
+ old.el.parentNode.removeChild(old.el);
18197
+ old._inDocument = false;
18198
+ }
18199
+ }
18200
+
18115
18201
  this.session.lineWidgets[w.row] = w;
18116
18202
 
18203
+ w.session = this.session;
18204
+
18117
18205
  var renderer = this.editor.renderer;
18118
18206
  if (w.html && !w.el) {
18119
18207
  w.el = dom.createElement("div");
@@ -18133,29 +18221,67 @@ function LineWidgets(session) {
18133
18221
  if (!w.pixelHeight) {
18134
18222
  w.pixelHeight = w.el.offsetHeight;
18135
18223
  }
18136
- if (w.rowCount == null)
18224
+ if (w.rowCount == null) {
18137
18225
  w.rowCount = w.pixelHeight / renderer.layerConfig.lineHeight;
18226
+ }
18138
18227
 
18228
+ var fold = this.session.getFoldAt(w.row, 0);
18229
+ w.$fold = fold;
18230
+ if (fold) {
18231
+ var lineWidgets = this.session.lineWidgets;
18232
+ if (w.row == fold.end.row && !lineWidgets[fold.start.row])
18233
+ lineWidgets[fold.start.row] = w;
18234
+ else
18235
+ w.hidden = true;
18236
+ }
18237
+
18139
18238
  this.session._emit("changeFold", {data:{start:{row: w.row}}});
18140
18239
 
18141
18240
  this.$updateRows();
18142
18241
  this.renderWidgets(null, renderer);
18242
+ this.onWidgetChanged(w);
18143
18243
  return w;
18144
18244
  };
18145
18245
 
18146
18246
  this.removeLineWidget = function(w) {
18147
18247
  w._inDocument = false;
18248
+ w.session = null;
18148
18249
  if (w.el && w.el.parentNode)
18149
18250
  w.el.parentNode.removeChild(w.el);
18150
18251
  if (w.editor && w.editor.destroy) try {
18151
18252
  w.editor.destroy();
18152
18253
  } catch(e){}
18153
- if (this.session.lineWidgets)
18154
- this.session.lineWidgets[w.row] = undefined;
18254
+ if (this.session.lineWidgets) {
18255
+ var w1 = this.session.lineWidgets[w.row]
18256
+ if (w1 == w) {
18257
+ this.session.lineWidgets[w.row] = w.$oldWidget;
18258
+ if (w.$oldWidget)
18259
+ this.onWidgetChanged(w.$oldWidget);
18260
+ } else {
18261
+ while (w1) {
18262
+ if (w1.$oldWidget == w) {
18263
+ w1.$oldWidget = w.$oldWidget;
18264
+ break;
18265
+ }
18266
+ w1 = w1.$oldWidget;
18267
+ }
18268
+ }
18269
+ }
18155
18270
  this.session._emit("changeFold", {data:{start:{row: w.row}}});
18156
18271
  this.$updateRows();
18157
18272
  };
18158
18273
 
18274
+ this.getWidgetsAtRow = function(row) {
18275
+ var lineWidgets = this.session.lineWidgets;
18276
+ var w = lineWidgets && lineWidgets[row];
18277
+ var list = [];
18278
+ while (w) {
18279
+ list.push(w);
18280
+ w = w.$oldWidget;
18281
+ }
18282
+ return list;
18283
+ };
18284
+
18159
18285
  this.onWidgetChanged = function(w) {
18160
18286
  this.session._changedWidgets.push(w);
18161
18287
  this.editor && this.editor.renderer.updateFull();
@@ -18169,7 +18295,11 @@ function LineWidgets(session) {
18169
18295
  var min = Infinity;
18170
18296
  for (var i = 0; i < changedWidgets.length; i++) {
18171
18297
  var w = changedWidgets[i];
18298
+ if (!w || !w.el) continue;
18299
+ if (w.session != this.session) continue;
18172
18300
  if (!w._inDocument) {
18301
+ if (this.session.lineWidgets[w.row] != w)
18302
+ continue;
18173
18303
  w._inDocument = true;
18174
18304
  renderer.container.appendChild(w.el);
18175
18305
  }
@@ -18218,7 +18348,10 @@ function LineWidgets(session) {
18218
18348
  for (var i = first; i <= last; i++) {
18219
18349
  var w = lineWidgets[i];
18220
18350
  if (!w || !w.el) continue;
18221
-
18351
+ if (w.hidden) {
18352
+ w.el.style.top = -100 - (w.pixelHeight || 0) + "px";
18353
+ continue;
18354
+ }
18222
18355
  if (!w._inDocument) {
18223
18356
  w._inDocument = true;
18224
18357
  renderer.container.appendChild(w.el);
@@ -18232,7 +18365,11 @@ function LineWidgets(session) {
18232
18365
  if (!w.fixedWidth)
18233
18366
  left -= renderer.scrollLeft;
18234
18367
  w.el.style.left = left + "px";
18235
-
18368
+
18369
+ if (w.fullWidth && w.screenWidth) {
18370
+ w.el.style.minWidth = config.width + 2 * config.padding + "px";
18371
+ }
18372
+
18236
18373
  if (w.fixedWidth) {
18237
18374
  w.el.style.right = renderer.scrollBar.getWidth() + "px";
18238
18375
  } else {
@@ -18316,7 +18453,9 @@ exports.showErrorMarker = function(editor, dir) {
18316
18453
 
18317
18454
  var pos = editor.getCursorPosition();
18318
18455
  var row = pos.row;
18319
- var oldWidget = session.lineWidgets && session.lineWidgets[row];
18456
+ var oldWidget = session.widgetManager.getWidgetsAtRow(row).filter(function(w) {
18457
+ return w.type == "errorMarker";
18458
+ })[0];
18320
18459
  if (oldWidget) {
18321
18460
  oldWidget.destroy();
18322
18461
  } else {
@@ -18346,7 +18485,8 @@ exports.showErrorMarker = function(editor, dir) {
18346
18485
  row: pos.row,
18347
18486
  fixedWidth: true,
18348
18487
  coverGutter: true,
18349
- el: dom.createElement("div")
18488
+ el: dom.createElement("div"),
18489
+ type: "errorMarker"
18350
18490
  };
18351
18491
  var el = w.el.appendChild(dom.createElement("div"));
18352
18492
  var arrow = w.el.appendChild(dom.createElement("div"));
@@ -18501,6 +18641,7 @@ exports.createEditSession = function(text, mode) {
18501
18641
  }
18502
18642
  exports.EditSession = EditSession;
18503
18643
  exports.UndoManager = UndoManager;
18644
+ exports.version = "1.2.2";
18504
18645
  });
18505
18646
  (function() {
18506
18647
  window.require(["ace/ace"], function(a) {