mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-21 16:06:16 -04:00
Merge pull request #599 from fourplusone/ace2_refactoring
ACE2 refactoring
This commit is contained in:
commit
57e137f65b
5 changed files with 298 additions and 208 deletions
|
@ -56,6 +56,7 @@
|
||||||
, "rjquery.js"
|
, "rjquery.js"
|
||||||
, "AttributePool.js"
|
, "AttributePool.js"
|
||||||
, "Changeset.js"
|
, "Changeset.js"
|
||||||
|
, "ChangesetUtils.js"
|
||||||
, "security.js"
|
, "security.js"
|
||||||
, "skiplist.js"
|
, "skiplist.js"
|
||||||
, "virtual_lines.js"
|
, "virtual_lines.js"
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
, "changesettracker.js"
|
, "changesettracker.js"
|
||||||
, "linestylefilter.js"
|
, "linestylefilter.js"
|
||||||
, "domline.js"
|
, "domline.js"
|
||||||
|
, "AttributeManager.js"
|
||||||
, "ace2_inner.js"
|
, "ace2_inner.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
158
src/static/js/AttributeManager.js
Normal file
158
src/static/js/AttributeManager.js
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
var Changeset = require('./Changeset');
|
||||||
|
var ChangesetUtils = require('./ChangesetUtils');
|
||||||
|
var _ = require('./underscore');
|
||||||
|
|
||||||
|
var lineMarkerAttribute = 'lmkr';
|
||||||
|
|
||||||
|
// If one of these attributes are set to the first character of a
|
||||||
|
// line it is considered as a line attribute marker i.e. attributes
|
||||||
|
// set on this marker are applied to the whole line.
|
||||||
|
// The list attribute is only maintained for compatibility reasons
|
||||||
|
var lineAttributes = [lineMarkerAttribute,'list'];
|
||||||
|
|
||||||
|
/*
|
||||||
|
The Attribute manager builds changesets based on a document
|
||||||
|
representation for setting and removing range or line-based attributes.
|
||||||
|
|
||||||
|
@param rep the document representation to be used
|
||||||
|
@param applyChangesetCallback this callback will be called
|
||||||
|
once a changeset has been built.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var AttributeManager = function(rep, applyChangesetCallback)
|
||||||
|
{
|
||||||
|
this.rep = rep;
|
||||||
|
this.applyChangesetCallback = applyChangesetCallback;
|
||||||
|
this.author = '';
|
||||||
|
|
||||||
|
// If the first char in a line has one of the following attributes
|
||||||
|
// it will be considered as a line marker
|
||||||
|
};
|
||||||
|
|
||||||
|
AttributeManager.prototype = _(AttributeManager.prototype).extend({
|
||||||
|
|
||||||
|
applyChangeset: function(changeset){
|
||||||
|
if(!this.applyChangesetCallback) return changeset;
|
||||||
|
|
||||||
|
var cs = changeset.toString();
|
||||||
|
if (!Changeset.isIdentity(cs))
|
||||||
|
{
|
||||||
|
this.applyChangesetCallback(cs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changeset;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets attributes on a range
|
||||||
|
@param start [row, col] tuple pointing to the start of the range
|
||||||
|
@param end [row, col] tuple pointing to the end of the range
|
||||||
|
@param attribute: an array of attributes
|
||||||
|
*/
|
||||||
|
setAttributesOnRange: function(start, end, attribs)
|
||||||
|
{
|
||||||
|
var builder = Changeset.builder(this.rep.lines.totalWidth());
|
||||||
|
ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, start);
|
||||||
|
ChangesetUtils.buildKeepRange(this.rep, builder, start, end, attribs, this.rep.apool);
|
||||||
|
return this.applyChangeset(builder);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns if the line already has a line marker
|
||||||
|
@param lineNum: the number of the line
|
||||||
|
*/
|
||||||
|
lineHasMarker: function(lineNum){
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
return _.find(lineAttributes, function(attribute){
|
||||||
|
return that.getAttributeOnLine(lineNum, attribute) != '';
|
||||||
|
}) !== undefined;
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Gets a specified attribute on a line
|
||||||
|
@param lineNum: the number of the line to set the attribute for
|
||||||
|
@param attributeKey: the name of the attribute to get, e.g. list
|
||||||
|
*/
|
||||||
|
getAttributeOnLine: function(lineNum, attributeName){
|
||||||
|
// get `attributeName` attribute of first char of line
|
||||||
|
var aline = this.rep.alines[lineNum];
|
||||||
|
if (aline)
|
||||||
|
{
|
||||||
|
var opIter = Changeset.opIterator(aline);
|
||||||
|
if (opIter.hasNext())
|
||||||
|
{
|
||||||
|
return Changeset.opAttributeValue(opIter.next(), attributeName, this.rep.apool) || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets a specified attribute on a line
|
||||||
|
@param lineNum: the number of the line to set the attribute for
|
||||||
|
@param attributeKey: the name of the attribute to set, e.g. list
|
||||||
|
@param attributeValue: an optional parameter to pass to the attribute (e.g. indention level)
|
||||||
|
|
||||||
|
*/
|
||||||
|
setAttributeOnLine: function(lineNum, attributeName, attributeValue){
|
||||||
|
var loc = [0,0];
|
||||||
|
var builder = Changeset.builder(this.rep.lines.totalWidth());
|
||||||
|
var hasMarker = this.lineHasMarker(lineNum);
|
||||||
|
|
||||||
|
ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 0]));
|
||||||
|
|
||||||
|
if(hasMarker){
|
||||||
|
ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 1]), [
|
||||||
|
[attributeName, attributeValue]
|
||||||
|
], this.rep.apool);
|
||||||
|
}else{
|
||||||
|
// add a line marker
|
||||||
|
builder.insert('*', [
|
||||||
|
['author', this.author],
|
||||||
|
['insertorder', 'first'],
|
||||||
|
[lineMarkerAttribute, '1'],
|
||||||
|
[attributeName, attributeValue]
|
||||||
|
], this.rep.apool);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.applyChangeset(builder);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Removes a specified attribute on a line
|
||||||
|
@param lineNum: the number of the affected line
|
||||||
|
@param attributeKey: the name of the attribute to remove, e.g. list
|
||||||
|
|
||||||
|
*/
|
||||||
|
removeAttributeOnLine: function(lineNum, attributeName, attributeValue){
|
||||||
|
|
||||||
|
var loc = [0,0];
|
||||||
|
var builder = Changeset.builder(this.rep.lines.totalWidth());
|
||||||
|
var hasMarker = this.lineHasMarker(lineNum);
|
||||||
|
|
||||||
|
if(hasMarker){
|
||||||
|
ChangesetUtils.buildKeepRange(this.rep, builder, loc, (loc = [lineNum, 0]), [
|
||||||
|
[attributeName, attributeValue]
|
||||||
|
], this.rep.apool);
|
||||||
|
ChangesetUtils.buildRemoveRange(this.rep, builder, loc, (loc = [lineNum, 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.applyChangeset(builder);
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sets a specified attribute on a line
|
||||||
|
@param lineNum: the number of the line to set the attribute for
|
||||||
|
@param attributeKey: the name of the attribute to set, e.g. list
|
||||||
|
@param attributeValue: an optional parameter to pass to the attribute (e.g. indention level)
|
||||||
|
*/
|
||||||
|
toggleAttributeOnLine: function(lineNum, attributeName, attributeValue) {
|
||||||
|
return this.getAttributeOnLine(attributeName) ?
|
||||||
|
this.removeAttributeOnLine(lineNum, attributeName) :
|
||||||
|
this.setAttributeOnLine(lineNum, attributeName, attributeValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = AttributeManager;
|
|
@ -22,6 +22,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
An AttributePool maintains a mapping from [key,value] Pairs called
|
||||||
|
Attributes to Numbers (unsigened integers) and vice versa. These numbers are
|
||||||
|
used to reference Attributes in Changesets.
|
||||||
|
*/
|
||||||
|
|
||||||
var AttributePool = function () {
|
var AttributePool = function () {
|
||||||
this.numToAttrib = {}; // e.g. {0: ['foo','bar']}
|
this.numToAttrib = {}; // e.g. {0: ['foo','bar']}
|
||||||
this.attribToNum = {}; // e.g. {'foo,bar': 0}
|
this.attribToNum = {}; // e.g. {'foo,bar': 0}
|
||||||
|
|
60
src/static/js/ChangesetUtils.js
Normal file
60
src/static/js/ChangesetUtils.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* This module contains several helper Functions to build Changesets
|
||||||
|
* based on a SkipList
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright 2009 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS-IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
exports.buildRemoveRange = function(rep, builder, start, end)
|
||||||
|
{
|
||||||
|
var startLineOffset = rep.lines.offsetOfIndex(start[0]);
|
||||||
|
var endLineOffset = rep.lines.offsetOfIndex(end[0]);
|
||||||
|
|
||||||
|
if (end[0] > start[0])
|
||||||
|
{
|
||||||
|
builder.remove(endLineOffset - startLineOffset - start[1], end[0] - start[0]);
|
||||||
|
builder.remove(end[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.remove(end[1] - start[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildKeepRange = function(rep, builder, start, end, attribs, pool)
|
||||||
|
{
|
||||||
|
var startLineOffset = rep.lines.offsetOfIndex(start[0]);
|
||||||
|
var endLineOffset = rep.lines.offsetOfIndex(end[0]);
|
||||||
|
|
||||||
|
if (end[0] > start[0])
|
||||||
|
{
|
||||||
|
builder.keep(endLineOffset - startLineOffset - start[1], end[0] - start[0], attribs, pool);
|
||||||
|
builder.keep(end[1], 0, attribs, pool);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.keep(end[1] - start[1], 0, attribs, pool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.buildKeepToStartOfRange = function(rep, builder, start)
|
||||||
|
{
|
||||||
|
var startLineOffset = rep.lines.offsetOfIndex(start[0]);
|
||||||
|
|
||||||
|
builder.keep(startLineOffset, start[0]);
|
||||||
|
builder.keep(start[1]);
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,8 @@ var isNodeText = Ace2Common.isNodeText,
|
||||||
binarySearchInfinite = Ace2Common.binarySearchInfinite,
|
binarySearchInfinite = Ace2Common.binarySearchInfinite,
|
||||||
htmlPrettyEscape = Ace2Common.htmlPrettyEscape,
|
htmlPrettyEscape = Ace2Common.htmlPrettyEscape,
|
||||||
noop = Ace2Common.noop;
|
noop = Ace2Common.noop;
|
||||||
|
var hooks = require('./pluginfw/hooks');
|
||||||
|
|
||||||
|
|
||||||
function Ace2Inner(){
|
function Ace2Inner(){
|
||||||
|
|
||||||
|
@ -45,10 +47,12 @@ function Ace2Inner(){
|
||||||
var domline = require('./domline').domline;
|
var domline = require('./domline').domline;
|
||||||
var AttribPool = require('./AttributePool');
|
var AttribPool = require('./AttributePool');
|
||||||
var Changeset = require('./Changeset');
|
var Changeset = require('./Changeset');
|
||||||
|
var ChangesetUtils = require('./ChangesetUtils');
|
||||||
var linestylefilter = require('./linestylefilter').linestylefilter;
|
var linestylefilter = require('./linestylefilter').linestylefilter;
|
||||||
var SkipList = require('./skiplist');
|
var SkipList = require('./skiplist');
|
||||||
var undoModule = require('./undomodule').undoModule;
|
var undoModule = require('./undomodule').undoModule;
|
||||||
var makeVirtualLineView = require('./virtual_lines').makeVirtualLineView;
|
var makeVirtualLineView = require('./virtual_lines').makeVirtualLineView;
|
||||||
|
var AttributeManager = require('./AttributeManager');
|
||||||
|
|
||||||
var DEBUG = false; //$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;"
|
var DEBUG = false; //$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;"
|
||||||
// changed to false
|
// changed to false
|
||||||
|
@ -78,14 +82,11 @@ function Ace2Inner(){
|
||||||
var overlaysdiv = lineMetricsDiv.nextSibling;
|
var overlaysdiv = lineMetricsDiv.nextSibling;
|
||||||
initLineNumbers();
|
initLineNumbers();
|
||||||
|
|
||||||
var outsideKeyDown = function(evt)
|
var outsideKeyDown = noop;
|
||||||
{};
|
|
||||||
var outsideKeyPress = function(evt)
|
var outsideKeyPress = function(){return true;};
|
||||||
{
|
|
||||||
return true;
|
var outsideNotifyDirty = noop;
|
||||||
};
|
|
||||||
var outsideNotifyDirty = function()
|
|
||||||
{};
|
|
||||||
|
|
||||||
// selFocusAtStart -- determines whether the selection extends "backwards", so that the focus
|
// selFocusAtStart -- determines whether the selection extends "backwards", so that the focus
|
||||||
// point (controlled with the arrow keys) is at the beginning; not supported in IE, though
|
// point (controlled with the arrow keys) is at the beginning; not supported in IE, though
|
||||||
|
@ -100,6 +101,7 @@ function Ace2Inner(){
|
||||||
alines: [],
|
alines: [],
|
||||||
apool: new AttribPool()
|
apool: new AttribPool()
|
||||||
};
|
};
|
||||||
|
|
||||||
// lines, alltext, alines, and DOM are set up in setup()
|
// lines, alltext, alines, and DOM are set up in setup()
|
||||||
if (undoModule.enabled)
|
if (undoModule.enabled)
|
||||||
{
|
{
|
||||||
|
@ -119,6 +121,7 @@ function Ace2Inner(){
|
||||||
iframePadRight = 0;
|
iframePadRight = 0;
|
||||||
|
|
||||||
var console = (DEBUG && window.console);
|
var console = (DEBUG && window.console);
|
||||||
|
var documentAttributeManager;
|
||||||
|
|
||||||
if (!window.console)
|
if (!window.console)
|
||||||
{
|
{
|
||||||
|
@ -155,6 +158,7 @@ function Ace2Inner(){
|
||||||
|
|
||||||
var textFace = 'monospace';
|
var textFace = 'monospace';
|
||||||
var textSize = 12;
|
var textSize = 12;
|
||||||
|
|
||||||
|
|
||||||
function textLineHeight()
|
function textLineHeight()
|
||||||
{
|
{
|
||||||
|
@ -929,7 +933,10 @@ function Ace2Inner(){
|
||||||
},
|
},
|
||||||
grayedout: setClassPresenceNamed(outerWin.document.body, "grayedout"),
|
grayedout: setClassPresenceNamed(outerWin.document.body, "grayedout"),
|
||||||
dmesg: function(){ dmesg = window.dmesg = value; },
|
dmesg: function(){ dmesg = window.dmesg = value; },
|
||||||
userauthor: function(value){ thisAuthor = String(value); },
|
userauthor: function(value){
|
||||||
|
thisAuthor = String(value);
|
||||||
|
documentAttributeManager.author = thisAuthor;
|
||||||
|
},
|
||||||
styled: setStyled,
|
styled: setStyled,
|
||||||
textface: setTextFace,
|
textface: setTextFace,
|
||||||
textsize: setTextSize,
|
textsize: setTextSize,
|
||||||
|
@ -1864,55 +1871,6 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function setupMozillaCaretHack(lineNum)
|
|
||||||
{
|
|
||||||
// This is really ugly, but by god, it works!
|
|
||||||
// Fixes annoying Firefox caret artifact (observed in 2.0.0.12
|
|
||||||
// and unfixed in Firefox 2 as of now) where mutating the DOM
|
|
||||||
// and then moving the caret to the beginning of a line causes
|
|
||||||
// an image of the caret to be XORed at the top of the iframe.
|
|
||||||
// The previous solution involved remembering to set the selection
|
|
||||||
// later, in response to the next event in the queue, which was hugely
|
|
||||||
// annoying.
|
|
||||||
// This solution: add a space character (0x20) to the beginning of the line.
|
|
||||||
// After setting the selection, remove the space.
|
|
||||||
var lineNode = rep.lines.atIndex(lineNum).lineNode;
|
|
||||||
|
|
||||||
var fc = lineNode.firstChild;
|
|
||||||
while (isBlockElement(fc) && fc.firstChild)
|
|
||||||
{
|
|
||||||
fc = fc.firstChild;
|
|
||||||
}
|
|
||||||
var textNode;
|
|
||||||
if (isNodeText(fc))
|
|
||||||
{
|
|
||||||
fc.nodeValue = " " + fc.nodeValue;
|
|
||||||
textNode = fc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
textNode = doc.createTextNode(" ");
|
|
||||||
fc.parentNode.insertBefore(textNode, fc);
|
|
||||||
}
|
|
||||||
markNodeClean(lineNode);
|
|
||||||
return {
|
|
||||||
unhack: function()
|
|
||||||
{
|
|
||||||
if (textNode.nodeValue == " ")
|
|
||||||
{
|
|
||||||
textNode.parentNode.removeChild(textNode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
textNode.nodeValue = textNode.nodeValue.substring(1);
|
|
||||||
}
|
|
||||||
markNodeClean(lineNode);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function getPointForLineAndChar(lineAndChar)
|
function getPointForLineAndChar(lineAndChar)
|
||||||
{
|
{
|
||||||
var line = lineAndChar[0];
|
var line = lineAndChar[0];
|
||||||
|
@ -2247,6 +2205,9 @@ function Ace2Inner(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Converts the position of a char (index in String) into a [row, col] tuple
|
||||||
|
*/
|
||||||
function lineAndColumnFromChar(x)
|
function lineAndColumnFromChar(x)
|
||||||
{
|
{
|
||||||
var lineEntry = rep.lines.atOffset(x);
|
var lineEntry = rep.lines.atOffset(x);
|
||||||
|
@ -2301,8 +2262,8 @@ function Ace2Inner(){
|
||||||
// CCCC\n
|
// CCCC\n
|
||||||
// end[0]: <CCC end[1] CCC>-------\n
|
// end[0]: <CCC end[1] CCC>-------\n
|
||||||
var builder = Changeset.builder(rep.lines.totalWidth());
|
var builder = Changeset.builder(rep.lines.totalWidth());
|
||||||
buildKeepToStartOfRange(builder, start);
|
ChangesetUtils.buildKeepToStartOfRange(rep, builder, start);
|
||||||
buildRemoveRange(builder, start, end);
|
ChangesetUtils.buildRemoveRange(rep, builder, start, end);
|
||||||
builder.insert(newText, [
|
builder.insert(newText, [
|
||||||
['author', thisAuthor]
|
['author', thisAuthor]
|
||||||
], rep.apool);
|
], rep.apool);
|
||||||
|
@ -2313,69 +2274,17 @@ function Ace2Inner(){
|
||||||
|
|
||||||
function performDocumentApplyAttributesToCharRange(start, end, attribs)
|
function performDocumentApplyAttributesToCharRange(start, end, attribs)
|
||||||
{
|
{
|
||||||
if (end >= rep.alltext.length)
|
end = Math.min(end, rep.alltext.length - 1);
|
||||||
{
|
documentAttributeManager.setAttributesOnRange(lineAndColumnFromChar(start), lineAndColumnFromChar(end), attribs);
|
||||||
end = rep.alltext.length - 1;
|
|
||||||
}
|
|
||||||
performDocumentApplyAttributesToRange(lineAndColumnFromChar(start), lineAndColumnFromChar(end), attribs);
|
|
||||||
}
|
}
|
||||||
editorInfo.ace_performDocumentApplyAttributesToCharRange = performDocumentApplyAttributesToCharRange;
|
editorInfo.ace_performDocumentApplyAttributesToCharRange = performDocumentApplyAttributesToCharRange;
|
||||||
|
|
||||||
function performDocumentApplyAttributesToRange(start, end, attribs)
|
|
||||||
{
|
|
||||||
var builder = Changeset.builder(rep.lines.totalWidth());
|
|
||||||
buildKeepToStartOfRange(builder, start);
|
|
||||||
buildKeepRange(builder, start, end, attribs, rep.apool);
|
|
||||||
var cs = builder.toString();
|
|
||||||
performDocumentApplyChangeset(cs);
|
|
||||||
}
|
|
||||||
editorInfo.ace_performDocumentApplyAttributesToRange = performDocumentApplyAttributesToRange;
|
|
||||||
|
|
||||||
function buildKeepToStartOfRange(builder, start)
|
|
||||||
{
|
|
||||||
var startLineOffset = rep.lines.offsetOfIndex(start[0]);
|
|
||||||
|
|
||||||
builder.keep(startLineOffset, start[0]);
|
|
||||||
builder.keep(start[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildRemoveRange(builder, start, end)
|
|
||||||
{
|
|
||||||
var startLineOffset = rep.lines.offsetOfIndex(start[0]);
|
|
||||||
var endLineOffset = rep.lines.offsetOfIndex(end[0]);
|
|
||||||
|
|
||||||
if (end[0] > start[0])
|
|
||||||
{
|
|
||||||
builder.remove(endLineOffset - startLineOffset - start[1], end[0] - start[0]);
|
|
||||||
builder.remove(end[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.remove(end[1] - start[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildKeepRange(builder, start, end, attribs, pool)
|
|
||||||
{
|
|
||||||
var startLineOffset = rep.lines.offsetOfIndex(start[0]);
|
|
||||||
var endLineOffset = rep.lines.offsetOfIndex(end[0]);
|
|
||||||
|
|
||||||
if (end[0] > start[0])
|
|
||||||
{
|
|
||||||
builder.keep(endLineOffset - startLineOffset - start[1], end[0] - start[0], attribs, pool);
|
|
||||||
builder.keep(end[1], 0, attribs, pool);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.keep(end[1] - start[1], 0, attribs, pool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setAttributeOnSelection(attributeName, attributeValue)
|
function setAttributeOnSelection(attributeName, attributeValue)
|
||||||
{
|
{
|
||||||
if (!(rep.selStart && rep.selEnd)) return;
|
if (!(rep.selStart && rep.selEnd)) return;
|
||||||
|
|
||||||
performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd, [
|
documentAttributeManager.setAttributesOnRange(rep.selStart, rep.selEnd, [
|
||||||
[attributeName, attributeValue]
|
[attributeName, attributeValue]
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -2436,13 +2345,13 @@ function Ace2Inner(){
|
||||||
|
|
||||||
if (selectionAllHasIt)
|
if (selectionAllHasIt)
|
||||||
{
|
{
|
||||||
performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd, [
|
documentAttributeManager.setAttributesOnRange(rep.selStart, rep.selEnd, [
|
||||||
[attributeName, '']
|
[attributeName, '']
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
performDocumentApplyAttributesToRange(rep.selStart, rep.selEnd, [
|
documentAttributeManager.setAttributesOnRange(rep.selStart, rep.selEnd, [
|
||||||
[attributeName, 'true']
|
[attributeName, 'true']
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -2964,6 +2873,10 @@ function Ace2Inner(){
|
||||||
"ul": 1
|
"ul": 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_.each(hooks.callAll('aceRegisterBlockElements'), function(element){
|
||||||
|
_blockElems[element] = 1;
|
||||||
|
})
|
||||||
|
|
||||||
function isBlockElement(n)
|
function isBlockElement(n)
|
||||||
{
|
{
|
||||||
return !!_blockElems[(n.tagName || "").toLowerCase()];
|
return !!_blockElems[(n.tagName || "").toLowerCase()];
|
||||||
|
@ -3328,6 +3241,7 @@ function Ace2Inner(){
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lineNum = rep.selStart[0];
|
var lineNum = rep.selStart[0];
|
||||||
var listType = getLineListType(lineNum);
|
var listType = getLineListType(lineNum);
|
||||||
|
|
||||||
|
@ -3399,11 +3313,9 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mods.length > 0)
|
_.each(mods, function(mod){
|
||||||
{
|
setLineListType(mod[0], mod[1]);
|
||||||
setLineListTypes(mods);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
editorInfo.ace_doIndentOutdent = doIndentOutdent;
|
editorInfo.ace_doIndentOutdent = doIndentOutdent;
|
||||||
|
@ -3818,26 +3730,17 @@ function Ace2Inner(){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mozillaCaretHack = (false && browser.mozilla && selStart && selEnd && selStart[0] == selEnd[0] && selStart[1] == rep.lines.atIndex(selStart[0]).lineMarker && selEnd[1] == rep.lines.atIndex(selEnd[0]).lineMarker && setupMozillaCaretHack(selStart[0]));
|
|
||||||
|
|
||||||
var selection = {};
|
var selection = {};
|
||||||
|
|
||||||
var ss = [selStart[0], selStart[1]];
|
var ss = [selStart[0], selStart[1]];
|
||||||
if (mozillaCaretHack) ss[1] += 1;
|
|
||||||
selection.startPoint = getPointForLineAndChar(ss);
|
selection.startPoint = getPointForLineAndChar(ss);
|
||||||
|
|
||||||
var se = [selEnd[0], selEnd[1]];
|
var se = [selEnd[0], selEnd[1]];
|
||||||
if (mozillaCaretHack) se[1] += 1;
|
|
||||||
selection.endPoint = getPointForLineAndChar(se);
|
selection.endPoint = getPointForLineAndChar(se);
|
||||||
|
|
||||||
selection.focusAtStart = !! rep.selFocusAtStart;
|
selection.focusAtStart = !! rep.selFocusAtStart;
|
||||||
|
|
||||||
setSelection(selection);
|
setSelection(selection);
|
||||||
|
|
||||||
if (mozillaCaretHack)
|
|
||||||
{
|
|
||||||
mozillaCaretHack.unhack();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRepHTML()
|
function getRepHTML()
|
||||||
|
@ -4926,27 +4829,30 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var listAttributeName = 'list';
|
||||||
|
|
||||||
function getLineListType(lineNum)
|
function getLineListType(lineNum)
|
||||||
{
|
{
|
||||||
// get "list" attribute of first char of line
|
return documentAttributeManager.getAttributeOnLine(lineNum, listAttributeName)
|
||||||
var aline = rep.alines[lineNum];
|
|
||||||
if (aline)
|
|
||||||
{
|
|
||||||
var opIter = Changeset.opIterator(aline);
|
|
||||||
if (opIter.hasNext())
|
|
||||||
{
|
|
||||||
return Changeset.opAttributeValue(opIter.next(), 'list', rep.apool) || '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLineListType(lineNum, listType)
|
function setLineListType(lineNum, listType)
|
||||||
{
|
{
|
||||||
setLineListTypes([
|
if(listType == ''){
|
||||||
[lineNum, listType]
|
documentAttributeManager.removeAttributeOnLine(lineNum, listAttributeName);
|
||||||
]);
|
}else{
|
||||||
|
documentAttributeManager.setAttributeOnLine(lineNum, listAttributeName, listType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the list has been removed, it is necessary to renumber
|
||||||
|
//starting from the *next* line because the list may have been
|
||||||
|
//separated. If it returns null, it means that the list was not cut, try
|
||||||
|
//from the current one.
|
||||||
|
if(renumberList(lineNum+1)==null)
|
||||||
|
{
|
||||||
|
renumberList(lineNum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renumberList(lineNum){
|
function renumberList(lineNum){
|
||||||
|
@ -4993,8 +4899,8 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
else if(curLevel == level)
|
else if(curLevel == level)
|
||||||
{
|
{
|
||||||
buildKeepRange(builder, loc, (loc = [line, 0]));
|
ChangesetUtils.buildKeepRange(rep, builder, loc, (loc = [line, 0]));
|
||||||
buildKeepRange(builder, loc, (loc = [line, 1]), [
|
ChangesetUtils.buildKeepRange(rep, builder, loc, (loc = [line, 1]), [
|
||||||
['start', position]
|
['start', position]
|
||||||
], rep.apool);
|
], rep.apool);
|
||||||
|
|
||||||
|
@ -5025,62 +4931,6 @@ function Ace2Inner(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLineListTypes(lineNumTypePairsInOrder)
|
|
||||||
{
|
|
||||||
var loc = [0, 0];
|
|
||||||
var builder = Changeset.builder(rep.lines.totalWidth());
|
|
||||||
for (var i = 0; i < lineNumTypePairsInOrder.length; i++)
|
|
||||||
{
|
|
||||||
var pair = lineNumTypePairsInOrder[i];
|
|
||||||
var lineNum = pair[0];
|
|
||||||
var listType = pair[1];
|
|
||||||
buildKeepRange(builder, loc, (loc = [lineNum, 0]));
|
|
||||||
if (getLineListType(lineNum))
|
|
||||||
{
|
|
||||||
// already a line marker
|
|
||||||
if (listType)
|
|
||||||
{
|
|
||||||
// make different list type
|
|
||||||
buildKeepRange(builder, loc, (loc = [lineNum, 1]), [
|
|
||||||
['list', listType]
|
|
||||||
], rep.apool);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// remove list marker
|
|
||||||
buildRemoveRange(builder, loc, (loc = [lineNum, 1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// currently no line marker
|
|
||||||
if (listType)
|
|
||||||
{
|
|
||||||
// add a line marker
|
|
||||||
builder.insert('*', [
|
|
||||||
['author', thisAuthor],
|
|
||||||
['insertorder', 'first'],
|
|
||||||
['list', listType]
|
|
||||||
], rep.apool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var cs = builder.toString();
|
|
||||||
if (!Changeset.isIdentity(cs))
|
|
||||||
{
|
|
||||||
performDocumentApplyChangeset(cs);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if the list has been removed, it is necessary to renumber
|
|
||||||
//starting from the *next* line because the list may have been
|
|
||||||
//separated. If it returns null, it means that the list was not cut, try
|
|
||||||
//from the current one.
|
|
||||||
if(renumberList(lineNum+1)==null)
|
|
||||||
{
|
|
||||||
renumberList(lineNum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function doInsertList(type)
|
function doInsertList(type)
|
||||||
{
|
{
|
||||||
|
@ -5118,7 +4968,10 @@ function Ace2Inner(){
|
||||||
var t = getLineListType(n);
|
var t = getLineListType(n);
|
||||||
mods.push([n, allLinesAreList ? 'indent' + level : (t ? type + level : type + '1')]);
|
mods.push([n, allLinesAreList ? 'indent' + level : (t ? type + level : type + '1')]);
|
||||||
}
|
}
|
||||||
setLineListTypes(mods);
|
|
||||||
|
_.each(mods, function(mod){
|
||||||
|
setLineListType(mod[0], mod[1]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function doInsertUnorderedList(){
|
function doInsertUnorderedList(){
|
||||||
|
@ -5538,6 +5391,11 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Init documentAttributeManager
|
||||||
|
documentAttributeManager = new AttributeManager(rep, performDocumentApplyChangeset);
|
||||||
|
editorInfo.ace_performDocumentApplyAttributesToRange = documentAttributeManager.setAttributesOnRange;
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
doc = document; // defined as a var in scope outside
|
doc = document; // defined as a var in scope outside
|
||||||
|
@ -5577,7 +5435,13 @@ function Ace2Inner(){
|
||||||
bindTheEventHandlers();
|
bindTheEventHandlers();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hooks.callAll('aceInitialized', {
|
||||||
|
editorInfo: editorInfo,
|
||||||
|
rep: rep,
|
||||||
|
documentAttributeManager: documentAttributeManager
|
||||||
|
});
|
||||||
|
|
||||||
scheduler.setTimeout(function()
|
scheduler.setTimeout(function()
|
||||||
{
|
{
|
||||||
parent.readyFunc(); // defined in code that sets up the inner iframe
|
parent.readyFunc(); // defined in code that sets up the inner iframe
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue