/
markerManager.js
154 lines (132 loc) · 5.13 KB
/
markerManager.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// # Ghost Editor Marker Manager
//
// MarkerManager looks after the array of markers which are attached to image markdown in the editor.
//
// Marker Manager is told by the Upload Manager to add a marker to a line.
// A marker takes the form of a 'magic id' which looks like:
// {<1>}
// It is appended to the start of the given line, and then defined as a CodeMirror 'TextMarker' widget which is
// subsequently added to an array of markers to keep track of all markers in the editor.
// The TextMarker is also set to 'collapsed' mode which means it does not show up in the display.
// Currently, the markers can be seen if you copy and paste your content out of Ghost into a text editor.
// The markers are stripped on save so should not appear in the DB
/*global _, Ghost */
(function () {
'use strict';
var imageMarkdownRegex = /^(?:\{<(.*?)>\})?!(?:\[([^\n\]]*)\])(?:\(([^\n\]]*)\))?$/gim,
markerRegex = /\{<([\w\W]*?)>\}/,
MarkerManager;
MarkerManager = function (editor) {
var markers = {},
uploadPrefix = 'image_upload',
uploadId = 1,
addMarker,
removeMarker,
markerRegexForId,
stripMarkerFromLine,
findAndStripMarker,
checkMarkers,
initMarkers;
// the regex
markerRegexForId = function (id) {
id = id.replace('image_upload_', '');
return new RegExp('\\{<' + id + '>\\}', 'gmi');
};
// Add a marker to the given line
// Params:
// line - CodeMirror LineHandle
// ln - line number
addMarker = function (line, ln) {
var marker,
magicId = '{<' + uploadId + '>}',
newText = magicId + line.text;
editor.replaceRange(
newText,
{line: ln, ch: 0},
{line: ln, ch: newText.length}
);
marker = editor.markText(
{line: ln, ch: 0},
{line: ln, ch: (magicId.length)},
{collapsed: true}
);
markers[uploadPrefix + '_' + uploadId] = marker;
uploadId += 1;
};
// Remove a marker
// Will be passed a LineHandle if we already know which line the marker is on
removeMarker = function (id, marker, line) {
delete markers[id];
marker.clear();
if (line) {
stripMarkerFromLine(line);
} else {
findAndStripMarker(id);
}
};
// Removes the marker on the given line if there is one
stripMarkerFromLine = function (line) {
var markerText = line.text.match(markerRegex),
ln = editor.getLineNumber(line);
if (markerText) {
editor.replaceRange(
'',
{line: ln, ch: markerText.index},
{line: ln, ch: markerText.index + markerText[0].length}
);
}
};
// Find a marker in the editor by id & remove it
// Goes line by line to find the marker by it's text if we've lost track of the TextMarker
findAndStripMarker = function (id) {
editor.eachLine(function (line) {
var markerText = markerRegexForId(id).exec(line.text),
ln;
if (markerText) {
ln = editor.getLineNumber(line);
editor.replaceRange(
'',
{line: ln, ch: markerText.index},
{line: ln, ch: markerText.index + markerText[0].length}
);
}
});
};
// Check each marker to see if it is still present in the editor and if it still corresponds to image markdown
// If it is no longer a valid image, remove it
checkMarkers = function () {
_.each(markers, function (marker, id) {
var line;
marker = markers[id];
if (marker.find()) {
line = editor.getLineHandle(marker.find().from.line);
if (!line.text.match(imageMarkdownRegex)) {
removeMarker(id, marker, line);
}
} else {
removeMarker(id, marker);
}
});
};
// Add markers to the line if it needs one
initMarkers = function (line) {
var isImage = line.text.match(imageMarkdownRegex),
hasMarker = line.text.match(markerRegex);
if (isImage && !hasMarker) {
addMarker(line, editor.getLineNumber(line));
}
};
// Initialise
editor.eachLine(initMarkers);
// Public API
_.extend(this, {
markers: markers,
checkMarkers: checkMarkers,
addMarker: addMarker,
stripMarkerFromLine: stripMarkerFromLine,
getMarkerRegexForId: markerRegexForId
});
};
Ghost.Editor = Ghost.Editor || {};
Ghost.Editor.MarkerManager = MarkerManager;
}());