written 0.0.5 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/LICENSE +8 -0
  4. data/README.md +63 -0
  5. data/Rakefile +17 -27
  6. data/lib/written.rb +0 -8
  7. data/lib/written/app/assets/images/written/placeholder.png +0 -0
  8. data/lib/written/app/assets/javascripts/written.coffee +2 -0
  9. data/lib/written/app/assets/javascripts/written/core/content.coffee +53 -35
  10. data/lib/written/app/assets/javascripts/written/core/cursor.coffee +33 -12
  11. data/lib/written/app/assets/javascripts/written/core/document.coffee +16 -11
  12. data/lib/written/app/assets/javascripts/written/core/extensions/string.coffee +9 -0
  13. data/lib/written/app/assets/javascripts/written/core/extensions/text.coffee +2 -0
  14. data/lib/written/app/assets/javascripts/written/core/history.coffee +2 -0
  15. data/lib/written/app/assets/javascripts/written/core/observer.coffee +6 -2
  16. data/lib/written/app/assets/javascripts/written/core/stringify.coffee +15 -0
  17. data/lib/written/app/assets/javascripts/written/parsers/block.coffee +69 -0
  18. data/lib/written/app/assets/javascripts/written/parsers/block/code.coffee +79 -15
  19. data/lib/written/app/assets/javascripts/written/parsers/block/heading.coffee +60 -5
  20. data/lib/written/app/assets/javascripts/written/parsers/block/image.coffee +103 -9
  21. data/lib/written/app/assets/javascripts/written/parsers/block/olist.coffee +94 -12
  22. data/lib/written/app/assets/javascripts/written/parsers/block/paragraph.coffee +63 -5
  23. data/lib/written/app/assets/javascripts/written/parsers/block/quote.coffee +92 -0
  24. data/lib/written/app/assets/javascripts/written/parsers/block/ulist.coffee +93 -12
  25. data/lib/written/app/assets/javascripts/written/parsers/inline.coffee +81 -0
  26. data/lib/written/app/assets/javascripts/written/parsers/inline/code.coffee +57 -0
  27. data/lib/written/app/assets/javascripts/written/parsers/inline/italic.coffee +40 -7
  28. data/lib/written/app/assets/javascripts/written/parsers/inline/link.coffee +43 -13
  29. data/lib/written/app/assets/javascripts/written/parsers/inline/list.coffee +27 -0
  30. data/lib/written/app/assets/javascripts/written/parsers/inline/strong.coffee +41 -7
  31. data/lib/written/app/assets/javascripts/written/parsers/parsers.coffee +21 -107
  32. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/CustomElements.js +32 -0
  33. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/base.js +40 -0
  34. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/boot.js +124 -0
  35. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/observe.js +318 -0
  36. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/register.js +369 -0
  37. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/traverse.js +86 -0
  38. data/lib/written/app/assets/javascripts/written/polyfills/CustomElements/upgrade.js +130 -0
  39. data/lib/written/app/assets/javascripts/written/polyfills/MutationObserver/MutationObserver.js +575 -0
  40. data/lib/written/app/assets/javascripts/written/polyfills/WeakMap/WeakMap.js +49 -0
  41. data/lib/written/app/assets/javascripts/written/polyfills/base.coffee +10 -0
  42. data/lib/written/app/assets/javascripts/written/polyfills/dom.js +104 -0
  43. data/lib/written/app/assets/javascripts/written/uploaders/aws.coffee +125 -0
  44. data/lib/written/app/assets/stylesheets/written.scss +80 -11
  45. data/lib/written/version.rb +1 -1
  46. data/test/server/app/assets/javascripts/application.coffee +20 -2
  47. data/test/server/app/assets/stylesheets/application.scss +2 -2
  48. data/test/server/app/assets/stylesheets/prism.css +0 -1
  49. data/test/server/app/views/posts/show.html.erb +10 -3
  50. metadata +26 -20
  51. data/lib/written/app/assets/javascripts/written/core/ext.coffee +0 -109
  52. data/lib/written/app/assets/javascripts/written/core/extensions.coffee +0 -2
  53. data/lib/written/document.rb +0 -42
  54. data/lib/written/node.rb +0 -21
  55. data/lib/written/nodes/code.rb +0 -65
  56. data/lib/written/nodes/heading.rb +0 -15
  57. data/lib/written/nodes/image.rb +0 -14
  58. data/lib/written/nodes/ordered_list.rb +0 -18
  59. data/lib/written/nodes/unordered_list.rb +0 -19
  60. data/lib/written/parsers.rb +0 -11
  61. data/lib/written/parsers/base.rb +0 -26
  62. data/lib/written/parsers/code.rb +0 -60
  63. data/lib/written/parsers/heading.rb +0 -19
  64. data/lib/written/parsers/image.rb +0 -19
  65. data/lib/written/parsers/link.rb +0 -12
  66. data/lib/written/parsers/list.rb +0 -33
  67. data/lib/written/parsers/word.rb +0 -16
