├── .gitignore ├── CapitalizeListItems.ftplugin ├── readme.md ├── package.json ├── main.js └── spec.js ├── characterCount.ftplugin ├── package.json └── main.js ├── ExampleKeyBinding.ftplugin ├── main.js └── package.json ├── toggle tags.ftplugin ├── package.json ├── spec.js └── main.js ├── EmacsKeyBindings.ftplugin ├── main.js ├── readme.md └── package.json ├── ReverseText.ftplugin ├── main.js ├── package.json └── spec.js ├── SortLines.ftplugin ├── main.js ├── package.json └── spec.js ├── stopwatch.ftplugin ├── package.json ├── style.less ├── play.svg ├── pause.svg └── main.js ├── RunScript.ftplugin ├── package.json ├── spec.js └── main.js ├── SpeedUp.ftplugin ├── package.json └── main.js ├── FilteringWordCount.ftplugin ├── package.json └── main.js ├── MakeSentenceCase.ftplugin ├── package.json ├── main.js └── spec.js ├── WikiLinks.ftplugin ├── package.json ├── main.js └── spec.js ├── CreateListItems.ftplugin ├── package.json ├── spec.js └── main.js ├── DateAndTime.ftplugin ├── package.json ├── main.js ├── spec.js └── readme.md └── ToggleEmptyLines.ftplugin ├── package.json ├── main.js └── spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /CapitalizeListItems.ftplugin/readme.md: -------------------------------------------------------------------------------- 1 | # Capitalize Items in a List 2 | 3 | Capitlize each element within the list that is selected 4 | 5 | Author: FoldingText -------------------------------------------------------------------------------- /characterCount.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Character Count", 3 | "version": "1.0.0", 4 | "description": "Show character count", 5 | "engines": { 6 | "foldingtext": ">=2.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ExampleKeyBinding.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | // 2 | // Demo plugin showing how to add a keybinding 3 | // 4 | Extensions.addInit(function (editor) { 5 | editor.addKeyMap({ 6 | 'Ctrl-A' : function (editor) { 7 | editor.replaceSelection('â'); 8 | } 9 | }); 10 | }, Extensions.PriorityLast); 11 | -------------------------------------------------------------------------------- /toggle tags.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ToggleTags", 3 | "version": "1.0.0", 4 | "description": "Toggle @done and @today tags.", 5 | "homepage": "https://github.com/FoldingText/plugins/tree/FoldingText-Dev", 6 | "enabled": true, 7 | "engines": { 8 | "foldingtext": ">3.0.0", 9 | "taskpaper": ">3.0.0" 10 | } 11 | } -------------------------------------------------------------------------------- /EmacsKeyBindings.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addKeyMap({ 2 | name: 'croy emacs extensions', 3 | 'Home': 'moveToEndOfLine', 4 | 'Shift-Home': 'moveToEndOfLineAndModifySelection', 5 | 'Alt-F': 'moveWordRight', 6 | 'Alt-B': 'moveWordLeft', 7 | 'Alt-D': 'deleteWordForward', 8 | 'Alt-W': 'expandSelectionToWord', 9 | }); 10 | -------------------------------------------------------------------------------- /ReverseText.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addCommand({ 2 | name: 'ReverseText', 3 | description: 'Reverse the selected text.', 4 | performCommand: (editor) => { 5 | var text = editor.selectedText(), 6 | reverseText = text.split('').reverse().join(''); 7 | editor.replaceSelection(reverseText, 'around'); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /SortLines.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addCommand({ 2 | name: 'sort lines', 3 | description: 'Sort the selected lines of text.', 4 | performCommand: function (editor) { 5 | var text = editor.selectedText(), 6 | sortedText = text.split('\n').sort().join('\n'); 7 | editor.replaceSelection(sortedText, 'around'); 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /EmacsKeyBindings.ftplugin/readme.md: -------------------------------------------------------------------------------- 1 | ### The following keys were added to standard emacs keybindings 2 | 3 | *Home* - Move cursor to end of the line 4 | 5 | *Shift-Home* - Move cursor to the end of the line and modify the selection 6 | 7 | *Alt-F* - Move cursor to the right one word 8 | 9 | *Alt-B* - Move cursor to the right one word 10 | 11 | *Alt-D* - Delete word forward 12 | -------------------------------------------------------------------------------- /stopwatch.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Stopwatch Mode", 3 | "version": "1.0.0", 4 | "description": "Adds 'stopwatch' mode", 5 | "homepage": "https://github.com/FoldingText/plugins/tree/FoldingText-Dev", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "Utility" 11 | ], 12 | "packageId": "StopWatch", 13 | "engines": { 14 | "foldingtext": ">2.0.0" 15 | } 16 | } -------------------------------------------------------------------------------- /RunScript.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Run Script", 3 | "version": "1.0.0", 4 | "description": "Run the selected text as a Javascript function.", 5 | "homepage": "https://github.com/FoldingText/plugins", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "utility", 11 | "sdk" 12 | ], 13 | "engines": { 14 | "foldingtext": ">3.0.0", 15 | "taskpaper": ">3.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /SpeedUp.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Speed Up!", 3 | "version": "1.0.0", 4 | "description": "Write fast! If you pause for more then 5 seconds your document is cleared!!!", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "Utility" 11 | ], 12 | "packageId" : "SpeedUp", 13 | "engines": { 14 | "foldingtext": ">3.0.0" 15 | } 16 | } -------------------------------------------------------------------------------- /SortLines.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sort Lines", 3 | "version": "1.0.0", 4 | "description": "Sort the selected lines.", 5 | "homepage": "https://github.com/FoldingText/plugins", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "utils", 11 | "formatting" 12 | ], 13 | "packageId": "SortLines", 14 | "engines": { 15 | "foldingtext": ">3.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } -------------------------------------------------------------------------------- /ReverseText.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Reverse Text", 3 | "version": "1.0.0", 4 | "description": "Adds command to reverse the selected text.", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "formatting" 11 | ], 12 | "packageId": "ReverseText", 13 | "engines": { 14 | "foldingtext": ">3.0.0", 15 | "taskpaper": ">3.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /FilteringWordCount.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Filtering Word Count", 3 | "version": "1.0.0", 4 | "description": "Alternative word count implementation that filters out blockquotes from total.", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "display" 11 | ], 12 | 13 | "packageId": "FilteringWordCount", 14 | "engines": { 15 | "foldingtext": ">3.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /MakeSentenceCase.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Capitalize List Items", 3 | "version": "1.0.0", 4 | "description": "Adds command to capitalize each selected list item.", 5 | "homepage": "https://github.com/FoldingText/plugins", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "formatting" 11 | ], 12 | "packageId" : "MakeSentenceCase", 13 | "engines": { 14 | "foldingtext": ">3.0.0", 15 | "taskpaper": ">3.0.0" 16 | } 17 | } -------------------------------------------------------------------------------- /CapitalizeListItems.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Capitalize List Items", 3 | "version": "1.0.0", 4 | "description": "Capitalize each selected list item.", 5 | "homepage": "https://github.com/FoldingText/plugins", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "lists", 11 | "formatting" 12 | ], 13 | "packageId": "CapitalizeListItems", 14 | "engines": { 15 | "foldingtext": ">2.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } -------------------------------------------------------------------------------- /WikiLinks.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Wiki Links", 3 | "version": "1.0.0", 4 | "description": "Example plugin showing how to add new wiki link syntax to editor.", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "keyboard", 11 | "emacs" 12 | ], 13 | "packageId": "WikiLinks", 14 | "engines": { 15 | "foldingtext": ">3.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } -------------------------------------------------------------------------------- /CreateListItems.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Create List Items", 3 | "version": "1.0.0", 4 | "description": "Create a list UnOrdered from selected list item.", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "keywords": [ 9 | "list", 10 | "formatting" 11 | ], 12 | "packageId": "CreateListItems", 13 | "enabled": true, 14 | "engines": { 15 | "foldingtext": ">3.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } -------------------------------------------------------------------------------- /DateAndTime.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Date and Time", 3 | "version": "1.0.0", 4 | "description": "Insert the current date or time at the cursor.", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "date", 11 | "time", 12 | "formatting", 13 | ], 14 | "packageId": "DateAndTime", 15 | "engines": { 16 | "foldingtext": ">3.0.0", 17 | "taskpaper": ">3.0.0" 18 | } 19 | } -------------------------------------------------------------------------------- /EmacsKeyBindings.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Emacs Key Bindings", 3 | "version": "1.0.0", 4 | "description": "Additions to the standard emacs keybindings", 5 | "homepage": "https://github.com/FoldingText/plugins", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "keyboard", 11 | "emacs" 12 | ], 13 | "packageId" : "EmacsKeybindings", 14 | "engines": { 15 | "foldingtext": ">3.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DateAndTime.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addCommand({ 2 | name: 'date', 3 | description: 'Insert the current date', 4 | performCommand: function (editor) { 5 | editor.replaceSelection(new Date().toLocaleDateString(), 'around'); 6 | } 7 | }); 8 | 9 | Extensions.addCommand({ 10 | name: 'time', 11 | description: 'Insert the current time', 12 | performCommand: function (editor) { 13 | editor.replaceSelection(new Date().toLocaleTimeString(), 'around'); 14 | } 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /ExampleKeyBinding.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Keybindings Example", 3 | "version": "1.0.0", 4 | "description": "Example plugin to show how to add custom keybinding.", 5 | "homepage": "https://github.com/FoldingText/plugins/", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": false, 9 | "keywords": [ 10 | "keyboard", 11 | "example" 12 | ], 13 | "packageId": "ExampleKeyBinding", 14 | "engines": { 15 | "foldingtext": ">3.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } -------------------------------------------------------------------------------- /ToggleEmptyLines.ftplugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Toggle Empty Lines", 3 | "version": "1.0.0", 4 | "description": "Toggle between no empty lines, and every other line being empty.", 5 | "homepage": "https://github.com/FoldingText/plugins", 6 | "author": "FoldingText", 7 | "license": "MIT", 8 | "enabled": true, 9 | "keywords": [ 10 | "Formatting", 11 | "Utility" 12 | ], 13 | "packageId": "ToggleEmptyLines", 14 | "engines": { 15 | "foldingtext": ">3.0.0", 16 | "taskpaper": ">3.0.0" 17 | } 18 | } -------------------------------------------------------------------------------- /stopwatch.ftplugin/style.less: -------------------------------------------------------------------------------- 1 | .cm-stopwatch-renderwidget { 2 | text-align: right; 3 | .button { 4 | width: 32px; 5 | pointer-events:all; 6 | background: rgb(75, 200, 0); 7 | -webkit-mask: url(play.svg); 8 | -webkit-mask-size: 100% 100%; 9 | -webkit-mask-repeat: no-repeat; 10 | padding : 0.1rem 0.5rem; 11 | } &:hover { 12 | cursor: pointer; 13 | } 14 | } & .running { 15 | .button { 16 | width: 32px; 17 | background: rgb(226, 0, 0); 18 | -webkit-mask: url(pause.svg); 19 | -webkit-mask-size: 100% 100%; 20 | -webkit-mask-repeat: no-repeat; 21 | } 22 | } -------------------------------------------------------------------------------- /SortLines.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Sort Lines', function () { 5 | var Editor = require('ft/editor/editor').Editor, 6 | editor; 7 | 8 | beforeEach(function () { 9 | editor = new Editor(''); 10 | }); 11 | 12 | afterEach(function () { 13 | editor.removeAndCleanupForCollection(); 14 | }); 15 | 16 | it('should sort selected text line', function () { 17 | editor.replaceSelection('c\na\nb', 'around'); 18 | editor.performCommand('sort lines'); 19 | expect(editor.textContent()).toEqual('a\nb\nc'); 20 | }); 21 | }); 22 | }); -------------------------------------------------------------------------------- /ReverseText.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Reverse Text', function () { 5 | var Editor = require('ft/editor/editor').Editor, 6 | editor; 7 | 8 | beforeEach(function () { 9 | editor = new Editor(''); 10 | }); 11 | 12 | afterEach(function () { 13 | editor.removeAndCleanupForCollection(); 14 | }); 15 | 16 | it('should reverse selected text', function () { 17 | editor.replaceSelection('hello world!', 'around'); 18 | editor.performCommand('reverse'); 19 | expect(editor.textContent()).toEqual('!dlrow olleh'); 20 | }); 21 | }); 22 | }); -------------------------------------------------------------------------------- /stopwatch.ftplugin/play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DateAndTime.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Date and time', function () { 5 | var Editor = require('ft/editor/editor').Editor, 6 | editor; 7 | 8 | beforeEach(function () { 9 | editor = new Editor(''); 10 | }); 11 | 12 | afterEach(function () { 13 | editor.removeAndCleanupForCollection(); 14 | }); 15 | 16 | it('should insert date', function () { 17 | editor.performCommand('date'); 18 | expect(editor.textContent()).not.toEqual(''); 19 | }); 20 | 21 | it('should insert time', function () { 22 | editor.performCommand('time'); 23 | expect(editor.textContent()).not.toEqual(''); 24 | }); 25 | }); 26 | }); -------------------------------------------------------------------------------- /stopwatch.ftplugin/pause.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CapitalizeListItems.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | // 2 | // This plugin is in response to http://support.foldingtext.com/discussions/suggestions/834-frq-transformations-make-sentence-case 3 | // 4 | Extensions.addCommand({ 5 | name: 'capitalize lists', 6 | description: 'Capitalize each selected list item.', 7 | performCommand: function (editor) { 8 | var range = editor.selectedRange(), 9 | tree = editor.tree(), 10 | type, text; 11 | 12 | tree.beginUpdates(); 13 | range.forEachNodeInRange(function (node) { 14 | type = node.type(); 15 | if (type === 'ordered' || type === 'unordered' || type === 'todo' || type == 'task') { 16 | text = node.text(); 17 | node.setText(text.charAt(0).toUpperCase() + text.slice(1)); 18 | } 19 | }); 20 | tree.endUpdates(); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /ToggleEmptyLines.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addCommand({ 2 | name: 'toggle empty lines', 3 | description: 'Toggle between no empty lines and every other line empty.', 4 | performCommand: function (editor) { 5 | var tree = editor.tree(), 6 | emptyLines = tree.evaluateNodePath('//@type empty'); 7 | 8 | tree.beginUpdates(); 9 | if (emptyLines.length > 0) { 10 | tree.removeNodes(emptyLines); 11 | } else if (tree.nodeCount() > 1) { 12 | var each = tree.firstLineNode().nextLineNode(); 13 | while (each) { 14 | tree.insertNodeBefore(tree.createNode(''), each); 15 | each = each.nextLineNode(); 16 | } 17 | } 18 | tree.endUpdates(); 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /RunScript.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Run Script', function () { 5 | var Editor = require('ft/editor/editor').Editor, 6 | editor; 7 | 8 | beforeEach(function () { 9 | editor = new Editor(''); 10 | }); 11 | 12 | afterEach(function () { 13 | editor.removeAndCleanupForCollection(); 14 | }); 15 | 16 | it('should run script', function () { 17 | editor.replaceSelection('1 + 2', 'around'); 18 | expect(editor.performCommand('run script')).toEqual(3); 19 | }); 20 | 21 | it('should run script function', function () { 22 | editor.replaceSelection('function(editor) { return editor.selectedText() }', 'around'); 23 | expect(editor.performCommand('run script')).toEqual(editor.selectedText()); 24 | }); 25 | }); 26 | }); -------------------------------------------------------------------------------- /RunScript.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addCommand({ 2 | name: 'run script', 3 | description: 'Run the selected text as a javascript function.', 4 | performCommand: function (editor) { 5 | var script = editor.selectedText(), 6 | result; 7 | 8 | try { 9 | var wrappedScript = '(' + script + ')'; 10 | result = eval(wrappedScript); 11 | if (typeof (result) == "function") { 12 | result = result(editor); 13 | } 14 | } catch (e) { 15 | result = e.toString(); 16 | } 17 | 18 | var range = editor.selectedRange().rangeByCollapsing(); 19 | editor.setSelectedRange(range); 20 | editor.replaceSelection(result + '', 'around'); 21 | 22 | return result; 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /DateAndTime.ftplugin/readme.md: -------------------------------------------------------------------------------- 1 | 2 | Opening paragraph, with an ordered list of autumn leaves I found 3 | 4 | 1. A big leaf 5 | 1. Some small leaves: 6 | 1. Red (nested) 7 | 2. **Orange** 8 | 3. Yellow 9 | 1. A medium sized leaf that ~~maybe~~ was pancake shaped 10 | 11 | Unordered list of fruits: 12 | 13 | - Blueberries 14 | - Apples 15 | - Macintosh 16 | - Honey crisp 17 | - Cortland 18 | - Banana 19 | 20 | ### Fancy Header Title 21 | 22 | Here's what someone said: 23 | 24 | > I think blockquotes are cool 25 | 26 | Nesting **an *[emphasized link](https://apolloapp.io)* inside strong text**, neato! 27 | 28 | And then they mentiond code around 'NSAttributedString' that looked like this code block: 29 | 30 | ```swift 31 | func yeah() -> NSAttributedString { 32 | // TODO: Write code 33 | } 34 | ``` 35 | 36 | Tables are even supported but (but need more than NSAttributedString' for support :p) 37 | -------------------------------------------------------------------------------- /MakeSentenceCase.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | // 2 | // This plugin is in response to http://support.foldingtext.com/discussions/suggestions/834-frq-transformations-make-sentence-case 3 | // 4 | Extensions.addCommand({ 5 | name: 'capitalize lists', 6 | description: 'Capitalize each selected list item.', 7 | performCommand: (editor) => { 8 | var range = editor.selectedRange(), 9 | tree = editor.tree(), 10 | type, text; 11 | 12 | tree.beginUpdates(); 13 | range.forEachNodeInRange(function (node) { 14 | type = node.type(); 15 | if (type === 'ordered' || type === 'unordered' || type === 'todo' || type === 'task') { 16 | text = node.text(); 17 | if (text.length > 0) { 18 | node.setText(text.charAt(0).toUpperCase() + text.slice(1)); 19 | } 20 | } 21 | }); 22 | tree.endUpdates(); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /toggle tags.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Toggle Tags', function () { 5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy, 6 | Taxonomies = require('ft/core/taxonomies'), 7 | Editor = require('ft/editor/editor').Editor, 8 | taxonomy = Taxonomies.taxonomy({ 9 | foldingtext: true, 10 | multimarkdown: true, 11 | gitmarkdown: true, 12 | criticMarkup: true 13 | }, 'markdown'), 14 | editor; 15 | 16 | beforeEach(function () { 17 | editor = new Editor('', taxonomy); 18 | }); 19 | 20 | afterEach(function () { 21 | editor.removeAndCleanupForCollection(); 22 | }); 23 | 24 | it('should toggle tags', function () { 25 | editor.setTextContent('hello'); 26 | editor.performCommand('toggleToday'); 27 | expect(editor.textContent()).toEqual('hello @today'); 28 | editor.performCommand('toggleToday'); 29 | expect(editor.textContent()).toEqual('hello'); 30 | }); 31 | }); 32 | }); -------------------------------------------------------------------------------- /WikiLinks.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | // 2 | // This plugin is in response to 3 | // 4 | var wikiLinkRE = /\[\[(.*?)\]\]/g; 5 | 6 | Extensions.add('com.foldingtext.taxonomy.classifier', { 7 | classify: function (text, state, previousState) { 8 | var escapedText = text.escapedText(), 9 | match; 10 | 11 | if (escapedText.indexOf(']]') === -1) { 12 | return; 13 | } 14 | 15 | while ((match = wikiLinkRE.exec(escapedText))) { 16 | var linkText = match[0], 17 | linktarget = 'nv://' + encodeURI(match[1]); 18 | 19 | text.addAttributeInRange('keyword', '[[', match.index, 2); 20 | text.addAttributeInRange('wikilink', linkText, match.index, linkText.length); 21 | text.addAttributeInRange('linktarget', linktarget, match.index + 2, linkText.length - 4); 22 | text.addAttributeInRange('keyword', ']]', match.index + linkText.length - 2, 2); 23 | } 24 | }, 25 | attributesToClear: ['wikilink'] 26 | }); 27 | -------------------------------------------------------------------------------- /CreateListItems.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Capitalize List Items', function () { 5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy, 6 | Taxonomies = require('ft/core/taxonomies'), 7 | Editor = require('ft/editor/editor').Editor, 8 | taxonomy = Taxonomies.taxonomy({ 9 | foldingtext: true, 10 | multimarkdown: true, 11 | gitmarkdown: true, 12 | criticMarkup: true 13 | }, 'markdown'), 14 | editor; 15 | 16 | beforeEach(function () { 17 | editor = new Editor('', taxonomy); 18 | }); 19 | 20 | afterEach(function () { 21 | editor.removeAndCleanupForCollection(); 22 | }); 23 | 24 | it('should capitlize each list item', function () { 25 | editor.setTextContent('line\n\n- one\n- two'); 26 | editor.tree().ensureClassified(); 27 | editor.performCommand('selectAll'); 28 | editor.performCommand('capitalize lists'); 29 | expect(editor.textContent()).toEqual('line\n\n- One\n- Two'); 30 | }); 31 | }); 32 | }); -------------------------------------------------------------------------------- /CapitalizeListItems.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Capitalize List Items', function () { 5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy, 6 | Taxonomies = require('ft/core/taxonomies'), 7 | Editor = require('ft/editor/editor').Editor, 8 | taxonomy = Taxonomies.taxonomy({ 9 | foldingtext: true, 10 | multimarkdown: true, 11 | gitmarkdown: true, 12 | criticMarkup: true 13 | }, 'markdown'), 14 | editor; 15 | 16 | beforeEach(function () { 17 | editor = new Editor('', taxonomy); 18 | }); 19 | 20 | afterEach(function () { 21 | editor.removeAndCleanupForCollection(); 22 | }); 23 | 24 | it('should capitlize each list item', function () { 25 | editor.setTextContent('line\n\n- one\n- two'); 26 | editor.tree().ensureClassified(); 27 | editor.performCommand('selectAll'); 28 | editor.performCommand('capitalize lists'); 29 | expect(editor.textContent()).toEqual('line\n\n- One\n- Two'); 30 | }); 31 | }); 32 | }); -------------------------------------------------------------------------------- /MakeSentenceCase.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Capitalize List Items', function () { 5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy, 6 | Taxonomies = require('ft/core/taxonomies'), 7 | Editor = require('ft/editor/editor').Editor, 8 | taxonomy = Taxonomies.taxonomy({ 9 | foldingtext: true, 10 | multimarkdown: true, 11 | gitmarkdown: true, 12 | criticMarkup: true 13 | }, 'markdown'), 14 | editor; 15 | 16 | beforeEach(function () { 17 | editor = new Editor('', taxonomy); 18 | }); 19 | 20 | afterEach(function () { 21 | editor.removeAndCleanupForCollection(); 22 | }); 23 | 24 | it('should capitlize each list item', function () { 25 | editor.setTextContent('line\n\n- one\n- two'); 26 | editor.tree().ensureClassified(); 27 | editor.performCommand('selectAll'); 28 | editor.performCommand('capitalize lists'); 29 | expect(editor.textContent()).toEqual('line\n\n- One\n- Two'); 30 | }); 31 | }); 32 | }); -------------------------------------------------------------------------------- /WikiLinks.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Wiki Links', function () { 5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy, 6 | Taxonomies = require('ft/core/taxonomies'), 7 | Editor = require('ft/editor/editor').Editor, 8 | taxonomy = Taxonomies.taxonomy({ 9 | foldingtext: true, 10 | multimarkdown: true, 11 | gitmarkdown: true, 12 | criticMarkup: true 13 | }, 'markdown'), 14 | editor; 15 | 16 | beforeEach(function () { 17 | editor = new Editor('', taxonomy); 18 | }); 19 | 20 | afterEach(function () { 21 | editor.removeAndCleanupForCollection(); 22 | }); 23 | 24 | it('should find wiki links tags', function () { 25 | editor.setTextContent('hello [[world]]'); 26 | editor.tree().ensureClassified(); 27 | expect(editor.tree().firstLineNode().lineAttributedString().toString()).toEqual('(hello /text)([[/keyword, text, wikilink)(world/linktarget, text, wikilink)(]]/keyword, text, wikilink)'); 28 | }); 29 | }); 30 | }); -------------------------------------------------------------------------------- /ToggleEmptyLines.ftplugin/spec.js: -------------------------------------------------------------------------------- 1 | define(function (require) { 2 | 'use strict'; 3 | 4 | describe('Toggle Empty Lines', function () { 5 | var MarkdownTaxonomy = require('ft/taxonomy/markdowntaxonomy').MarkdownTaxonomy, 6 | Taxonomies = require('ft/core/taxonomies'), 7 | Editor = require('ft/editor/editor').Editor, 8 | taxonomy = Taxonomies.taxonomy({ 9 | foldingtext: true, 10 | multimarkdown: true, 11 | gitmarkdown: true, 12 | criticMarkup: true 13 | }, 'markdown'), 14 | editor; 15 | 16 | beforeEach(function () { 17 | editor = new Editor('', taxonomy); 18 | }); 19 | 20 | afterEach(function () { 21 | editor.removeAndCleanupForCollection(); 22 | }); 23 | 24 | it('should toggle empty lines', function () { 25 | editor.replaceSelection('a\nb\nc', 'around'); 26 | editor.performCommand('toggle empty lines'); 27 | expect(editor.textContent()).toEqual('a\n\nb\n\nc'); 28 | editor.performCommand('toggle empty lines'); 29 | expect(editor.textContent()).toEqual('a\nb\nc'); 30 | }); 31 | }); 32 | }); -------------------------------------------------------------------------------- /SpeedUp.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | // 2 | // http://support.foldingtext.com/t/plugin-for-write-or-it-will-be-erased-mode/520 3 | // 4 | var isSpeedUp, 5 | timeoutID, 6 | ignore; 7 | 8 | Extensions.addTreeChanged(function (editor, e) { 9 | if (!editor.option('speedUp')) { 10 | return; 11 | } 12 | 13 | if (timeoutID) { 14 | clearTimeout(timeoutID); 15 | } 16 | 17 | if (!ignore) { 18 | timeoutID = setTimeout(function () { 19 | if (!editor.option('speedUp')) { 20 | return; 21 | } 22 | ignore = true; 23 | editor.setTextContent('SPEED UP!\n- To get your work back UNDO!\n- To stop this crazyness Edit > Run Command > End Speed Up!'); 24 | ignore = false; 25 | }, 5000); 26 | } 27 | }); 28 | 29 | Extensions.addCommand({ 30 | name: 'begin speed up', 31 | description: 'Begin "Speed Up!" session', 32 | performCommand: function (editor) { 33 | editor.setOption('speedUp', true); 34 | } 35 | }); 36 | 37 | Extensions.addCommand({ 38 | name: 'end speed up', 39 | description: 'End "Speed Up!" session', 40 | performCommand: function (editor) { 41 | editor.setOption('speedUp', false); 42 | } 43 | }); 44 | -------------------------------------------------------------------------------- /toggle tags.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | Extensions.addCommand({ 2 | name: 'toggleDone', 3 | keymap: 'Cmd-D', 4 | description: 'Toggle @done tag for selected lines.', 5 | performCommand: (editor) => { 6 | editor.toggleTag('done', new Date().toISOString().substr(0, 10)); 7 | } 8 | }); 9 | 10 | Extensions.addCommand({ 11 | name: 'toggleToday', 12 | keymap: 'Cmd-T', 13 | description: 'Toggle @today tag for selected lines.', 14 | performCommand: (editor) => { 15 | editor.toggleTag('today'); 16 | } 17 | }); 18 | 19 | Extensions.addCommand({ 20 | name: 'toggleError', 21 | keymap: 'Shift-Cmd-E', 22 | description: 'Toggle @error tag for selected lines.', 23 | performCommand: (editor) => { 24 | editor.toggleTag('error'); 25 | } 26 | }); 27 | 28 | Extensions.addCommand({ 29 | name: 'toggleMonthly', 30 | keymap: 'Shift-Cmd-M', 31 | description: 'Toggle @monthly tag for selected lines.', 32 | performCommand: (editor) => { 33 | editor.toggleTag('monthly'); 34 | } 35 | }); 36 | 37 | Extensions.addCommand({ 38 | name: 'toggleCCMB', 39 | keymap: 'Ctrl-C', 40 | description: 'Toggle @ccmb tag for selected lines.', 41 | performCommand: (editor) => { 42 | editor.toggleTag('ccmb'); 43 | } 44 | }); 45 | 46 | Extensions.addCommand({ 47 | name: 'toggleUSMC', 48 | keymap: 'Shift-Cmd-U', 49 | description: 'Toggle @usmc tag for selected lines.', 50 | performCommand: (editor) => { 51 | editor.toggleTag('usmc'); 52 | } 53 | }); 54 | 55 | Extensions.addCommand({ 56 | name: 'newday', 57 | description: 'Insert the current date and make it a day formatted as needed', 58 | keymap: 'Shift-Cmd-N', 59 | performCommand: (editor) => { 60 | var today = new Date().toLocaleDateString(), 61 | str = "# **" + today + "** @day"; 62 | editor.replaceSelection(str, 'end'); 63 | } 64 | }); 65 | 66 | Extensions.addKeyMap({ 67 | 'Shift-Cmd-T': 'setTheme', 68 | }); 69 | 70 | -------------------------------------------------------------------------------- /characterCount.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | 'use strict'; 3 | 4 | require('ft/util/parallel'); 5 | 6 | var Extensions = require('ft/core/extensions').Extensions, 7 | element; 8 | 9 | function formatNumber(number) { 10 | return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 11 | } 12 | 13 | function updateDisplay(editor) { 14 | if (!element) { 15 | element = document.createElement('div'); 16 | document.body.insertBefore(element, document.body.firstChild); 17 | } 18 | 19 | var selectedRange = editor.selectedRange(), 20 | newInnerHTML; 21 | 22 | if (selectedRange.isCollapsed()) { 23 | element.className = 'characterCount'; 24 | newInnerHTML = formatNumber(editor.tree().textLength()) + ' Characters
'; 25 | } else { 26 | element.className = 'characterCount characterCountSelected'; 27 | newInnerHTML = formatNumber(selectedRange.length()) + ' Characters
'; 28 | } 29 | 30 | if (newInnerHTML !== element.innerHTML) { 31 | element.innerHTML = newInnerHTML; 32 | } 33 | } 34 | 35 | Extensions.addInit(function (editor) { 36 | updateDisplay(editor); 37 | }); 38 | 39 | Extensions.addTreeChanged(function (editor, e) { 40 | updateDisplay(editor); 41 | }); 42 | 43 | Extensions.addSelectionDidChange(function (editor) { 44 | updateDisplay(editor); 45 | }); 46 | 47 | /*jshint multistr:true */ 48 | Extensions.add('com.foldingtext.editor.styles', 49 | '.characterCount {\ 50 | pointer-events: none;\ 51 | position: fixed;\ 52 | top: 0.5rem;\ 53 | right: 1.5rem;\ 54 | color: @secondaryTextColor;\ 55 | z-index: 100;\ 56 | background-color: fadeout(@paperColor, 20%);\ 57 | padding: 5px;\ 58 | border-radius: 3px;\ 59 | }\ 60 | .characterCountSelected {\ 61 | color: @secondaryTextColor;\ 62 | }' 63 | ); 64 | /*jshint multistr:false */ 65 | 66 | }); 67 | -------------------------------------------------------------------------------- /CreateListItems.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | // 2 | // This plugin is in response to http://support.foldingtext.com/discussions/suggestions/834-frq-transformations-make-sentence-case 3 | // 4 | Extensions.addCommand({ 5 | name: "create unordered list", 6 | keymap: "Shift-Cmd-O", 7 | description: "Create an Unordered list of selected items.", 8 | performCommand: function (editor) { 9 | var range = editor.selectedRange(), 10 | tree = editor.tree(), 11 | type, 12 | text; 13 | 14 | tree.beginUpdates(); 15 | range.forEachNodeInRange(function (node) { 16 | type = node.type(); 17 | if (type !== "ordered" && type !== "unordered" && type !== "todo") { 18 | text = node.text(); 19 | node.setText("- " + text.charAt(0).toUpperCase() + text.slice(1)); 20 | } 21 | }); 22 | tree.endUpdates(); 23 | }, 24 | }); 25 | 26 | Extensions.addCommand({ 27 | name: "create ordered list", 28 | description: "Create an Ordered list of selected items.", 29 | performCommand: function (editor) { 30 | var range = editor.selectedRange(), 31 | tree = editor.tree(), 32 | type, 33 | text, 34 | index = 1; 35 | 36 | tree.beginUpdates(); 37 | range.forEachNodeInRange(function (node) { 38 | type = node.type(); 39 | if (type !== "ordered" && type !== "unordered" && type !== "task") { 40 | text = node.text(); 41 | node.setText( 42 | index + ". " + text.charAt(0).toUpperCase() + text.slice(1) 43 | ); 44 | index++; 45 | } 46 | }); 47 | tree.endUpdates(); 48 | }, 49 | }); 50 | 51 | Extensions.addCommand({ 52 | name: "undo list", 53 | description: "Undo an list of selected items.", 54 | keymap: "Shift-Cmd-P", 55 | performCommand: function (editor) { 56 | var range = editor.selectedRange(), 57 | tree = editor.tree(), 58 | type, 59 | text; 60 | 61 | tree.beginUpdates(); 62 | range.forEachNodeInRange(function (node) { 63 | type = node.type(); 64 | if (type === "ordered" || type === "unordered" || type === "task") { 65 | node.setType("body"); 66 | } 67 | }); 68 | tree.endUpdates(); 69 | }, 70 | }); 71 | 72 | // Extensions.addInit(function (editor) { 73 | // editor.addKeyMap({ 74 | // 'Shift-Cmd-O': 'create unordered list', 75 | // 'Shift-Cmd-P': 'undo list', 76 | // }); 77 | -------------------------------------------------------------------------------- /FilteringWordCount.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Alternative word count approach that tracks counts per node. This makes it possible 3 | * to filter certain node types out of the count, and to exclude trailing tags and other 4 | * syntax from the count. 5 | */ 6 | var nodeIDsToLastCount = {}, 7 | totalWordCount = 0, 8 | element; 9 | 10 | function updateDisplay(editor) { 11 | if (!element) { 12 | element = document.createElement('div'); 13 | element.className = 'filteringWordCount'; 14 | document.body.appendChild(element); 15 | } 16 | 17 | var newInnerHTML = totalWordCount + ' Words
'; 18 | if (newInnerHTML !== element.innerHTML) { 19 | element.innerHTML = newInnerHTML; 20 | } 21 | } 22 | 23 | function updateAndReturnWordCountForNode(node) { 24 | var text; 25 | if (node.type() !== 'blockquote') { 26 | text = node.text(); 27 | } 28 | 29 | var match = text ? text.match(/\S+/g) : null, 30 | newWordCount = match ? match.length : 0; 31 | nodeIDsToLastCount[node.id] = newWordCount; 32 | return newWordCount; 33 | } 34 | 35 | Extensions.addInit(function (editor) { 36 | var each = editor.tree().firstLineNode(); 37 | while (each) { 38 | totalWordCount += updateAndReturnWordCountForNode(each); 39 | each = each.nextLineNode(); 40 | } 41 | }); 42 | 43 | Extensions.addTreeChanged(function (editor, e) { 44 | var deltas = e.deltas, 45 | deletasLength = deltas.length; 46 | for (var i = 0; i < deletasLength; i++) { 47 | var eachDelta = deltas[i], 48 | updatedNode = eachDelta.updatedNode, 49 | removedNodes = eachDelta.removedNodes, 50 | insertedNodes = eachDelta.insertedNodes; 51 | 52 | if (updatedNode) { 53 | totalWordCount -= nodeIDsToLastCount[updatedNode.id]; 54 | totalWordCount += updateAndReturnWordCountForNode(updatedNode); 55 | } 56 | 57 | for (var j = 0; j < removedNodes.length; j++) { 58 | totalWordCount -= nodeIDsToLastCount[removedNodes[j].id]; 59 | delete nodeIDsToLastCount[removedNodes[j].id]; 60 | } 61 | 62 | for (var k = 0; k < insertedNodes.length; k++) { 63 | totalWordCount += updateAndReturnWordCountForNode(insertedNodes[k]); 64 | } 65 | } 66 | 67 | updateDisplay(editor); 68 | }); 69 | 70 | /*jshint multistr:true */ 71 | Extensions.add('com.foldingtext.editor.styles', 72 | '.filteringWordCount {\ 73 | pointer-events: none;\ 74 | position: fixed;\ 75 | bottom: 0.5rem;\ 76 | left: 0.5rem;\ 77 | color: @secondaryTextColor;\ 78 | }' 79 | ); 80 | /*jshint multistr:false */ 81 | -------------------------------------------------------------------------------- /stopwatch.ftplugin/main.js: -------------------------------------------------------------------------------- 1 | define(function (require, exports, module) { 2 | 'use strict'; 3 | 4 | var AmountHelper = require('ft/taxonomy/helpers/amounthelper'), 5 | Extensions = require('ft/core/extensions').Extensions, 6 | NodeSet = require('ft/core/nodeset').NodeSet, 7 | DateUtils = require('ft/util/date'), 8 | currentDate = new Date(), 9 | stopwatchs = new NodeSet(); 10 | 11 | Extensions.addMode({ 12 | name: 'stopwatch' 13 | }); 14 | 15 | function start(editor, node) { 16 | node.setPropertyNodeValue('Start', currentDate.format('mmm d, yyyy h:MM:ss TT')); 17 | } 18 | 19 | function stop(editor, node) { 20 | var tree = editor.tree(), 21 | startDate = getStartDate(node), 22 | startPropertyNode = node.propertyNode('start'), 23 | duration = formatDuration((currentDate.valueOf() - startDate.valueOf()) / 1000); 24 | 25 | tree.beginUpdates(); 26 | node.insertChildBefore(tree.createNode('- ' + duration), startPropertyNode); 27 | startPropertyNode.removeFromParent(); 28 | tree.endUpdates(); 29 | } 30 | 31 | function getStartDate(node) { 32 | var startPropertyNode = node.propertyNode('start'); 33 | if (startPropertyNode) { 34 | var value = startPropertyNode.tags().value; 35 | if (value) { 36 | return new Date(value); 37 | } 38 | } 39 | return undefined; 40 | } 41 | 42 | function formatDuration(duration, shortFormat) { 43 | var hours = Math.floor(duration / 3600), 44 | minutes = Math.floor((duration - (hours * 3600)) / 60), 45 | seconds = Math.ceil(duration - (hours * 3600) - (minutes * 60)), 46 | result = []; 47 | 48 | if (hours) { 49 | if (shortFormat) { 50 | result.push(hours + 'h'); 51 | } else { 52 | result.push(hours + ' hours'); 53 | } 54 | } 55 | if (minutes) { 56 | if (shortFormat) { 57 | result.push(minutes + 'm'); 58 | } else { 59 | result.push(minutes + ' minutes'); 60 | } 61 | } 62 | if (seconds) { 63 | if (shortFormat) { 64 | result.push(seconds + 's'); 65 | } else { 66 | result.push(seconds + ' seconds'); 67 | } 68 | } 69 | 70 | return result.join(' '); 71 | } 72 | 73 | Extensions.addRenderNode(function (editor, node, nodeRenderer) { 74 | if (node.mode() === 'stopwatch') { 75 | var widget = document.createElement('div'), 76 | button = document.createElement('span'), 77 | label = document.createElement('span'), 78 | startDate = getStartDate(node), 79 | duration = 0; 80 | 81 | widget.className = 'cm-' + 'stopwatch' + '-renderwidget'; 82 | button.className = 'button'; 83 | label.className = 'label'; 84 | 85 | widget.appendChild(label); 86 | widget.appendChild(button); 87 | 88 | if (startDate) { 89 | widget.className += ' running'; 90 | duration = (currentDate.valueOf() - startDate.valueOf()) / 1000; 91 | } else { 92 | node.children().forEach(function (each) { 93 | if (each.tags().duration) { 94 | duration += each.tags().duration; 95 | } 96 | }); 97 | } 98 | 99 | if (duration) { 100 | label.textContent = formatDuration(duration, true) + '\xA0'; 101 | } 102 | 103 | button.addEventListener('mousedown', function (e) { 104 | e.preventDefault(); 105 | }); 106 | 107 | button.addEventListener('mouseup', function (e) { 108 | e.preventDefault(); 109 | editor.tree().ensureClassified(); 110 | if (getStartDate(node)) { 111 | stop(editor, node); 112 | } else { 113 | start(editor, node); 114 | } 115 | }); 116 | 117 | nodeRenderer.renderLineWidget(widget, { 118 | overlay : true, 119 | positionWidget : function (widgetWidth, widgetHeight) { 120 | var line = node.lineNumber(), 121 | leadingSpace = node.line().match(/\s*/)[0], 122 | coords = editor.cursorCoords({ line : line, ch : leadingSpace.length}, 'div'); 123 | return { 124 | left: Math.round(coords.left - (widgetWidth + editor.defaultSpaceWidth())) + 'px' 125 | }; 126 | } 127 | }); 128 | } 129 | }); 130 | 131 | Extensions.addTreeChanged(function (editor, e) { 132 | var deltas = e.deltas; 133 | for (var i = 0; i < deltas.length; i++) { 134 | var insertedNodes = deltas[i].insertedNodes, 135 | removedNodes = deltas[i].removedNodes, 136 | updatedNode = deltas[i].updatedNode, 137 | parent, 138 | each, 139 | j; 140 | 141 | length = removedNodes.length; 142 | for (j = 0; j < length; j++) { 143 | each = removedNodes[j]; 144 | var previousParent = e.previousParent(each); 145 | if (previousParent && previousParent.mode() === 'stopwatch') { 146 | editor.setNeedsRender(previousParent); 147 | } 148 | } 149 | 150 | length = insertedNodes.length; 151 | for (j = 0; j < length; j++) { 152 | each = insertedNodes[j]; 153 | if (each.mode() === 'stopwatch') { 154 | stopwatchs.addNode(each); 155 | } else { 156 | parent = each.parent; 157 | if (parent && parent.mode() === 'stopwatch') { 158 | editor.setNeedsRender(parent); 159 | } 160 | } 161 | } 162 | 163 | if (updatedNode) { 164 | if (updatedNode.mode() === 'stopwatch') { 165 | stopwatchs.addNode(updatedNode); 166 | } else { 167 | parent = updatedNode.parent; 168 | if (parent && parent.mode() === 'stopwatch') { 169 | editor.setNeedsRender(parent); 170 | } 171 | } 172 | } 173 | } 174 | }); 175 | 176 | Extensions.add('com.foldingtext.taxonomy.classifier', { 177 | classify: function (text, state, previousState) { 178 | if (state.type === 'unordered') { 179 | var modeStack = state.modeStack; 180 | if (modeStack) { 181 | var modeRecord = modeStack.lastObject(); 182 | if (!modeRecord || modeRecord.mode !== 'stopwatch') { 183 | return; 184 | } 185 | } else { 186 | return; 187 | } 188 | 189 | var duration = AmountHelper.parseDuration(text, state, previousState); 190 | if (duration) { 191 | state.tags.duration = duration; 192 | } 193 | } 194 | }, 195 | attributesToClear: [].concat(AmountHelper.attributesToClear) 196 | }); 197 | 198 | Extensions.add('com.foldingtext.editor.clockTick', function (editor, date) { 199 | currentDate = date; 200 | stopwatchs.forEachNodeInSet(function (each) { 201 | if (!each.isTracked || each.mode() !== 'stopwatch') { 202 | stopwatchs.removeNode(each); 203 | } else { 204 | editor.setNeedsRender(each); 205 | } 206 | }); 207 | }); 208 | }); --------------------------------------------------------------------------------