@@ -1,16 +1,46 @@
1
1
  class Link
2
2
  constructor: (match) ->
3
3
  @match = match
4
- @node = "<a>".toHTML()
5
-
6
- render: (textNode) =>
7
- @node.href = @match[4]
8
- name = "<strong>".toHTML()
9
- anchor = textNode.splitText(textNode.textContent.indexOf(@match[0]))
10
- anchor.splitText(@match[0].length)
11
- name.textContent = @match[1]
12
- @node.appendChild(name)
13
- @node.appendChild(document.createTextNode(@match[3]))
14
- textNode.parentElement.replaceChild(@node, anchor)
15
-
16
- Written.Parsers.Inline.register Link, /!{0}(\[([^\]]+)\])(\(([^\)]+)\))/gi
4
+
5
+ index: =>
6
+ @match.index
7
+
8
+ length: =>
9
+ @match[0].length
10
+
11
+ markdown: =>
12
+ "<a is='written-a' href='javascript:void(0)'><strong>#{@match[1]}</strong>#{@match[3]}</a>".toHTML()
13
+
14
+ html: =>
15
+ "<a href='#{@match[4]}'>#{@match[2]}</a>".toHTML()
16
+
17
+ Link.rule = /!{0}(\[([^\]]+)\])(\(([^\)]+)\))/gi
18
+
19
+ Written.Parsers.Inline.register Link
20
+
21
+ prototype = Object.create(HTMLAnchorElement.prototype)
22
+
23
+ prototype.getRange = (offset, walker) ->
24
+ range = document.createRange()
25
+
26
+ if !@firstChild?
27
+ range.setStart(this, 0)
28
+ else
29
+ while walker.nextNode()
30
+ if walker.currentNode.length < offset
31
+ offset -= walker.currentNode.length
32
+ continue
33
+
34
+ range.setStart(walker.currentNode, offset)
35
+ break
36
+
37
+ range.collapse(true)
38
+ range
39
+
40
+ prototype.toString = ->
41
+ @textContent
42
+
43
+ document.registerElement('written-a', {
44
+ prototype: prototype
45
+ extends: 'a'
46
+ })
@@ -0,0 +1,27 @@
1
+ prototype = Object.create(HTMLLIElement.prototype)
2
+
3
+ prototype.getRange = (offset, walker) ->
4
+ range = document.createRange()
5
+
6
+ if !@firstChild?
7
+ range.setStart(this, 0)
8
+ else
9
+ while walker.nextNode()
10
+ if walker.currentNode.length < offset
11
+ offset -= walker.currentNode.length
12
+ continue
13
+
14
+ range.setStart(walker.currentNode, offset)
15
+ break
16
+
17
+ range.collapse(true)
18
+ range
19
+
20
+ prototype.toString = ->
21
+ @textContent
22
+
23
+ document.registerElement('written-li', {
24
+ prototype: prototype
25
+ extends: 'li'
26
+ })
27
+
@@ -1,12 +1,46 @@
1
1
  class Strong
2
2
  constructor: (match) ->
3
3
  @match = match
4
- @node = "<strong>".toHTML()
5
4
 
6
- render: (textNode) =>
7
- strong = textNode.splitText(textNode.textContent.indexOf(@match[0]))
8
- strong.splitText(@match[0].length)
9
- @node.appendChild(document.createTextNode(@match[0]))
10
- textNode.parentElement.replaceChild(@node, strong)
5
+ index: =>
6
+ @match.index
11
7
 
12
- Written.Parsers.Inline.register Strong, /((\*{2})[^\*]+(\*{2}))/gi
8
+ length: =>
9
+ @match[0].length
10
+
11
+ markdown: =>
12
+ "<strong is='written-strong'>#{@match[0]}</strong>".toHTML()
13
+
14
+ html: =>
15
+ "<strong>#{@match[3]}</strong>".toHTML()
16
+
17
+ Strong.rule = /((\*{1})([^\*]+)(\*{1}))/gi
18
+
19
+ Written.Parsers.Inline.register Strong
20
+
21
+ prototype = Object.create(HTMLElement.prototype)
22
+
23
+ prototype.getRange = (offset, walker) ->
24
+ range = document.createRange()
25
+
26
+ if !@firstChild?
27
+ range.setStart(this, 0)
28
+ else
29
+ while walker.nextNode()
30
+ if walker.currentNode.length < offset
31
+ offset -= walker.currentNode.length
32
+ continue
33
+
34
+ range.setStart(walker.currentNode, offset)
35
+ break
36
+
37
+ range.collapse(true)
38
+ range
39
+
40
+ prototype.toString = ->
41
+ @textContent
42
+
43
+ document.registerElement('written-strong', {
44
+ prototype: prototype
45
+ extends: 'strong'
46
+ })
@@ -1,113 +1,27 @@
1
- Written.Parsers = {
2
- freeze: ->
3
- Written.Parsers.Block.freeze()
4
- Written.Parsers.Inline.freeze()
5
- }
6
-
7
- Written.Parsers.Block = new class
8
- constructor: ->
9
- @parsers = []
10
-
11
- freeze: ->
12
- @parsers.push this.defaultParser
13
-
14
- Object.freeze(this)
15
- Object.freeze(@parsers)
16
-
17
- get: (name) ->
18
- parser = @parsers.find (parser) ->
19
- parser.parser.name.localeCompare(name) == 0
20
-
21
- if parser
22
- parser.parser
23
-
24
-
25
-
26
- register: (parser, rule, defaultParser = false) ->
27
- if defaultParser
28
- this.defaultParser = {
29
- rule: rule,
30
- parser: parser
31
- }
32
- else
33
- @parsers.push {
34
- rule: rule,
35
- parser: parser
36
- }
37
-
38
- parse: (lines) =>
39
- elements = []
40
- currentNode = undefined
41
- while (line = lines.pop()) != undefined
42
- str = line.toString()
43
- if !currentNode
44
- parser = @find(str)
45
- currentNode = parser.render(str)
46
- elements.push(currentNode)
47
- continue
48
-
49
- if currentNode.dataset.status != 'opened'
50
- parser = @find(str)
51
- currentNode.nextDocumentNode = parser.render(str)
52
- currentNode = currentNode.nextDocumentNode
53
- currentNode.writtenNodeParser = parser
54
- elements.push(currentNode)
55
- continue
56
- else if currentNode.writtenNodeParser.valid(str)
57
- currentNode.writtenNodeParser.render(str)
58
- continue
59
- else
60
- parser = @find(str)
61
- currentNode.nextDocumentNode = parser.render(str)
62
- currentNode = currentNode.nextDocumentNode
63
- currentNode.writtenNodeParser = parser
64
- elements.push(currentNode)
65
-
66
- elements[0]
67
-
68
- find: (str) ->
69
- parser = undefined
70
- for p in @parsers
71
- if match = p.rule.exec(str)
72
- parser = new p.parser(match)
73
- break
74
-
75
- return parser
76
-
77
-
78
- Written.Parsers.Inline = new class
1
+ class @Written.Parsers
79
2
  constructor: ->
80
- @parsers = []
81
-
82
- freeze: ->
83
- Object.freeze(this)
84
- Object.freeze(@parsers)
3
+ @block = new Written.Parsers.Block()
4
+ @inline = new Written.Parsers.Inline()
85
5
 
86
- get: (name) ->
87
- parser = @parsers.find (parser) ->
88
- parser.parser.name.localeCompare(name) == 0
6
+ use: (type, name) ->
7
+ if type != 'block' && type != 'inline'
8
+ raise 'error: Written.Parsers can either be "block" or "inline"'
9
+ return
89
10
 
90
- if parser
91
- parser.parser
11
+ @[type].use(name)
92
12
 
93
-
94
- register: (parser, rule) ->
95
- @parsers.push {
96
- rule: rule,
97
- parser: parser
13
+ available: ->
14
+ {
15
+ block: Written.Parsers.Block.parsers.available,
16
+ inline: Written.Parsers.Inline.parsers.available
98
17
  }
99
18
 
100
- parse: (block) =>
101
- walker = document.createTreeWalker(block, NodeFilter.SHOW_TEXT)
102
- for p in @parsers
103
- walker.currentNode = walker.root
104
-
105
- while walker.nextNode()
106
- if match = p.rule.exec(walker.currentNode.textContent)
107
- new p.parser(match).render(walker.currentNode)
108
-
109
-
110
- isLeafNode: (node) ->
111
- if node.children.length == 0
112
- return NodeFilter.FILTER_ACCEPT
113
-
19
+ freeze: ->
20
+ @block.freeze()
21
+ @inline.freeze()
22
+
23
+ @Written.Parsers.default = ->
24
+ parsers = new Written.Parsers()
25
+ parsers.use('inline', 'all')
26
+ parsers.use('block', 'all')
27
+ parsers
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
+ * Code distributed by Google as part of the polymer project is also
8
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9
+ */
10
+ (function() {
11
+
12
+ // Establish polyfill scope. We do this here to store flags. Flags are not
13
+ // supported in the build.
14
+ window.CustomElements = window.CustomElements || {flags:{}};
15
+
16
+ // Flags. Convert url arguments to flags
17
+ var flags = {};
18
+ if (!flags.noOpts) {
19
+ location.search.slice(1).split('&').forEach(function(option) {
20
+ var parts = option.split('=');
21
+ var match;
22
+ if (parts[0] && (match = parts[0].match(/wc-(.+)/))) {
23
+ flags[match[1]] = parts[1] || true;
24
+ }
25
+ });
26
+ }
27
+
28
+
29
+ // exports
30
+ window.CustomElements.flags = flags;
31
+
32
+ })();
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
+ * Code distributed by Google as part of the polymer project is also
8
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9
+ */
10
+ window.CustomElements = window.CustomElements || {flags:{}};
11
+
12
+ (function(scope) {
13
+
14
+ // imports
15
+ var flags = scope.flags;
16
+
17
+ // world's simplest module initializer
18
+ var modules = [];
19
+ var addModule = function(module) {
20
+ modules.push(module);
21
+ };
22
+
23
+ var initializeModules = function() {
24
+ modules.forEach(function(module) {
25
+ module(scope);
26
+ });
27
+ };
28
+
29
+ // exports
30
+ scope.addModule = addModule;
31
+ scope.initializeModules = initializeModules;
32
+ scope.hasNative = Boolean(document.registerElement);
33
+ scope.isIE = /Trident/.test(navigator.userAgent);
34
+
35
+ // NOTE: For consistent timing, use native custom elements only when not
36
+ // polyfilling other key related web components features.
37
+ scope.useNative = !flags.register && scope.hasNative &&
38
+ !window.ShadowDOMPolyfill && (!window.HTMLImports || window.HTMLImports.useNative);
39
+
40
+ })(window.CustomElements);
@@ -0,0 +1,124 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
+ * Code distributed by Google as part of the polymer project is also
8
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
9
+ */
10
+ (function(scope){
11
+
12
+ // imports
13
+ var useNative = scope.useNative;
14
+ var initializeModules = scope.initializeModules;
15
+
16
+ var isIE = scope.isIE;
17
+
18
+ // If native, setup stub api and bail.
19
+ // NOTE: we fire `WebComponentsReady` under native for api compatibility
20
+ if (useNative) {
21
+ // stub
22
+ var nop = function() {};
23
+
24
+ // exports
25
+ scope.watchShadow = nop;
26
+ scope.upgrade = nop;
27
+ scope.upgradeAll = nop;
28
+ scope.upgradeDocumentTree = nop;
29
+ scope.upgradeSubtree = nop;
30
+ scope.takeRecords = nop;
31
+
32
+ scope.instanceof = function(obj, base) {
33
+ return obj instanceof base;
34
+ };
35
+
36
+ } else {
37
+ // Initialize polyfill modules. Note, polyfill modules are loaded but not
38
+ // executed; this is a convenient way to control which modules run when
39
+ // the polyfill is required and allows the polyfill to load even when it's
40
+ // not needed.
41
+ initializeModules();
42
+ }
43
+
44
+ // imports
45
+ var upgradeDocumentTree = scope.upgradeDocumentTree;
46
+ var upgradeDocument = scope.upgradeDocument;
47
+
48
+ // ShadowDOM polyfill wraps elements but some elements like `document`
49
+ // cannot be wrapped so we help the polyfill by wrapping some elements.
50
+ if (!window.wrap) {
51
+ if (window.ShadowDOMPolyfill) {
52
+ window.wrap = window.ShadowDOMPolyfill.wrapIfNeeded;
53
+ window.unwrap = window.ShadowDOMPolyfill.unwrapIfNeeded;
54
+ } else {
55
+ window.wrap = window.unwrap = function(node) {
56
+ return node;
57
+ };
58
+ }
59
+ }
60
+
61
+ // eagarly upgrade imported documents
62
+ if (window.HTMLImports) {
63
+ window.HTMLImports.__importsParsingHook = function(elt) {
64
+ if (elt.import) {
65
+ upgradeDocument(wrap(elt.import));
66
+ }
67
+ };
68
+ }
69
+
70
+ // bootstrap parsing
71
+ function bootstrap() {
72
+ // one more upgrade to catch out of order registrations
73
+ upgradeDocumentTree(window.wrap(document));
74
+ // install upgrade hook if HTMLImports are available
75
+ // set internal 'ready' flag, now document.registerElement will trigger
76
+ // synchronous upgrades
77
+ window.CustomElements.ready = true;
78
+ // async to ensure *native* custom elements upgrade prior to this
79
+ // DOMContentLoaded can fire before elements upgrade (e.g. when there's
80
+ // an external script)
81
+ // Delay doubly to help workaround
82
+ // https://code.google.com/p/chromium/issues/detail?id=516550.
83
+ // CustomElements must use requestAnimationFrame in attachedCallback
84
+ // to query style/layout data. The WebComponentsReady event is intended
85
+ // to convey overall readiness, which ideally should be after elements
86
+ // are attached. Adding a slight extra delay to WebComponentsReady
87
+ // helps preserve this guarantee.
88
+ var requestAnimationFrame = window.requestAnimationFrame || function(f) {
89
+ setTimeout(f, 16);
90
+ };
91
+ requestAnimationFrame(function() {
92
+ setTimeout(function() {
93
+ // capture blunt profiling data
94
+ window.CustomElements.readyTime = Date.now();
95
+ if (window.HTMLImports) {
96
+ window.CustomElements.elapsed = window.CustomElements.readyTime - window.HTMLImports.readyTime;
97
+ }
98
+ // notify the system that we are bootstrapped
99
+ document.dispatchEvent(
100
+ new CustomEvent('WebComponentsReady', {bubbles: true})
101
+ );
102
+ });
103
+ });
104
+ }
105
+
106
+ // When loading at readyState complete time (or via flag), boot custom elements
107
+ // immediately.
108
+ // If relevant, HTMLImports must already be loaded.
109
+ if (document.readyState === 'complete' || scope.flags.eager) {
110
+ bootstrap();
111
+ // When loading at readyState interactive time, bootstrap only if HTMLImports
112
+ // are not pending. Also avoid IE as the semantics of this state are unreliable.
113
+ } else if (document.readyState === 'interactive' && !window.attachEvent &&
114
+ (!window.HTMLImports || window.HTMLImports.ready)) {
115
+ bootstrap();
116
+ // When loading at other readyStates, wait for the appropriate DOM event to
117
+ // bootstrap.
118
+ } else {
119
+ var loadEvent = window.HTMLImports && !window.HTMLImports.ready ?
120
+ 'HTMLImportsLoaded' : 'DOMContentLoaded';
121
+ window.addEventListener(loadEvent, bootstrap);
122
+ }
123
+
124
+ })(window.CustomElements);