Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • master
1 result

Target

Select target project
  • oss/minerva/minerva-app
1 result
Select Git revision
  • master
1 result
Show changes
Showing
with 16566 additions and 0 deletions
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Backbone.Undo sample</title>
<style>
body {
font-family: sans-serif;
line-height: 140%;
}
#centered {
position: absolute;
top: 50%;
left: 50%;
margin-left: -180px;
margin-top: -120px;
}
</style>
</head>
<body>
<ol id="centered">
<li>
<button id="start">startTracking</button><button id="stop">stopTracking</button>
<p>Changes are currently <strong id="trackingState"></strong></p>
</li>
<li>
<input type="text" id="input" value="foo" /><button id="set">set</button>
</li>
<li>
<p>Number of undo-actions in the action-stack: <strong id="stacklength">0</strong></p>
<button id="undo">undo</button><button id="redo">redo</button>
</li>
</ol>
<ol>
<li>Click <em>startTracking</em> to start tracking changes</li>
<li>Enter different values into the input field and call <em>set</em> each time</li>
<li>Click <em>undo</em> or <em>redo</em> to undo/redo your changes</li>
</ol>
<script src="jquery-1.9.1.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<script src="../Backbone.Undo.js"></script>
<script>
$(function () {
var model = new Backbone.Model({"value": "foo"}),
View = Backbone.View.extend({
initialize: function () {
// If the model's value changes, update the view
this.model.on("change:value", function (model, value, options) {
if (value != this.$el.val()) {
this.$el.val(value);
}
}, this);
}
})
view = new View({
model: model,
el: $("#input")
})
// If you click the set button, the model's value is changed
$("#set").on("click", function () {
model.set("value", $("#input").val());
$("#stacklength").text(undoManager.stack.length);
})
// Now: The undo/redo part
var undoManager = new Backbone.UndoManager;
undoManager.register(model);
$("#start").on("click", function () {
undoManager.startTracking();
$("#trackingState").text("tracked");
})
$("#stop").on("click", function () {
undoManager.stopTracking();
$("#trackingState").text("not tracked");
}).click();
$("#undo").on("click", function () {
undoManager.undo();
})
$("#redo").on("click", function () {
undoManager.redo();
})
})
</script>
</body>
</html>
\ No newline at end of file
Source diff could not be displayed: it is too large. Options to address this: view the blob.
// Underscore.js 1.4.4
// ===================
// > http://underscorejs.org
// > (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
// > Underscore may be freely distributed under the MIT license.
// Baseline setup
// --------------
(function() {
// Establish the root object, `window` in the browser, or `global` on the server.
var root = this;
// Save the previous value of the `_` variable.
var previousUnderscore = root._;
// Establish the object that gets returned to break out of a loop iteration.
var breaker = {};
// Save bytes in the minified (but not gzipped) version:
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
// Create quick reference variables for speed access to core prototypes.
var push = ArrayProto.push,
slice = ArrayProto.slice,
concat = ArrayProto.concat,
toString = ObjProto.toString,
hasOwnProperty = ObjProto.hasOwnProperty;
// All **ECMAScript 5** native function implementations that we hope to use
// are declared here.
var
nativeForEach = ArrayProto.forEach,
nativeMap = ArrayProto.map,
nativeReduce = ArrayProto.reduce,
nativeReduceRight = ArrayProto.reduceRight,
nativeFilter = ArrayProto.filter,
nativeEvery = ArrayProto.every,
nativeSome = ArrayProto.some,
nativeIndexOf = ArrayProto.indexOf,
nativeLastIndexOf = ArrayProto.lastIndexOf,
nativeIsArray = Array.isArray,
nativeKeys = Object.keys,
nativeBind = FuncProto.bind;
// Create a safe reference to the Underscore object for use below.
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj);
this._wrapped = obj;
};
// Export the Underscore object for **Node.js**, with
// backwards-compatibility for the old `require()` API. If we're in
// the browser, add `_` as a global object via a string identifier,
// for Closure Compiler "advanced" mode.
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = _;
}
exports._ = _;
} else {
root._ = _;
}
// Current version.
_.VERSION = '1.4.4';
// Collection Functions
// --------------------
// The cornerstone, an `each` implementation, aka `forEach`.
// Handles objects with the built-in `forEach`, arrays, and raw objects.
// Delegates to **ECMAScript 5**'s native `forEach` if available.
var each = _.each = _.forEach = function(obj, iterator, context) {
if (obj == null) return;
if (nativeForEach && obj.forEach === nativeForEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (var i = 0, l = obj.length; i < l; i++) {
if (iterator.call(context, obj[i], i, obj) === breaker) return;
}
} else {
for (var key in obj) {
if (_.has(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === breaker) return;
}
}
}
};
// Return the results of applying the iterator to each element.
// Delegates to **ECMAScript 5**'s native `map` if available.
_.map = _.collect = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
each(obj, function(value, index, list) {
results[results.length] = iterator.call(context, value, index, list);
});
return results;
};
var reduceError = 'Reduce of empty array with no initial value';
// **Reduce** builds up a single result from a list of values, aka `inject`,
// or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
_.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduce && obj.reduce === nativeReduce) {
if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
}
each(obj, function(value, index, list) {
if (!initial) {
memo = value;
initial = true;
} else {
memo = iterator.call(context, memo, value, index, list);
}
});
if (!initial) throw new TypeError(reduceError);
return memo;
};
// The right-associative version of reduce, also known as `foldr`.
// Delegates to **ECMAScript 5**'s native `reduceRight` if available.
_.reduceRight = _.foldr = function(obj, iterator, memo, context) {
var initial = arguments.length > 2;
if (obj == null) obj = [];
if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
if (context) iterator = _.bind(iterator, context);
return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
}
var length = obj.length;
if (length !== +length) {
var keys = _.keys(obj);
length = keys.length;
}
each(obj, function(value, index, list) {
index = keys ? keys[--length] : --length;
if (!initial) {
memo = obj[index];
initial = true;
} else {
memo = iterator.call(context, memo, obj[index], index, list);
}
});
if (!initial) throw new TypeError(reduceError);
return memo;
};
// Return the first value which passes a truth test. Aliased as `detect`.
_.find = _.detect = function(obj, iterator, context) {
var result;
any(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) {
result = value;
return true;
}
});
return result;
};
// Return all the elements that pass a truth test.
// Delegates to **ECMAScript 5**'s native `filter` if available.
// Aliased as `select`.
_.filter = _.select = function(obj, iterator, context) {
var results = [];
if (obj == null) return results;
if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
each(obj, function(value, index, list) {
if (iterator.call(context, value, index, list)) results[results.length] = value;
});
return results;
};
// Return all the elements for which a truth test fails.
_.reject = function(obj, iterator, context) {
return _.filter(obj, function(value, index, list) {
return !iterator.call(context, value, index, list);
}, context);
};
// Determine whether all of the elements match a truth test.
// Delegates to **ECMAScript 5**'s native `every` if available.
// Aliased as `all`.
_.every = _.all = function(obj, iterator, context) {
iterator || (iterator = _.identity);
var result = true;
if (obj == null) return result;
if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
each(obj, function(value, index, list) {
if (!(result = result && iterator.call(context, value, index, list))) return breaker;
});
return !!result;
};
// Determine if at least one element in the object matches a truth test.
// Delegates to **ECMAScript 5**'s native `some` if available.
// Aliased as `any`.
var any = _.some = _.any = function(obj, iterator, context) {
iterator || (iterator = _.identity);
var result = false;
if (obj == null) return result;
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
each(obj, function(value, index, list) {
if (result || (result = iterator.call(context, value, index, list))) return breaker;
});
return !!result;
};
// Determine if the array or object contains a given value (using `===`).
// Aliased as `include`.
_.contains = _.include = function(obj, target) {
if (obj == null) return false;
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
return any(obj, function(value) {
return value === target;
});
};
// Invoke a method (with arguments) on every item in a collection.
_.invoke = function(obj, method) {
var args = slice.call(arguments, 2);
var isFunc = _.isFunction(method);
return _.map(obj, function(value) {
return (isFunc ? method : value[method]).apply(value, args);
});
};
// Convenience version of a common use case of `map`: fetching a property.
_.pluck = function(obj, key) {
return _.map(obj, function(value){ return value[key]; });
};
// Convenience version of a common use case of `filter`: selecting only objects
// containing specific `key:value` pairs.
_.where = function(obj, attrs, first) {
if (_.isEmpty(attrs)) return first ? null : [];
return _[first ? 'find' : 'filter'](obj, function(value) {
for (var key in attrs) {
if (attrs[key] !== value[key]) return false;
}
return true;
});
};
// Convenience version of a common use case of `find`: getting the first object
// containing specific `key:value` pairs.
_.findWhere = function(obj, attrs) {
return _.where(obj, attrs, true);
};
// Return the maximum element or (element-based computation).
// Can't optimize arrays of integers longer than 65,535 elements.
// See: https://bugs.webkit.org/show_bug.cgi?id=80797
_.max = function(obj, iterator, context) {
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
return Math.max.apply(Math, obj);
}
if (!iterator && _.isEmpty(obj)) return -Infinity;
var result = {computed : -Infinity, value: -Infinity};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed >= result.computed && (result = {value : value, computed : computed});
});
return result.value;
};
// Return the minimum element (or element-based computation).
_.min = function(obj, iterator, context) {
if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
return Math.min.apply(Math, obj);
}
if (!iterator && _.isEmpty(obj)) return Infinity;
var result = {computed : Infinity, value: Infinity};
each(obj, function(value, index, list) {
var computed = iterator ? iterator.call(context, value, index, list) : value;
computed < result.computed && (result = {value : value, computed : computed});
});
return result.value;
};
// Shuffle an array.
_.shuffle = function(obj) {
var rand;
var index = 0;
var shuffled = [];
each(obj, function(value) {
rand = _.random(index++);
shuffled[index - 1] = shuffled[rand];
shuffled[rand] = value;
});
return shuffled;
};
// An internal function to generate lookup iterators.
var lookupIterator = function(value) {
return _.isFunction(value) ? value : function(obj){ return obj[value]; };
};
// Sort the object's values by a criterion produced by an iterator.
_.sortBy = function(obj, value, context) {
var iterator = lookupIterator(value);
return _.pluck(_.map(obj, function(value, index, list) {
return {
value : value,
index : index,
criteria : iterator.call(context, value, index, list)
};
}).sort(function(left, right) {
var a = left.criteria;
var b = right.criteria;
if (a !== b) {
if (a > b || a === void 0) return 1;
if (a < b || b === void 0) return -1;
}
return left.index < right.index ? -1 : 1;
}), 'value');
};
// An internal function used for aggregate "group by" operations.
var group = function(obj, value, context, behavior) {
var result = {};
var iterator = lookupIterator(value || _.identity);
each(obj, function(value, index) {
var key = iterator.call(context, value, index, obj);
behavior(result, key, value);
});
return result;
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = function(obj, value, context) {
return group(obj, value, context, function(result, key, value) {
(_.has(result, key) ? result[key] : (result[key] = [])).push(value);
});
};
// Counts instances of an object that group by a certain criterion. Pass
// either a string attribute to count by, or a function that returns the
// criterion.
_.countBy = function(obj, value, context) {
return group(obj, value, context, function(result, key) {
if (!_.has(result, key)) result[key] = 0;
result[key]++;
});
};
// Use a comparator function to figure out the smallest index at which
// an object should be inserted so as to maintain order. Uses binary search.
_.sortedIndex = function(array, obj, iterator, context) {
iterator = iterator == null ? _.identity : lookupIterator(iterator);
var value = iterator.call(context, obj);
var low = 0, high = array.length;
while (low < high) {
var mid = (low + high) >>> 1;
iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
}
return low;
};
// Safely convert anything iterable into a real, live array.
_.toArray = function(obj) {
if (!obj) return [];
if (_.isArray(obj)) return slice.call(obj);
if (obj.length === +obj.length) return _.map(obj, _.identity);
return _.values(obj);
};
// Return the number of elements in an object.
_.size = function(obj) {
if (obj == null) return 0;
return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
};
// Array Functions
// ---------------
// Get the first element of an array. Passing **n** will return the first N
// values in the array. Aliased as `head` and `take`. The **guard** check
// allows it to work with `_.map`.
_.first = _.head = _.take = function(array, n, guard) {
if (array == null) return void 0;
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
};
// Returns everything but the last entry of the array. Especially useful on
// the arguments object. Passing **n** will return all the values in
// the array, excluding the last N. The **guard** check allows it to work with
// `_.map`.
_.initial = function(array, n, guard) {
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
};
// Get the last element of an array. Passing **n** will return the last N
// values in the array. The **guard** check allows it to work with `_.map`.
_.last = function(array, n, guard) {
if (array == null) return void 0;
if ((n != null) && !guard) {
return slice.call(array, Math.max(array.length - n, 0));
} else {
return array[array.length - 1];
}
};
// Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
// Especially useful on the arguments object. Passing an **n** will return
// the rest N values in the array. The **guard**
// check allows it to work with `_.map`.
_.rest = _.tail = _.drop = function(array, n, guard) {
return slice.call(array, (n == null) || guard ? 1 : n);
};
// Trim out all falsy values from an array.
_.compact = function(array) {
return _.filter(array, _.identity);
};
// Internal implementation of a recursive `flatten` function.
var flatten = function(input, shallow, output) {
each(input, function(value) {
if (_.isArray(value)) {
shallow ? push.apply(output, value) : flatten(value, shallow, output);
} else {
output.push(value);
}
});
return output;
};
// Return a completely flattened version of an array.
_.flatten = function(array, shallow) {
return flatten(array, shallow, []);
};
// Return a version of the array that does not contain the specified value(s).
_.without = function(array) {
return _.difference(array, slice.call(arguments, 1));
};
// Produce a duplicate-free version of the array. If the array has already
// been sorted, you have the option of using a faster algorithm.
// Aliased as `unique`.
_.uniq = _.unique = function(array, isSorted, iterator, context) {
if (_.isFunction(isSorted)) {
context = iterator;
iterator = isSorted;
isSorted = false;
}
var initial = iterator ? _.map(array, iterator, context) : array;
var results = [];
var seen = [];
each(initial, function(value, index) {
if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
seen.push(value);
results.push(array[index]);
}
});
return results;
};
// Produce an array that contains the union: each distinct element from all of
// the passed-in arrays.
_.union = function() {
return _.uniq(concat.apply(ArrayProto, arguments));
};
// Produce an array that contains every item shared between all the
// passed-in arrays.
_.intersection = function(array) {
var rest = slice.call(arguments, 1);
return _.filter(_.uniq(array), function(item) {
return _.every(rest, function(other) {
return _.indexOf(other, item) >= 0;
});
});
};
// Take the difference between one array and a number of other arrays.
// Only the elements present in just the first array will remain.
_.difference = function(array) {
var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
return _.filter(array, function(value){ return !_.contains(rest, value); });
};
// Zip together multiple lists into a single array -- elements that share
// an index go together.
_.zip = function() {
var args = slice.call(arguments);
var length = _.max(_.pluck(args, 'length'));
var results = new Array(length);
for (var i = 0; i < length; i++) {
results[i] = _.pluck(args, "" + i);
}
return results;
};
// Converts lists into objects. Pass either a single array of `[key, value]`
// pairs, or two parallel arrays of the same length -- one of keys, and one of
// the corresponding values.
_.object = function(list, values) {
if (list == null) return {};
var result = {};
for (var i = 0, l = list.length; i < l; i++) {
if (values) {
result[list[i]] = values[i];
} else {
result[list[i][0]] = list[i][1];
}
}
return result;
};
// If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
// we need this function. Return the position of the first occurrence of an
// item in an array, or -1 if the item is not included in the array.
// Delegates to **ECMAScript 5**'s native `indexOf` if available.
// If the array is large and already in sort order, pass `true`
// for **isSorted** to use binary search.
_.indexOf = function(array, item, isSorted) {
if (array == null) return -1;
var i = 0, l = array.length;
if (isSorted) {
if (typeof isSorted == 'number') {
i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
} else {
i = _.sortedIndex(array, item);
return array[i] === item ? i : -1;
}
}
if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
for (; i < l; i++) if (array[i] === item) return i;
return -1;
};
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
_.lastIndexOf = function(array, item, from) {
if (array == null) return -1;
var hasIndex = from != null;
if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
}
var i = (hasIndex ? from : array.length);
while (i--) if (array[i] === item) return i;
return -1;
};
// Generate an integer Array containing an arithmetic progression. A port of
// the native Python `range()` function. See
// [the Python documentation](http://docs.python.org/library/functions.html#range).
_.range = function(start, stop, step) {
if (arguments.length <= 1) {
stop = start || 0;
start = 0;
}
step = arguments[2] || 1;
var len = Math.max(Math.ceil((stop - start) / step), 0);
var idx = 0;
var range = new Array(len);
while(idx < len) {
range[idx++] = start;
start += step;
}
return range;
};
// Function (ahem) Functions
// ------------------
// Create a function bound to a given object (assigning `this`, and arguments,
// optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
// available.
_.bind = function(func, context) {
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
var args = slice.call(arguments, 2);
return function() {
return func.apply(context, args.concat(slice.call(arguments)));
};
};
// Partially apply a function by creating a version that has had some of its
// arguments pre-filled, without changing its dynamic `this` context.
_.partial = function(func) {
var args = slice.call(arguments, 1);
return function() {
return func.apply(this, args.concat(slice.call(arguments)));
};
};
// Bind all of an object's methods to that object. Useful for ensuring that
// all callbacks defined on an object belong to it.
_.bindAll = function(obj) {
var funcs = slice.call(arguments, 1);
if (funcs.length === 0) funcs = _.functions(obj);
each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
return obj;
};
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memo = {};
hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
};
};
// Delays a function for the given number of milliseconds, and then calls
// it with the arguments supplied.
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
// Defers a function, scheduling it to run after the current call stack has
// cleared.
_.defer = function(func) {
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
};
// Returns a function, that, when invoked, will only be triggered at most once
// during a given window of time.
_.throttle = function(func, wait) {
var context, args, timeout, result;
var previous = 0;
var later = function() {
previous = new Date;
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = new Date;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
} else if (!timeout) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
_.debounce = function(func, wait, immediate) {
var timeout, result;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) result = func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) result = func.apply(context, args);
return result;
};
};
// Returns a function that will be executed at most one time, no matter how
// often you call it. Useful for lazy initialization.
_.once = function(func) {
var ran = false, memo;
return function() {
if (ran) return memo;
ran = true;
memo = func.apply(this, arguments);
func = null;
return memo;
};
};
// Returns the first function passed as an argument to the second,
// allowing you to adjust arguments, run code before and after, and
// conditionally execute the original function.
_.wrap = function(func, wrapper) {
return function() {
var args = [func];
push.apply(args, arguments);
return wrapper.apply(this, args);
};
};
// Returns a function that is the composition of a list of functions, each
// consuming the return value of the function that follows.
_.compose = function() {
var funcs = arguments;
return function() {
var args = arguments;
for (var i = funcs.length - 1; i >= 0; i--) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
};
// Returns a function that will only be executed after being called N times.
_.after = function(times, func) {
if (times <= 0) return func();
return function() {
if (--times < 1) {
return func.apply(this, arguments);
}
};
};
// Object Functions
// ----------------
// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = nativeKeys || function(obj) {
if (obj !== Object(obj)) throw new TypeError('Invalid object');
var keys = [];
for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
return keys;
};
// Retrieve the values of an object's properties.
_.values = function(obj) {
var values = [];
for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
return values;
};
// Convert an object into a list of `[key, value]` pairs.
_.pairs = function(obj) {
var pairs = [];
for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
return pairs;
};
// Invert the keys and values of an object. The values must be serializable.
_.invert = function(obj) {
var result = {};
for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
return result;
};
// Return a sorted list of the function names available on the object.
// Aliased as `methods`
_.functions = _.methods = function(obj) {
var names = [];
for (var key in obj) {
if (_.isFunction(obj[key])) names.push(key);
}
return names.sort();
};
// Extend a given object with all the properties in passed-in object(s).
_.extend = function(obj) {
each(slice.call(arguments, 1), function(source) {
if (source) {
for (var prop in source) {
obj[prop] = source[prop];
}
}
});
return obj;
};
// Return a copy of the object only containing the whitelisted properties.
_.pick = function(obj) {
var copy = {};
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
each(keys, function(key) {
if (key in obj) copy[key] = obj[key];
});
return copy;
};
// Return a copy of the object without the blacklisted properties.
_.omit = function(obj) {
var copy = {};
var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
for (var key in obj) {
if (!_.contains(keys, key)) copy[key] = obj[key];
}
return copy;
};
// Fill in a given object with default properties.
_.defaults = function(obj) {
each(slice.call(arguments, 1), function(source) {
if (source) {
for (var prop in source) {
if (obj[prop] == null) obj[prop] = source[prop];
}
}
});
return obj;
};
// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
if (!_.isObject(obj)) return obj;
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};
// Invokes interceptor with the obj, and then returns obj.
// The primary purpose of this method is to "tap into" a method chain, in
// order to perform operations on intermediate results within the chain.
_.tap = function(obj, interceptor) {
interceptor(obj);
return obj;
};
// Internal recursive comparison function for `isEqual`.
var eq = function(a, b, aStack, bStack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
if (a === b) return a !== 0 || 1 / a == 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a instanceof _) a = a._wrapped;
if (b instanceof _) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className != toString.call(b)) return false;
switch (className) {
// Strings, numbers, dates, and booleans are compared by value.
case '[object String]':
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
// equivalent to `new String("5")`.
return a == String(b);
case '[object Number]':
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
// other numeric values.
return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
case '[object Date]':
case '[object Boolean]':
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
// millisecond representations. Note that invalid dates with millisecond representations
// of `NaN` are not equivalent.
return +a == +b;
// RegExps are compared by their source patterns and flags.
case '[object RegExp]':
return a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
}
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = aStack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (aStack[length] == a) return bStack[length] == b;
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
bStack.push(b);
var size = 0, result = true;
// Recursively compare objects and arrays.
if (className == '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
result = size == b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
if (!(result = eq(a[size], b[size], aStack, bStack))) break;
}
}
} else {
// Objects with different constructors are not equivalent, but `Object`s
// from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
_.isFunction(bCtor) && (bCtor instanceof bCtor))) {
return false;
}
// Deep compare objects.
for (var key in a) {
if (_.has(a, key)) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
}
}
// Ensure that both objects contain the same number of properties.
if (result) {
for (key in b) {
if (_.has(b, key) && !(size--)) break;
}
result = !size;
}
}
// Remove the first object from the stack of traversed objects.
aStack.pop();
bStack.pop();
return result;
};
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b, [], []);
};
// Is a given array, string, or object empty?
// An "empty" object has no enumerable own-properties.
_.isEmpty = function(obj) {
if (obj == null) return true;
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
for (var key in obj) if (_.has(obj, key)) return false;
return true;
};
// Is a given value a DOM element?
_.isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
// Is a given value an array?
// Delegates to ECMA5's native Array.isArray
_.isArray = nativeIsArray || function(obj) {
return toString.call(obj) == '[object Array]';
};
// Is a given variable an object?
_.isObject = function(obj) {
return obj === Object(obj);
};
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
_['is' + name] = function(obj) {
return toString.call(obj) == '[object ' + name + ']';
};
});
// Define a fallback version of the method in browsers (ahem, IE), where
// there isn't any inspectable "Arguments" type.
if (!_.isArguments(arguments)) {
_.isArguments = function(obj) {
return !!(obj && _.has(obj, 'callee'));
};
}
// Optimize `isFunction` if appropriate.
if (typeof (/./) !== 'function') {
_.isFunction = function(obj) {
return typeof obj === 'function';
};
}
// Is a given object a finite number?
_.isFinite = function(obj) {
return isFinite(obj) && !isNaN(parseFloat(obj));
};
// Is the given value `NaN`? (NaN is the only number which does not equal itself).
_.isNaN = function(obj) {
return _.isNumber(obj) && obj != +obj;
};
// Is a given value a boolean?
_.isBoolean = function(obj) {
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
};
// Is a given value equal to null?
_.isNull = function(obj) {
return obj === null;
};
// Is a given variable undefined?
_.isUndefined = function(obj) {
return obj === void 0;
};
// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
// Utility Functions
// -----------------
// Run Underscore.js in *noConflict* mode, returning the `_` variable to its
// previous owner. Returns a reference to the Underscore object.
_.noConflict = function() {
root._ = previousUnderscore;
return this;
};
// Keep the identity function around for default iterators.
_.identity = function(value) {
return value;
};
// Run a function **n** times.
_.times = function(n, iterator, context) {
var accum = Array(n);
for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
return accum;
};
// Return a random integer between min and max (inclusive).
_.random = function(min, max) {
if (max == null) {
max = min;
min = 0;
}
return min + Math.floor(Math.random() * (max - min + 1));
};
// List of HTML entities for escaping.
var entityMap = {
escape: {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'/': '&#x2F;'
}
};
entityMap.unescape = _.invert(entityMap.escape);
// Regexes containing the keys and values listed immediately above.
var entityRegexes = {
escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
};
// Functions for escaping and unescaping strings to/from HTML interpolation.
_.each(['escape', 'unescape'], function(method) {
_[method] = function(string) {
if (string == null) return '';
return ('' + string).replace(entityRegexes[method], function(match) {
return entityMap[method][match];
});
};
});
// If the value of the named property is a function then invoke it;
// otherwise, return it.
_.result = function(object, property) {
if (object == null) return null;
var value = object[property];
return _.isFunction(value) ? value.call(object) : value;
};
// Add your own custom functions to the Underscore object.
_.mixin = function(obj) {
each(_.functions(obj), function(name){
var func = _[name] = obj[name];
_.prototype[name] = function() {
var args = [this._wrapped];
push.apply(args, arguments);
return result.call(this, func.apply(_, args));
};
});
};
// Generate a unique integer id (unique within the entire client session).
// Useful for temporary DOM ids.
var idCounter = 0;
_.uniqueId = function(prefix) {
var id = ++idCounter + '';
return prefix ? prefix + id : id;
};
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
"'": "'",
'\\': '\\',
'\r': 'r',
'\n': 'n',
'\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
_.template = function(text, data, settings) {
var render;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
var matcher = new RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately.
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
source += text.slice(index, offset)
.replace(escaper, function(match) { return '\\' + escapes[match]; });
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
}
if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
}
if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
index = offset + match.length;
return match;
});
source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + "return __p;\n";
try {
render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
if (data) return render(data, _);
var template = function(data) {
return render.call(this, data, _);
};
// Provide the compiled function source as a convenience for precompilation.
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
return template;
};
// Add a "chain" function, which will delegate to the wrapper.
_.chain = function(obj) {
return _(obj).chain();
};
// OOP
// ---------------
// If Underscore is called as a function, it returns a wrapped object that
// can be used OO-style. This wrapper holds altered versions of all the
// underscore functions. Wrapped objects may be chained.
// Helper function to continue chaining intermediate results.
var result = function(obj) {
return this._chain ? _(obj).chain() : obj;
};
// Add all of the Underscore functions to the wrapper object.
_.mixin(_);
// Add all mutator Array functions to the wrapper.
each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
var obj = this._wrapped;
method.apply(obj, arguments);
if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
return result.call(this, obj);
};
});
// Add all accessor Array functions to the wrapper.
each(['concat', 'join', 'slice'], function(name) {
var method = ArrayProto[name];
_.prototype[name] = function() {
return result.call(this, method.apply(this._wrapped, arguments));
};
});
_.extend(_.prototype, {
// Start chaining a wrapped Underscore object.
chain: function() {
this._chain = true;
return this;
},
// Extracts the result from a wrapped and chained object.
value: function() {
return this._wrapped;
}
});
}).call(this);
Copyright (c) 2010-2016 Jeremy Ashkenas, DocumentCloud
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
____ __ __
/\ _`\ /\ \ /\ \ __
\ \ \ \ \ __ ___\ \ \/'\\ \ \____ ___ ___ __ /\_\ ____
\ \ _ <' /'__`\ /'___\ \ , < \ \ '__`\ / __`\ /' _ `\ /'__`\ \/\ \ /',__\
\ \ \ \ \/\ \ \.\_/\ \__/\ \ \\`\\ \ \ \ \/\ \ \ \/\ \/\ \/\ __/ __ \ \ \/\__, `\
\ \____/\ \__/.\_\ \____\\ \_\ \_\ \_,__/\ \____/\ \_\ \_\ \____\/\_\_\ \ \/\____/
\/___/ \/__/\/_/\/____/ \/_/\/_/\/___/ \/___/ \/_/\/_/\/____/\/_/\ \_\ \/___/
\ \____/
\/___/
(_'_______________________________________________________________________________'_)
(_.———————————————————————————————————————————————————————————————————————————————._)
Backbone supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.
For Docs, License, Tests, pre-packed downloads, and everything else, really, see:
http://backbonejs.org
To suggest a feature or report a bug:
https://github.com/jashkenas/backbone/issues
For questions on working with Backbone or general discussions:
https://groups.google.com/forum/#!forum/backbonejs,
http://stackoverflow.com/questions/tagged/backbone.js, or
https://gitter.im/jashkenas/backbone
Backbone is an open-sourced component of DocumentCloud:
https://github.com/documentcloud
Many thanks to our contributors:
https://github.com/jashkenas/backbone/graphs/contributors
Special thanks to Robert Kieffer for the original philosophy behind Backbone.
https://github.com/broofa
(function(t){var e=typeof self=="object"&&self.self===self&&self||typeof global=="object"&&global.global===global&&global;if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,n){e.Backbone=t(e,n,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore"),r;try{r=require("jquery")}catch(n){}t(e,exports,i,r)}else{e.Backbone=t(e,{},e._,e.jQuery||e.Zepto||e.ender||e.$)}})(function(t,e,i,r){var n=t.Backbone;var s=Array.prototype.slice;e.VERSION="1.3.3";e.$=r;e.noConflict=function(){t.Backbone=n;return this};e.emulateHTTP=false;e.emulateJSON=false;var a=function(t,e,r){switch(t){case 1:return function(){return i[e](this[r])};case 2:return function(t){return i[e](this[r],t)};case 3:return function(t,n){return i[e](this[r],o(t,this),n)};case 4:return function(t,n,s){return i[e](this[r],o(t,this),n,s)};default:return function(){var t=s.call(arguments);t.unshift(this[r]);return i[e].apply(i,t)}}};var h=function(t,e,r){i.each(e,function(e,n){if(i[n])t.prototype[n]=a(e,n,r)})};var o=function(t,e){if(i.isFunction(t))return t;if(i.isObject(t)&&!e._isModel(t))return l(t);if(i.isString(t))return function(e){return e.get(t)};return t};var l=function(t){var e=i.matches(t);return function(t){return e(t.attributes)}};var u=e.Events={};var c=/\s+/;var f=function(t,e,r,n,s){var a=0,h;if(r&&typeof r==="object"){if(n!==void 0&&"context"in s&&s.context===void 0)s.context=n;for(h=i.keys(r);a<h.length;a++){e=f(t,e,h[a],r[h[a]],s)}}else if(r&&c.test(r)){for(h=r.split(c);a<h.length;a++){e=t(e,h[a],n,s)}}else{e=t(e,r,n,s)}return e};u.on=function(t,e,i){return d(this,t,e,i)};var d=function(t,e,i,r,n){t._events=f(v,t._events||{},e,i,{context:r,ctx:t,listening:n});if(n){var s=t._listeners||(t._listeners={});s[n.id]=n}return t};u.listenTo=function(t,e,r){if(!t)return this;var n=t._listenId||(t._listenId=i.uniqueId("l"));var s=this._listeningTo||(this._listeningTo={});var a=s[n];if(!a){var h=this._listenId||(this._listenId=i.uniqueId("l"));a=s[n]={obj:t,objId:n,id:h,listeningTo:s,count:0}}d(t,e,r,this,a);return this};var v=function(t,e,i,r){if(i){var n=t[e]||(t[e]=[]);var s=r.context,a=r.ctx,h=r.listening;if(h)h.count++;n.push({callback:i,context:s,ctx:s||a,listening:h})}return t};u.off=function(t,e,i){if(!this._events)return this;this._events=f(g,this._events,t,e,{context:i,listeners:this._listeners});return this};u.stopListening=function(t,e,r){var n=this._listeningTo;if(!n)return this;var s=t?[t._listenId]:i.keys(n);for(var a=0;a<s.length;a++){var h=n[s[a]];if(!h)break;h.obj.off(e,r,this)}return this};var g=function(t,e,r,n){if(!t)return;var s=0,a;var h=n.context,o=n.listeners;if(!e&&!r&&!h){var l=i.keys(o);for(;s<l.length;s++){a=o[l[s]];delete o[a.id];delete a.listeningTo[a.objId]}return}var u=e?[e]:i.keys(t);for(;s<u.length;s++){e=u[s];var c=t[e];if(!c)break;var f=[];for(var d=0;d<c.length;d++){var v=c[d];if(r&&r!==v.callback&&r!==v.callback._callback||h&&h!==v.context){f.push(v)}else{a=v.listening;if(a&&--a.count===0){delete o[a.id];delete a.listeningTo[a.objId]}}}if(f.length){t[e]=f}else{delete t[e]}}return t};u.once=function(t,e,r){var n=f(p,{},t,e,i.bind(this.off,this));if(typeof t==="string"&&r==null)e=void 0;return this.on(n,e,r)};u.listenToOnce=function(t,e,r){var n=f(p,{},e,r,i.bind(this.stopListening,this,t));return this.listenTo(t,n)};var p=function(t,e,r,n){if(r){var s=t[e]=i.once(function(){n(e,s);r.apply(this,arguments)});s._callback=r}return t};u.trigger=function(t){if(!this._events)return this;var e=Math.max(0,arguments.length-1);var i=Array(e);for(var r=0;r<e;r++)i[r]=arguments[r+1];f(m,this._events,t,void 0,i);return this};var m=function(t,e,i,r){if(t){var n=t[e];var s=t.all;if(n&&s)s=s.slice();if(n)_(n,r);if(s)_(s,[e].concat(r))}return t};var _=function(t,e){var i,r=-1,n=t.length,s=e[0],a=e[1],h=e[2];switch(e.length){case 0:while(++r<n)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<n)(i=t[r]).callback.call(i.ctx,s);return;case 2:while(++r<n)(i=t[r]).callback.call(i.ctx,s,a);return;case 3:while(++r<n)(i=t[r]).callback.call(i.ctx,s,a,h);return;default:while(++r<n)(i=t[r]).callback.apply(i.ctx,e);return}};u.bind=u.on;u.unbind=u.off;i.extend(e,u);var y=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId(this.cidPrefix);this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};var n=i.result(this,"defaults");r=i.defaults(i.extend({},n,r),n);this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(y.prototype,u,{changed:null,validationError:null,idAttribute:"id",cidPrefix:"c",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},matches:function(t){return!!i.iteratee(t,this)(this.attributes)},set:function(t,e,r){if(t==null)return this;var n;if(typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r||(r={});if(!this._validate(n,r))return false;var s=r.unset;var a=r.silent;var h=[];var o=this._changing;this._changing=true;if(!o){this._previousAttributes=i.clone(this.attributes);this.changed={}}var l=this.attributes;var u=this.changed;var c=this._previousAttributes;for(var f in n){e=n[f];if(!i.isEqual(l[f],e))h.push(f);if(!i.isEqual(c[f],e)){u[f]=e}else{delete u[f]}s?delete l[f]:l[f]=e}if(this.idAttribute in n)this.id=this.get(this.idAttribute);if(!a){if(h.length)this._pending=r;for(var d=0;d<h.length;d++){this.trigger("change:"+h[d],this,l[h[d]],r)}}if(o)return this;if(!a){while(this._pending){r=this._pending;this._pending=false;this.trigger("change",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e=this._changing?this._previousAttributes:this.attributes;var r={};for(var n in t){var s=t[n];if(i.isEqual(e[n],s))continue;r[n]=s}return i.size(r)?r:false},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=i.extend({parse:true},t);var e=this;var r=t.success;t.success=function(i){var n=t.parse?e.parse(i,t):i;if(!e.set(n,t))return false;if(r)r.call(t.context,e,i,t);e.trigger("sync",e,i,t)};B(this,t);return this.sync("read",this,t)},save:function(t,e,r){var n;if(t==null||typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r=i.extend({validate:true,parse:true},r);var s=r.wait;if(n&&!s){if(!this.set(n,r))return false}else if(!this._validate(n,r)){return false}var a=this;var h=r.success;var o=this.attributes;r.success=function(t){a.attributes=o;var e=r.parse?a.parse(t,r):t;if(s)e=i.extend({},n,e);if(e&&!a.set(e,r))return false;if(h)h.call(r.context,a,t,r);a.trigger("sync",a,t,r)};B(this,r);if(n&&s)this.attributes=i.extend({},o,n);var l=this.isNew()?"create":r.patch?"patch":"update";if(l==="patch"&&!r.attrs)r.attrs=n;var u=this.sync(l,this,r);this.attributes=o;return u},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var n=t.wait;var s=function(){e.stopListening();e.trigger("destroy",e,e.collection,t)};t.success=function(i){if(n)s();if(r)r.call(t.context,e,i,t);if(!e.isNew())e.trigger("sync",e,i,t)};var a=false;if(this.isNew()){i.defer(t.success)}else{B(this,t);a=this.sync("delete",this,t)}if(!n)s();return a},url:function(){var t=i.result(this,"urlRoot")||i.result(this.collection,"url")||F();if(this.isNew())return t;var e=this.get(this.idAttribute);return t.replace(/[^\/]$/,"$&/")+encodeURIComponent(e)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.extend({},t,{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger("invalid",this,r,i.extend(e,{validationError:r}));return false}});var b={keys:1,values:1,pairs:1,invert:1,pick:0,omit:0,chain:1,isEmpty:1};h(y,b,"attributes");var x=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var w={add:true,remove:true,merge:true};var E={add:true,remove:false};var I=function(t,e,i){i=Math.min(Math.max(i,0),t.length);var r=Array(t.length-i);var n=e.length;var s;for(s=0;s<r.length;s++)r[s]=t[s+i];for(s=0;s<n;s++)t[s+i]=e[s];for(s=0;s<r.length;s++)t[s+n+i]=r[s]};i.extend(x.prototype,u,{model:y,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,E))},remove:function(t,e){e=i.extend({},e);var r=!i.isArray(t);t=r?[t]:t.slice();var n=this._removeModels(t,e);if(!e.silent&&n.length){e.changes={added:[],merged:[],removed:n};this.trigger("update",this,e)}return r?n[0]:n},set:function(t,e){if(t==null)return;e=i.extend({},w,e);if(e.parse&&!this._isModel(t)){t=this.parse(t,e)||[]}var r=!i.isArray(t);t=r?[t]:t.slice();var n=e.at;if(n!=null)n=+n;if(n>this.length)n=this.length;if(n<0)n+=this.length+1;var s=[];var a=[];var h=[];var o=[];var l={};var u=e.add;var c=e.merge;var f=e.remove;var d=false;var v=this.comparator&&n==null&&e.sort!==false;var g=i.isString(this.comparator)?this.comparator:null;var p,m;for(m=0;m<t.length;m++){p=t[m];var _=this.get(p);if(_){if(c&&p!==_){var y=this._isModel(p)?p.attributes:p;if(e.parse)y=_.parse(y,e);_.set(y,e);h.push(_);if(v&&!d)d=_.hasChanged(g)}if(!l[_.cid]){l[_.cid]=true;s.push(_)}t[m]=_}else if(u){p=t[m]=this._prepareModel(p,e);if(p){a.push(p);this._addReference(p,e);l[p.cid]=true;s.push(p)}}}if(f){for(m=0;m<this.length;m++){p=this.models[m];if(!l[p.cid])o.push(p)}if(o.length)this._removeModels(o,e)}var b=false;var x=!v&&u&&f;if(s.length&&x){b=this.length!==s.length||i.some(this.models,function(t,e){return t!==s[e]});this.models.length=0;I(this.models,s,0);this.length=this.models.length}else if(a.length){if(v)d=true;I(this.models,a,n==null?this.length:n);this.length=this.models.length}if(d)this.sort({silent:true});if(!e.silent){for(m=0;m<a.length;m++){if(n!=null)e.index=n+m;p=a[m];p.trigger("add",p,this,e)}if(d||b)this.trigger("sort",this,e);if(a.length||o.length||h.length){e.changes={added:a,removed:o,merged:h};this.trigger("update",this,e)}}return r?t[0]:t},reset:function(t,e){e=e?i.clone(e):{};for(var r=0;r<this.models.length;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);return this.remove(e,t)},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);return this.remove(e,t)},slice:function(){return s.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t]||this._byId[this.modelId(t.attributes||t)]||t.cid&&this._byId[t.cid]},has:function(t){return this.get(t)!=null},at:function(t){if(t<0)t+=this.length;return this.models[t]},where:function(t,e){return this[e?"find":"filter"](t)},findWhere:function(t){return this.where(t,true)},sort:function(t){var e=this.comparator;if(!e)throw new Error("Cannot sort a set without a comparator");t||(t={});var r=e.length;if(i.isFunction(e))e=i.bind(e,this);if(r===1||i.isString(e)){this.models=this.sortBy(e)}else{this.models.sort(e)}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return this.map(t+"")},fetch:function(t){t=i.extend({parse:true},t);var e=t.success;var r=this;t.success=function(i){var n=t.reset?"reset":"set";r[n](i,t);if(e)e.call(t.context,r,i,t);r.trigger("sync",r,i,t)};B(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?i.clone(e):{};var r=e.wait;t=this._prepareModel(t,e);if(!t)return false;if(!r)this.add(t,e);var n=this;var s=e.success;e.success=function(t,e,i){if(r)n.add(t,i);if(s)s.call(i.context,t,e,i)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models,{model:this.model,comparator:this.comparator})},modelId:function(t){return t[this.model.prototype.idAttribute||"id"]},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(this._isModel(t)){if(!t.collection)t.collection=this;return t}e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger("invalid",this,r.validationError,e);return false},_removeModels:function(t,e){var i=[];for(var r=0;r<t.length;r++){var n=this.get(t[r]);if(!n)continue;var s=this.indexOf(n);this.models.splice(s,1);this.length--;delete this._byId[n.cid];var a=this.modelId(n.attributes);if(a!=null)delete this._byId[a];if(!e.silent){e.index=s;n.trigger("remove",n,this,e)}i.push(n);this._removeReference(n,e)}return i},_isModel:function(t){return t instanceof y},_addReference:function(t,e){this._byId[t.cid]=t;var i=this.modelId(t.attributes);if(i!=null)this._byId[i]=t;t.on("all",this._onModelEvent,this)},_removeReference:function(t,e){delete this._byId[t.cid];var i=this.modelId(t.attributes);if(i!=null)delete this._byId[i];if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if(e){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(t==="change"){var n=this.modelId(e.previousAttributes());var s=this.modelId(e.attributes);if(n!==s){if(n!=null)delete this._byId[n];if(s!=null)this._byId[s]=e}}}this.trigger.apply(this,arguments)}});var S={forEach:3,each:3,map:3,collect:3,reduce:0,foldl:0,inject:0,reduceRight:0,foldr:0,find:3,detect:3,filter:3,select:3,reject:3,every:3,all:3,some:3,any:3,include:3,includes:3,contains:3,invoke:0,max:3,min:3,toArray:1,size:1,first:3,head:3,take:3,initial:3,rest:3,tail:3,drop:3,last:3,without:0,difference:0,indexOf:3,shuffle:1,lastIndexOf:3,isEmpty:1,chain:1,sample:3,partition:3,groupBy:3,countBy:3,sortBy:3,indexBy:3,findIndex:3,findLastIndex:3};h(x,S,"models");var k=e.View=function(t){this.cid=i.uniqueId("view");i.extend(this,i.pick(t,P));this._ensureElement();this.initialize.apply(this,arguments)};var T=/^(\S+)\s*(.*)$/;var P=["model","collection","el","id","attributes","className","tagName","events"];i.extend(k.prototype,u,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this._removeElement();this.stopListening();return this},_removeElement:function(){this.$el.remove()},setElement:function(t){this.undelegateEvents();this._setElement(t);this.delegateEvents();return this},_setElement:function(t){this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0]},delegateEvents:function(t){t||(t=i.result(this,"events"));if(!t)return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[r];if(!r)continue;var n=e.match(T);this.delegate(n[1],n[2],i.bind(r,this))}return this},delegate:function(t,e,i){this.$el.on(t+".delegateEvents"+this.cid,e,i);return this},undelegateEvents:function(){if(this.$el)this.$el.off(".delegateEvents"+this.cid);return this},undelegate:function(t,e,i){this.$el.off(t+".delegateEvents"+this.cid,e,i);return this},_createElement:function(t){return document.createElement(t)},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,"attributes"));if(this.id)t.id=i.result(this,"id");if(this.className)t["class"]=i.result(this,"className");this.setElement(this._createElement(i.result(this,"tagName")));this._setAttributes(t)}else{this.setElement(i.result(this,"el"))}},_setAttributes:function(t){this.$el.attr(t)}});e.sync=function(t,r,n){var s=H[t];i.defaults(n||(n={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:s,dataType:"json"};if(!n.url){a.url=i.result(r,"url")||F()}if(n.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(n.attrs||r.toJSON(n))}if(n.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(n.emulateHTTP&&(s==="PUT"||s==="DELETE"||s==="PATCH")){a.type="POST";if(n.emulateJSON)a.data._method=s;var h=n.beforeSend;n.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",s);if(h)return h.apply(this,arguments)}}if(a.type!=="GET"&&!n.emulateJSON){a.processData=false}var o=n.error;n.error=function(t,e,i){n.textStatus=e;n.errorThrown=i;if(o)o.call(n.context,t,e,i)};var l=n.xhr=e.ajax(i.extend(a,n));r.trigger("request",r,l,n);return l};var H={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var A=/\((.*?)\)/g;var C=/(\(\?)?:\w+/g;var R=/\*\w+/g;var j=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,n){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){n=r;r=""}if(!n)n=this[r];var s=this;e.history.route(t,function(i){var a=s._extractParameters(t,i);if(s.execute(n,a,r)!==false){s.trigger.apply(s,["route:"+r].concat(a));s.trigger("route",r,a);e.history.trigger("route",s,r,a)}});return this},execute:function(t,e,i){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(j,"\\$&").replace(A,"(?:$1)?").replace(C,function(t,e){return e?t:"([^/?]+)"}).replace(R,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];this.checkUrl=i.bind(this.checkUrl,this);if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var M=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var U=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){var t=this.location.pathname.replace(/[^\/]$/,"$&/");return t===this.root&&!this.getSearch()},matchRoot:function(){var t=this.decodeFragment(this.location.pathname);var e=t.slice(0,this.root.length-1)+"/";return e===this.root},decodeFragment:function(t){return decodeURI(t.replace(/%25/g,"%2525"))},getSearch:function(){var t=this.location.href.replace(/#.*/,"").match(/\?.+/);return t?t[0]:""},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getPath:function(){var t=this.decodeFragment(this.location.pathname+this.getSearch()).slice(this.root.length-1);return t.charAt(0)==="/"?t.slice(1):t},getFragment:function(t){if(t==null){if(this._usePushState||!this._wantsHashChange){t=this.getPath()}else{t=this.getHash()}}return t.replace(M,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._hasHashChange="onhashchange"in window&&(document.documentMode===void 0||document.documentMode>7);this._useHashChange=this._wantsHashChange&&this._hasHashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.history&&this.history.pushState);this._usePushState=this._wantsPushState&&this._hasPushState;this.fragment=this.getFragment();this.root=("/"+this.root+"/").replace(O,"/");if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){var e=this.root.slice(0,-1)||"/";this.location.replace(e+"#"+this.getPath());return true}else if(this._hasPushState&&this.atRoot()){this.navigate(this.getHash(),{replace:true})}}if(!this._hasHashChange&&this._wantsHashChange&&!this._usePushState){this.iframe=document.createElement("iframe");this.iframe.src="javascript:0";this.iframe.style.display="none";this.iframe.tabIndex=-1;var r=document.body;var n=r.insertBefore(this.iframe,r.firstChild).contentWindow;n.document.open();n.document.close();n.location.hash="#"+this.fragment}var s=window.addEventListener||function(t,e){return attachEvent("on"+t,e)};if(this._usePushState){s("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){s("hashchange",this.checkUrl,false)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}if(!this.options.silent)return this.loadUrl()},stop:function(){var t=window.removeEventListener||function(t,e){return detachEvent("on"+t,e)};if(this._usePushState){t("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){t("hashchange",this.checkUrl,false)}if(this.iframe){document.body.removeChild(this.iframe);this.iframe=null}if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getHash(this.iframe.contentWindow)}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){if(!this.matchRoot())return false;t=this.fragment=this.getFragment(t);return i.some(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};t=this.getFragment(t||"");var i=this.root;if(t===""||t.charAt(0)==="?"){i=i.slice(0,-1)||"/"}var r=i+t;t=this.decodeFragment(t.replace(U,""));if(this.fragment===t)return;this.fragment=t;if(this._usePushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,r)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getHash(this.iframe.contentWindow)){var n=this.iframe.contentWindow;if(!e.replace){n.document.open();n.document.close()}this._updateHash(n.location,t,e.replace)}}else{return this.location.assign(r)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new N;var q=function(t,e){var r=this;var n;if(t&&i.has(t,"constructor")){n=t.constructor}else{n=function(){return r.apply(this,arguments)}}i.extend(n,r,e);n.prototype=i.create(r.prototype,t);n.prototype.constructor=n;n.__super__=r.prototype;return n};y.extend=x.extend=$.extend=k.extend=N.extend=q;var F=function(){throw new Error('A "url" property or function must be specified')};var B=function(t,e){var i=e.error;e.error=function(r){if(i)i.call(e.context,t,r,e);t.trigger("error",t,r,e)}};return e});
//# sourceMappingURL=backbone-min.map
\ No newline at end of file
{"version":3,"sources":["backbone.js"],"names":["factory","root","self","global","define","amd","_","$","exports","Backbone","require","e","jQuery","Zepto","ender","previousBackbone","slice","Array","prototype","VERSION","noConflict","this","emulateHTTP","emulateJSON","addMethod","length","method","attribute","value","iteratee","context","cb","defaultVal","args","call","arguments","unshift","apply","addUnderscoreMethods","Class","methods","each","instance","isFunction","isObject","_isModel","modelMatcher","isString","model","get","attrs","matcher","matches","attributes","Events","eventSplitter","eventsApi","events","name","callback","opts","i","names","keys","test","split","on","internalOn","obj","listening","_events","onApi","ctx","listeners","_listeners","id","listenTo","_listenId","uniqueId","listeningTo","_listeningTo","thisId","objId","count","options","handlers","push","off","offApi","stopListening","ids","remaining","j","handler","_callback","once","onceMap","bind","listenToOnce","map","offer","trigger","Math","max","triggerApi","objEvents","allEvents","all","triggerEvents","concat","ev","l","a1","a2","a3","unbind","extend","Model","cid","cidPrefix","collection","parse","defaults","result","set","changed","initialize","validationError","idAttribute","toJSON","clone","sync","attr","escape","has","key","val","_validate","unset","silent","changes","changing","_changing","_previousAttributes","current","prev","isEqual","_pending","clear","hasChanged","isEmpty","changedAttributes","diff","old","size","previous","previousAttributes","fetch","success","resp","serverAttrs","wrapError","save","validate","wait","isNew","patch","xhr","destroy","defer","url","base","urlError","replace","encodeURIComponent","constructor","isValid","error","modelMethods","values","pairs","invert","pick","omit","chain","Collection","models","comparator","_reset","reset","setOptions","add","remove","merge","addOptions","splice","array","insert","at","min","tail","singular","isArray","removed","_removeModels","added","merged","toAdd","toMerge","toRemove","modelMap","sort","sortable","sortAttr","existing","_prepareModel","_addReference","orderChanged","some","m","index","_removeReference","previousModels","pop","shift","_byId","modelId","where","first","findWhere","Error","sortBy","pluck","create","callbackOpts","indexOf","_onModelEvent","event","prevId","collectionMethods","forEach","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","any","include","includes","contains","invoke","toArray","head","take","initial","rest","drop","last","without","difference","shuffle","lastIndexOf","sample","partition","groupBy","countBy","indexBy","findIndex","findLastIndex","View","viewOptions","_ensureElement","delegateEventSplitter","tagName","selector","$el","render","_removeElement","setElement","element","undelegateEvents","_setElement","delegateEvents","el","match","delegate","eventName","listener","undelegate","_createElement","document","createElement","className","_setAttributes","type","methodMap","params","dataType","data","contentType","JSON","stringify","_method","beforeSend","setRequestHeader","processData","textStatus","errorThrown","ajax","update","delete","read","Router","routes","_bindRoutes","optionalParam","namedParam","splatParam","escapeRegExp","route","isRegExp","_routeToRegExp","router","history","fragment","_extractParameters","execute","navigate","optional","RegExp","exec","param","decodeURIComponent","History","checkUrl","window","location","routeStripper","rootStripper","pathStripper","started","interval","atRoot","path","pathname","getSearch","matchRoot","decodeFragment","rootPath","decodeURI","href","getHash","getPath","charAt","getFragment","_usePushState","_wantsHashChange","start","hashChange","_hasHashChange","documentMode","_useHashChange","_wantsPushState","pushState","_hasPushState","iframe","src","style","display","tabIndex","body","iWindow","insertBefore","firstChild","contentWindow","open","close","hash","addEventListener","attachEvent","_checkUrlInterval","setInterval","loadUrl","stop","removeEventListener","detachEvent","removeChild","clearInterval","title","_updateHash","assign","protoProps","staticProps","parent","child","__super__"],"mappings":"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","file":"backbone-min.js"}
\ No newline at end of file
// Backbone.js 1.3.3
// (c) 2010-2016 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
// Backbone may be freely distributed under the MIT license.
// For all details and documentation:
// http://backbonejs.org
(function(factory) {
// Establish the root object, `window` (`self`) in the browser, or `global` on the server.
// We use `self` instead of `window` for `WebWorker` support.
var root = (typeof self == 'object' && self.self === self && self) ||
(typeof global == 'object' && global.global === global && global);
// Set up Backbone appropriately for the environment. Start with AMD.
if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
// Export global even in AMD case in case this script is loaded with
// others that may still expect a global Backbone.
root.Backbone = factory(root, exports, _, $);
});
// Next for Node.js or CommonJS. jQuery may not be needed as a module.
} else if (typeof exports !== 'undefined') {
var _ = require('underscore'), $;
try { $ = require('jquery'); } catch (e) {}
factory(root, exports, _, $);
// Finally, as a browser global.
} else {
root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
}
})(function(root, Backbone, _, $) {
// Initial Setup
// -------------
// Save the previous value of the `Backbone` variable, so that it can be
// restored later on, if `noConflict` is used.
var previousBackbone = root.Backbone;
// Create a local reference to a common array method we'll want to use later.
var slice = Array.prototype.slice;
// Current version of the library. Keep in sync with `package.json`.
Backbone.VERSION = '1.3.3';
// For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
// the `$` variable.
Backbone.$ = $;
// Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
// to its previous owner. Returns a reference to this Backbone object.
Backbone.noConflict = function() {
root.Backbone = previousBackbone;
return this;
};
// Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
// will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
// set a `X-Http-Method-Override` header.
Backbone.emulateHTTP = false;
// Turn on `emulateJSON` to support legacy servers that can't deal with direct
// `application/json` requests ... this will encode the body as
// `application/x-www-form-urlencoded` instead and will send the model in a
// form param named `model`.
Backbone.emulateJSON = false;
// Proxy Backbone class methods to Underscore functions, wrapping the model's
// `attributes` object or collection's `models` array behind the scenes.
//
// collection.filter(function(model) { return model.get('age') > 10 });
// collection.each(this.addView);
//
// `Function#apply` can be slow so we use the method's arg count, if we know it.
var addMethod = function(length, method, attribute) {
switch (length) {
case 1: return function() {
return _[method](this[attribute]);
};
case 2: return function(value) {
return _[method](this[attribute], value);
};
case 3: return function(iteratee, context) {
return _[method](this[attribute], cb(iteratee, this), context);
};
case 4: return function(iteratee, defaultVal, context) {
return _[method](this[attribute], cb(iteratee, this), defaultVal, context);
};
default: return function() {
var args = slice.call(arguments);
args.unshift(this[attribute]);
return _[method].apply(_, args);
};
}
};
var addUnderscoreMethods = function(Class, methods, attribute) {
_.each(methods, function(length, method) {
if (_[method]) Class.prototype[method] = addMethod(length, method, attribute);
});
};
// Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`.
var cb = function(iteratee, instance) {
if (_.isFunction(iteratee)) return iteratee;
if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee);
if (_.isString(iteratee)) return function(model) { return model.get(iteratee); };
return iteratee;
};
var modelMatcher = function(attrs) {
var matcher = _.matches(attrs);
return function(model) {
return matcher(model.attributes);
};
};
// Backbone.Events
// ---------------
// A module that can be mixed in to *any object* in order to provide it with
// a custom event channel. You may bind a callback to an event with `on` or
// remove with `off`; `trigger`-ing an event fires all callbacks in
// succession.
//
// var object = {};
// _.extend(object, Backbone.Events);
// object.on('expand', function(){ alert('expanded'); });
// object.trigger('expand');
//
var Events = Backbone.Events = {};
// Regular expression used to split event strings.
var eventSplitter = /\s+/;
// Iterates over the standard `event, callback` (as well as the fancy multiple
// space-separated events `"change blur", callback` and jQuery-style event
// maps `{event: callback}`).
var eventsApi = function(iteratee, events, name, callback, opts) {
var i = 0, names;
if (name && typeof name === 'object') {
// Handle event maps.
if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
for (names = _.keys(name); i < names.length ; i++) {
events = eventsApi(iteratee, events, names[i], name[names[i]], opts);
}
} else if (name && eventSplitter.test(name)) {
// Handle space-separated event names by delegating them individually.
for (names = name.split(eventSplitter); i < names.length; i++) {
events = iteratee(events, names[i], callback, opts);
}
} else {
// Finally, standard events.
events = iteratee(events, name, callback, opts);
}
return events;
};
// Bind an event to a `callback` function. Passing `"all"` will bind
// the callback to all events fired.
Events.on = function(name, callback, context) {
return internalOn(this, name, callback, context);
};
// Guard the `listening` argument from the public API.
var internalOn = function(obj, name, callback, context, listening) {
obj._events = eventsApi(onApi, obj._events || {}, name, callback, {
context: context,
ctx: obj,
listening: listening
});
if (listening) {
var listeners = obj._listeners || (obj._listeners = {});
listeners[listening.id] = listening;
}
return obj;
};
// Inversion-of-control versions of `on`. Tell *this* object to listen to
// an event in another object... keeping track of what it's listening to
// for easier unbinding later.
Events.listenTo = function(obj, name, callback) {
if (!obj) return this;
var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
var listeningTo = this._listeningTo || (this._listeningTo = {});
var listening = listeningTo[id];
// This object is not listening to any other events on `obj` yet.
// Setup the necessary references to track the listening callbacks.
if (!listening) {
var thisId = this._listenId || (this._listenId = _.uniqueId('l'));
listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0};
}
// Bind callbacks on obj, and keep track of them on listening.
internalOn(obj, name, callback, this, listening);
return this;
};
// The reducing API that adds a callback to the `events` object.
var onApi = function(events, name, callback, options) {
if (callback) {
var handlers = events[name] || (events[name] = []);
var context = options.context, ctx = options.ctx, listening = options.listening;
if (listening) listening.count++;
handlers.push({callback: callback, context: context, ctx: context || ctx, listening: listening});
}
return events;
};
// Remove one or many callbacks. If `context` is null, removes all
// callbacks with that function. If `callback` is null, removes all
// callbacks for the event. If `name` is null, removes all bound
// callbacks for all events.
Events.off = function(name, callback, context) {
if (!this._events) return this;
this._events = eventsApi(offApi, this._events, name, callback, {
context: context,
listeners: this._listeners
});
return this;
};
// Tell this object to stop listening to either specific events ... or
// to every object it's currently listening to.
Events.stopListening = function(obj, name, callback) {
var listeningTo = this._listeningTo;
if (!listeningTo) return this;
var ids = obj ? [obj._listenId] : _.keys(listeningTo);
for (var i = 0; i < ids.length; i++) {
var listening = listeningTo[ids[i]];
// If listening doesn't exist, this object is not currently
// listening to obj. Break out early.
if (!listening) break;
listening.obj.off(name, callback, this);
}
return this;
};
// The reducing API that removes a callback from the `events` object.
var offApi = function(events, name, callback, options) {
if (!events) return;
var i = 0, listening;
var context = options.context, listeners = options.listeners;
// Delete all events listeners and "drop" events.
if (!name && !callback && !context) {
var ids = _.keys(listeners);
for (; i < ids.length; i++) {
listening = listeners[ids[i]];
delete listeners[listening.id];
delete listening.listeningTo[listening.objId];
}
return;
}
var names = name ? [name] : _.keys(events);
for (; i < names.length; i++) {
name = names[i];
var handlers = events[name];
// Bail out if there are no events stored.
if (!handlers) break;
// Replace events if there are any remaining. Otherwise, clean up.
var remaining = [];
for (var j = 0; j < handlers.length; j++) {
var handler = handlers[j];
if (
callback && callback !== handler.callback &&
callback !== handler.callback._callback ||
context && context !== handler.context
) {
remaining.push(handler);
} else {
listening = handler.listening;
if (listening && --listening.count === 0) {
delete listeners[listening.id];
delete listening.listeningTo[listening.objId];
}
}
}
// Update tail event if the list has any events. Otherwise, clean up.
if (remaining.length) {
events[name] = remaining;
} else {
delete events[name];
}
}
return events;
};
// Bind an event to only be triggered a single time. After the first time
// the callback is invoked, its listener will be removed. If multiple events
// are passed in using the space-separated syntax, the handler will fire
// once for each event, not once for a combination of all events.
Events.once = function(name, callback, context) {
// Map the event into a `{event: once}` object.
var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this));
if (typeof name === 'string' && context == null) callback = void 0;
return this.on(events, callback, context);
};
// Inversion-of-control versions of `once`.
Events.listenToOnce = function(obj, name, callback) {
// Map the event into a `{event: once}` object.
var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj));
return this.listenTo(obj, events);
};
// Reduces the event callbacks into a map of `{event: onceWrapper}`.
// `offer` unbinds the `onceWrapper` after it has been called.
var onceMap = function(map, name, callback, offer) {
if (callback) {
var once = map[name] = _.once(function() {
offer(name, once);
callback.apply(this, arguments);
});
once._callback = callback;
}
return map;
};
// Trigger one or many events, firing all bound callbacks. Callbacks are
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
Events.trigger = function(name) {
if (!this._events) return this;
var length = Math.max(0, arguments.length - 1);
var args = Array(length);
for (var i = 0; i < length; i++) args[i] = arguments[i + 1];
eventsApi(triggerApi, this._events, name, void 0, args);
return this;
};
// Handles triggering the appropriate event callbacks.
var triggerApi = function(objEvents, name, callback, args) {
if (objEvents) {
var events = objEvents[name];
var allEvents = objEvents.all;
if (events && allEvents) allEvents = allEvents.slice();
if (events) triggerEvents(events, args);
if (allEvents) triggerEvents(allEvents, [name].concat(args));
}
return objEvents;
};
// A difficult-to-believe, but optimized internal dispatch function for
// triggering events. Tries to keep the usual cases speedy (most internal
// Backbone events have 3 arguments).
var triggerEvents = function(events, args) {
var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
switch (args.length) {
case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
}
};
// Aliases for backwards compatibility.
Events.bind = Events.on;
Events.unbind = Events.off;
// Allow the `Backbone` object to serve as a global event bus, for folks who
// want global "pubsub" in a convenient place.
_.extend(Backbone, Events);
// Backbone.Model
// --------------
// Backbone **Models** are the basic data object in the framework --
// frequently representing a row in a table in a database on your server.
// A discrete chunk of data and a bunch of useful, related methods for
// performing computations and transformations on that data.
// Create a new model with the specified attributes. A client id (`cid`)
// is automatically generated and assigned for you.
var Model = Backbone.Model = function(attributes, options) {
var attrs = attributes || {};
options || (options = {});
this.cid = _.uniqueId(this.cidPrefix);
this.attributes = {};
if (options.collection) this.collection = options.collection;
if (options.parse) attrs = this.parse(attrs, options) || {};
var defaults = _.result(this, 'defaults');
attrs = _.defaults(_.extend({}, defaults, attrs), defaults);
this.set(attrs, options);
this.changed = {};
this.initialize.apply(this, arguments);
};
// Attach all inheritable methods to the Model prototype.
_.extend(Model.prototype, Events, {
// A hash of attributes whose current and previous value differ.
changed: null,
// The value returned during the last failed validation.
validationError: null,
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
// CouchDB users may want to set this to `"_id"`.
idAttribute: 'id',
// The prefix is used to create the client id which is used to identify models locally.
// You may want to override this if you're experiencing name clashes with model ids.
cidPrefix: 'c',
// Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize: function(){},
// Return a copy of the model's `attributes` object.
toJSON: function(options) {
return _.clone(this.attributes);
},
// Proxy `Backbone.sync` by default -- but override this if you need
// custom syncing semantics for *this* particular model.
sync: function() {
return Backbone.sync.apply(this, arguments);
},
// Get the value of an attribute.
get: function(attr) {
return this.attributes[attr];
},
// Get the HTML-escaped value of an attribute.
escape: function(attr) {
return _.escape(this.get(attr));
},
// Returns `true` if the attribute contains a value that is not null
// or undefined.
has: function(attr) {
return this.get(attr) != null;
},
// Special-cased proxy to underscore's `_.matches` method.
matches: function(attrs) {
return !!_.iteratee(attrs, this)(this.attributes);
},
// Set a hash of model attributes on the object, firing `"change"`. This is
// the core primitive operation of a model, updating the data and notifying
// anyone who needs to know about the change in state. The heart of the beast.
set: function(key, val, options) {
if (key == null) return this;
// Handle both `"key", value` and `{key: value}` -style arguments.
var attrs;
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
options || (options = {});
// Run validation.
if (!this._validate(attrs, options)) return false;
// Extract attributes and options.
var unset = options.unset;
var silent = options.silent;
var changes = [];
var changing = this._changing;
this._changing = true;
if (!changing) {
this._previousAttributes = _.clone(this.attributes);
this.changed = {};
}
var current = this.attributes;
var changed = this.changed;
var prev = this._previousAttributes;
// For each `set` attribute, update or delete the current value.
for (var attr in attrs) {
val = attrs[attr];
if (!_.isEqual(current[attr], val)) changes.push(attr);
if (!_.isEqual(prev[attr], val)) {
changed[attr] = val;
} else {
delete changed[attr];
}
unset ? delete current[attr] : current[attr] = val;
}
// Update the `id`.
if (this.idAttribute in attrs) this.id = this.get(this.idAttribute);
// Trigger all relevant attribute changes.
if (!silent) {
if (changes.length) this._pending = options;
for (var i = 0; i < changes.length; i++) {
this.trigger('change:' + changes[i], this, current[changes[i]], options);
}
}
// You might be wondering why there's a `while` loop here. Changes can
// be recursively nested within `"change"` events.
if (changing) return this;
if (!silent) {
while (this._pending) {
options = this._pending;
this._pending = false;
this.trigger('change', this, options);
}
}
this._pending = false;
this._changing = false;
return this;
},
// Remove an attribute from the model, firing `"change"`. `unset` is a noop
// if the attribute doesn't exist.
unset: function(attr, options) {
return this.set(attr, void 0, _.extend({}, options, {unset: true}));
},
// Clear all attributes on the model, firing `"change"`.
clear: function(options) {
var attrs = {};
for (var key in this.attributes) attrs[key] = void 0;
return this.set(attrs, _.extend({}, options, {unset: true}));
},
// Determine if the model has changed since the last `"change"` event.
// If you specify an attribute name, determine if that attribute has changed.
hasChanged: function(attr) {
if (attr == null) return !_.isEmpty(this.changed);
return _.has(this.changed, attr);
},
// Return an object containing all the attributes that have changed, or
// false if there are no changed attributes. Useful for determining what
// parts of a view need to be updated and/or what attributes need to be
// persisted to the server. Unset attributes will be set to undefined.
// You can also pass an attributes object to diff against the model,
// determining if there *would be* a change.
changedAttributes: function(diff) {
if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
var old = this._changing ? this._previousAttributes : this.attributes;
var changed = {};
for (var attr in diff) {
var val = diff[attr];
if (_.isEqual(old[attr], val)) continue;
changed[attr] = val;
}
return _.size(changed) ? changed : false;
},
// Get the previous value of an attribute, recorded at the time the last
// `"change"` event was fired.
previous: function(attr) {
if (attr == null || !this._previousAttributes) return null;
return this._previousAttributes[attr];
},
// Get all of the attributes of the model at the time of the previous
// `"change"` event.
previousAttributes: function() {
return _.clone(this._previousAttributes);
},
// Fetch the model from the server, merging the response with the model's
// local attributes. Any changed attributes will trigger a "change" event.
fetch: function(options) {
options = _.extend({parse: true}, options);
var model = this;
var success = options.success;
options.success = function(resp) {
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
if (!model.set(serverAttrs, options)) return false;
if (success) success.call(options.context, model, resp, options);
model.trigger('sync', model, resp, options);
};
wrapError(this, options);
return this.sync('read', this, options);
},
// Set a hash of model attributes, and sync the model to the server.
// If the server returns an attributes hash that differs, the model's
// state will be `set` again.
save: function(key, val, options) {
// Handle both `"key", value` and `{key: value}` -style arguments.
var attrs;
if (key == null || typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
options = _.extend({validate: true, parse: true}, options);
var wait = options.wait;
// If we're not waiting and attributes exist, save acts as
// `set(attr).save(null, opts)` with validation. Otherwise, check if
// the model will be valid when the attributes, if any, are set.
if (attrs && !wait) {
if (!this.set(attrs, options)) return false;
} else if (!this._validate(attrs, options)) {
return false;
}
// After a successful server-side save, the client is (optionally)
// updated with the server-side state.
var model = this;
var success = options.success;
var attributes = this.attributes;
options.success = function(resp) {
// Ensure attributes are restored during synchronous saves.
model.attributes = attributes;
var serverAttrs = options.parse ? model.parse(resp, options) : resp;
if (wait) serverAttrs = _.extend({}, attrs, serverAttrs);
if (serverAttrs && !model.set(serverAttrs, options)) return false;
if (success) success.call(options.context, model, resp, options);
model.trigger('sync', model, resp, options);
};
wrapError(this, options);
// Set temporary attributes if `{wait: true}` to properly find new ids.
if (attrs && wait) this.attributes = _.extend({}, attributes, attrs);
var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
if (method === 'patch' && !options.attrs) options.attrs = attrs;
var xhr = this.sync(method, this, options);
// Restore attributes.
this.attributes = attributes;
return xhr;
},
// Destroy this model on the server if it was already persisted.
// Optimistically removes the model from its collection, if it has one.
// If `wait: true` is passed, waits for the server to respond before removal.
destroy: function(options) {
options = options ? _.clone(options) : {};
var model = this;
var success = options.success;
var wait = options.wait;
var destroy = function() {
model.stopListening();
model.trigger('destroy', model, model.collection, options);
};
options.success = function(resp) {
if (wait) destroy();
if (success) success.call(options.context, model, resp, options);
if (!model.isNew()) model.trigger('sync', model, resp, options);
};
var xhr = false;
if (this.isNew()) {
_.defer(options.success);
} else {
wrapError(this, options);
xhr = this.sync('delete', this, options);
}
if (!wait) destroy();
return xhr;
},
// Default URL for the model's representation on the server -- if you're
// using Backbone's restful methods, override this to change the endpoint
// that will be called.
url: function() {
var base =
_.result(this, 'urlRoot') ||
_.result(this.collection, 'url') ||
urlError();
if (this.isNew()) return base;
var id = this.get(this.idAttribute);
return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
},
// **parse** converts a response into the hash of attributes to be `set` on
// the model. The default implementation is just to pass the response along.
parse: function(resp, options) {
return resp;
},
// Create a new model with identical attributes to this one.
clone: function() {
return new this.constructor(this.attributes);
},
// A model is new if it has never been saved to the server, and lacks an id.
isNew: function() {
return !this.has(this.idAttribute);
},
// Check if the model is currently in a valid state.
isValid: function(options) {
return this._validate({}, _.extend({}, options, {validate: true}));
},
// Run validation against the next complete set of model attributes,
// returning `true` if all is well. Otherwise, fire an `"invalid"` event.
_validate: function(attrs, options) {
if (!options.validate || !this.validate) return true;
attrs = _.extend({}, this.attributes, attrs);
var error = this.validationError = this.validate(attrs, options) || null;
if (!error) return true;
this.trigger('invalid', this, error, _.extend(options, {validationError: error}));
return false;
}
});
// Underscore methods that we want to implement on the Model, mapped to the
// number of arguments they take.
var modelMethods = {keys: 1, values: 1, pairs: 1, invert: 1, pick: 0,
omit: 0, chain: 1, isEmpty: 1};
// Mix in each Underscore method as a proxy to `Model#attributes`.
addUnderscoreMethods(Model, modelMethods, 'attributes');
// Backbone.Collection
// -------------------
// If models tend to represent a single row of data, a Backbone Collection is
// more analogous to a table full of data ... or a small slice or page of that
// table, or a collection of rows that belong together for a particular reason
// -- all of the messages in this particular folder, all of the documents
// belonging to this particular author, and so on. Collections maintain
// indexes of their models, both in order, and for lookup by `id`.
// Create a new **Collection**, perhaps to contain a specific type of `model`.
// If a `comparator` is specified, the Collection will maintain
// its models in sort order, as they're added and removed.
var Collection = Backbone.Collection = function(models, options) {
options || (options = {});
if (options.model) this.model = options.model;
if (options.comparator !== void 0) this.comparator = options.comparator;
this._reset();
this.initialize.apply(this, arguments);
if (models) this.reset(models, _.extend({silent: true}, options));
};
// Default options for `Collection#set`.
var setOptions = {add: true, remove: true, merge: true};
var addOptions = {add: true, remove: false};
// Splices `insert` into `array` at index `at`.
var splice = function(array, insert, at) {
at = Math.min(Math.max(at, 0), array.length);
var tail = Array(array.length - at);
var length = insert.length;
var i;
for (i = 0; i < tail.length; i++) tail[i] = array[i + at];
for (i = 0; i < length; i++) array[i + at] = insert[i];
for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
};
// Define the Collection's inheritable methods.
_.extend(Collection.prototype, Events, {
// The default model for a collection is just a **Backbone.Model**.
// This should be overridden in most cases.
model: Model,
// Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize: function(){},
// The JSON representation of a Collection is an array of the
// models' attributes.
toJSON: function(options) {
return this.map(function(model) { return model.toJSON(options); });
},
// Proxy `Backbone.sync` by default.
sync: function() {
return Backbone.sync.apply(this, arguments);
},
// Add a model, or list of models to the set. `models` may be Backbone
// Models or raw JavaScript objects to be converted to Models, or any
// combination of the two.
add: function(models, options) {
return this.set(models, _.extend({merge: false}, options, addOptions));
},
// Remove a model, or a list of models from the set.
remove: function(models, options) {
options = _.extend({}, options);
var singular = !_.isArray(models);
models = singular ? [models] : models.slice();
var removed = this._removeModels(models, options);
if (!options.silent && removed.length) {
options.changes = {added: [], merged: [], removed: removed};
this.trigger('update', this, options);
}
return singular ? removed[0] : removed;
},
// Update a collection by `set`-ing a new list of models, adding new ones,
// removing models that are no longer present, and merging models that
// already exist in the collection, as necessary. Similar to **Model#set**,
// the core operation for updating the data contained by the collection.
set: function(models, options) {
if (models == null) return;
options = _.extend({}, setOptions, options);
if (options.parse && !this._isModel(models)) {
models = this.parse(models, options) || [];
}
var singular = !_.isArray(models);
models = singular ? [models] : models.slice();
var at = options.at;
if (at != null) at = +at;
if (at > this.length) at = this.length;
if (at < 0) at += this.length + 1;
var set = [];
var toAdd = [];
var toMerge = [];
var toRemove = [];
var modelMap = {};
var add = options.add;
var merge = options.merge;
var remove = options.remove;
var sort = false;
var sortable = this.comparator && at == null && options.sort !== false;
var sortAttr = _.isString(this.comparator) ? this.comparator : null;
// Turn bare objects into model references, and prevent invalid models
// from being added.
var model, i;
for (i = 0; i < models.length; i++) {
model = models[i];
// If a duplicate is found, prevent it from being added and
// optionally merge it into the existing model.
var existing = this.get(model);
if (existing) {
if (merge && model !== existing) {
var attrs = this._isModel(model) ? model.attributes : model;
if (options.parse) attrs = existing.parse(attrs, options);
existing.set(attrs, options);
toMerge.push(existing);
if (sortable && !sort) sort = existing.hasChanged(sortAttr);
}
if (!modelMap[existing.cid]) {
modelMap[existing.cid] = true;
set.push(existing);
}
models[i] = existing;
// If this is a new, valid model, push it to the `toAdd` list.
} else if (add) {
model = models[i] = this._prepareModel(model, options);
if (model) {
toAdd.push(model);
this._addReference(model, options);
modelMap[model.cid] = true;
set.push(model);
}
}
}
// Remove stale models.
if (remove) {
for (i = 0; i < this.length; i++) {
model = this.models[i];
if (!modelMap[model.cid]) toRemove.push(model);
}
if (toRemove.length) this._removeModels(toRemove, options);
}
// See if sorting is needed, update `length` and splice in new models.
var orderChanged = false;
var replace = !sortable && add && remove;
if (set.length && replace) {
orderChanged = this.length !== set.length || _.some(this.models, function(m, index) {
return m !== set[index];
});
this.models.length = 0;
splice(this.models, set, 0);
this.length = this.models.length;
} else if (toAdd.length) {
if (sortable) sort = true;
splice(this.models, toAdd, at == null ? this.length : at);
this.length = this.models.length;
}
// Silently sort the collection if appropriate.
if (sort) this.sort({silent: true});
// Unless silenced, it's time to fire all appropriate add/sort/update events.
if (!options.silent) {
for (i = 0; i < toAdd.length; i++) {
if (at != null) options.index = at + i;
model = toAdd[i];
model.trigger('add', model, this, options);
}
if (sort || orderChanged) this.trigger('sort', this, options);
if (toAdd.length || toRemove.length || toMerge.length) {
options.changes = {
added: toAdd,
removed: toRemove,
merged: toMerge
};
this.trigger('update', this, options);
}
}
// Return the added (or merged) model (or models).
return singular ? models[0] : models;
},
// When you have more items than you want to add or remove individually,
// you can reset the entire set with a new list of models, without firing
// any granular `add` or `remove` events. Fires `reset` when finished.
// Useful for bulk operations and optimizations.
reset: function(models, options) {
options = options ? _.clone(options) : {};
for (var i = 0; i < this.models.length; i++) {
this._removeReference(this.models[i], options);
}
options.previousModels = this.models;
this._reset();
models = this.add(models, _.extend({silent: true}, options));
if (!options.silent) this.trigger('reset', this, options);
return models;
},
// Add a model to the end of the collection.
push: function(model, options) {
return this.add(model, _.extend({at: this.length}, options));
},
// Remove a model from the end of the collection.
pop: function(options) {
var model = this.at(this.length - 1);
return this.remove(model, options);
},
// Add a model to the beginning of the collection.
unshift: function(model, options) {
return this.add(model, _.extend({at: 0}, options));
},
// Remove a model from the beginning of the collection.
shift: function(options) {
var model = this.at(0);
return this.remove(model, options);
},
// Slice out a sub-array of models from the collection.
slice: function() {
return slice.apply(this.models, arguments);
},
// Get a model from the set by id, cid, model object with id or cid
// properties, or an attributes object that is transformed through modelId.
get: function(obj) {
if (obj == null) return void 0;
return this._byId[obj] ||
this._byId[this.modelId(obj.attributes || obj)] ||
obj.cid && this._byId[obj.cid];
},
// Returns `true` if the model is in the collection.
has: function(obj) {
return this.get(obj) != null;
},
// Get the model at the given index.
at: function(index) {
if (index < 0) index += this.length;
return this.models[index];
},
// Return models with matching attributes. Useful for simple cases of
// `filter`.
where: function(attrs, first) {
return this[first ? 'find' : 'filter'](attrs);
},
// Return the first model with matching attributes. Useful for simple cases
// of `find`.
findWhere: function(attrs) {
return this.where(attrs, true);
},
// Force the collection to re-sort itself. You don't need to call this under
// normal circumstances, as the set will maintain sort order as each item
// is added.
sort: function(options) {
var comparator = this.comparator;
if (!comparator) throw new Error('Cannot sort a set without a comparator');
options || (options = {});
var length = comparator.length;
if (_.isFunction(comparator)) comparator = _.bind(comparator, this);
// Run sort based on type of `comparator`.
if (length === 1 || _.isString(comparator)) {
this.models = this.sortBy(comparator);
} else {
this.models.sort(comparator);
}
if (!options.silent) this.trigger('sort', this, options);
return this;
},
// Pluck an attribute from each model in the collection.
pluck: function(attr) {
return this.map(attr + '');
},
// Fetch the default set of models for this collection, resetting the
// collection when they arrive. If `reset: true` is passed, the response
// data will be passed through the `reset` method instead of `set`.
fetch: function(options) {
options = _.extend({parse: true}, options);
var success = options.success;
var collection = this;
options.success = function(resp) {
var method = options.reset ? 'reset' : 'set';
collection[method](resp, options);
if (success) success.call(options.context, collection, resp, options);
collection.trigger('sync', collection, resp, options);
};
wrapError(this, options);
return this.sync('read', this, options);
},
// Create a new instance of a model in this collection. Add the model to the
// collection immediately, unless `wait: true` is passed, in which case we
// wait for the server to agree.
create: function(model, options) {
options = options ? _.clone(options) : {};
var wait = options.wait;
model = this._prepareModel(model, options);
if (!model) return false;
if (!wait) this.add(model, options);
var collection = this;
var success = options.success;
options.success = function(m, resp, callbackOpts) {
if (wait) collection.add(m, callbackOpts);
if (success) success.call(callbackOpts.context, m, resp, callbackOpts);
};
model.save(null, options);
return model;
},
// **parse** converts a response into a list of models to be added to the
// collection. The default implementation is just to pass it through.
parse: function(resp, options) {
return resp;
},
// Create a new collection with an identical list of models as this one.
clone: function() {
return new this.constructor(this.models, {
model: this.model,
comparator: this.comparator
});
},
// Define how to uniquely identify models in the collection.
modelId: function(attrs) {
return attrs[this.model.prototype.idAttribute || 'id'];
},
// Private method to reset all internal state. Called when the collection
// is first initialized or reset.
_reset: function() {
this.length = 0;
this.models = [];
this._byId = {};
},
// Prepare a hash of attributes (or other model) to be added to this
// collection.
_prepareModel: function(attrs, options) {
if (this._isModel(attrs)) {
if (!attrs.collection) attrs.collection = this;
return attrs;
}
options = options ? _.clone(options) : {};
options.collection = this;
var model = new this.model(attrs, options);
if (!model.validationError) return model;
this.trigger('invalid', this, model.validationError, options);
return false;
},
// Internal method called by both remove and set.
_removeModels: function(models, options) {
var removed = [];
for (var i = 0; i < models.length; i++) {
var model = this.get(models[i]);
if (!model) continue;
var index = this.indexOf(model);
this.models.splice(index, 1);
this.length--;
// Remove references before triggering 'remove' event to prevent an
// infinite loop. #3693
delete this._byId[model.cid];
var id = this.modelId(model.attributes);
if (id != null) delete this._byId[id];
if (!options.silent) {
options.index = index;
model.trigger('remove', model, this, options);
}
removed.push(model);
this._removeReference(model, options);
}
return removed;
},
// Method for checking whether an object should be considered a model for
// the purposes of adding to the collection.
_isModel: function(model) {
return model instanceof Model;
},
// Internal method to create a model's ties to a collection.
_addReference: function(model, options) {
this._byId[model.cid] = model;
var id = this.modelId(model.attributes);
if (id != null) this._byId[id] = model;
model.on('all', this._onModelEvent, this);
},
// Internal method to sever a model's ties to a collection.
_removeReference: function(model, options) {
delete this._byId[model.cid];
var id = this.modelId(model.attributes);
if (id != null) delete this._byId[id];
if (this === model.collection) delete model.collection;
model.off('all', this._onModelEvent, this);
},
// Internal method called every time a model in the set fires an event.
// Sets need to update their indexes when models change ids. All other
// events simply proxy through. "add" and "remove" events that originate
// in other collections are ignored.
_onModelEvent: function(event, model, collection, options) {
if (model) {
if ((event === 'add' || event === 'remove') && collection !== this) return;
if (event === 'destroy') this.remove(model, options);
if (event === 'change') {
var prevId = this.modelId(model.previousAttributes());
var id = this.modelId(model.attributes);
if (prevId !== id) {
if (prevId != null) delete this._byId[prevId];
if (id != null) this._byId[id] = model;
}
}
}
this.trigger.apply(this, arguments);
}
});
// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var collectionMethods = {forEach: 3, each: 3, map: 3, collect: 3, reduce: 0,
foldl: 0, inject: 0, reduceRight: 0, foldr: 0, find: 3, detect: 3, filter: 3,
select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 3, includes: 3,
contains: 3, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3,
head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3,
without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
isEmpty: 1, chain: 1, sample: 3, partition: 3, groupBy: 3, countBy: 3,
sortBy: 3, indexBy: 3, findIndex: 3, findLastIndex: 3};
// Mix in each Underscore method as a proxy to `Collection#models`.
addUnderscoreMethods(Collection, collectionMethods, 'models');
// Backbone.View
// -------------
// Backbone Views are almost more convention than they are actual code. A View
// is simply a JavaScript object that represents a logical chunk of UI in the
// DOM. This might be a single item, an entire list, a sidebar or panel, or
// even the surrounding frame which wraps your whole app. Defining a chunk of
// UI as a **View** allows you to define your DOM events declaratively, without
// having to worry about render order ... and makes it easy for the view to
// react to specific changes in the state of your models.
// Creating a Backbone.View creates its initial element outside of the DOM,
// if an existing element is not provided...
var View = Backbone.View = function(options) {
this.cid = _.uniqueId('view');
_.extend(this, _.pick(options, viewOptions));
this._ensureElement();
this.initialize.apply(this, arguments);
};
// Cached regex to split keys for `delegate`.
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
// List of view options to be set as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
// Set up all inheritable **Backbone.View** properties and methods.
_.extend(View.prototype, Events, {
// The default `tagName` of a View's element is `"div"`.
tagName: 'div',
// jQuery delegate for element lookup, scoped to DOM elements within the
// current view. This should be preferred to global lookups where possible.
$: function(selector) {
return this.$el.find(selector);
},
// Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize: function(){},
// **render** is the core function that your view should override, in order
// to populate its element (`this.el`), with the appropriate HTML. The
// convention is for **render** to always return `this`.
render: function() {
return this;
},
// Remove this view by taking the element out of the DOM, and removing any
// applicable Backbone.Events listeners.
remove: function() {
this._removeElement();
this.stopListening();
return this;
},
// Remove this view's element from the document and all event listeners
// attached to it. Exposed for subclasses using an alternative DOM
// manipulation API.
_removeElement: function() {
this.$el.remove();
},
// Change the view's element (`this.el` property) and re-delegate the
// view's events on the new element.
setElement: function(element) {
this.undelegateEvents();
this._setElement(element);
this.delegateEvents();
return this;
},
// Creates the `this.el` and `this.$el` references for this view using the
// given `el`. `el` can be a CSS selector or an HTML string, a jQuery
// context or an element. Subclasses can override this to utilize an
// alternative DOM manipulation API and are only required to set the
// `this.el` property.
_setElement: function(el) {
this.$el = el instanceof Backbone.$ ? el : Backbone.$(el);
this.el = this.$el[0];
},
// Set callbacks, where `this.events` is a hash of
//
// *{"event selector": "callback"}*
//
// {
// 'mousedown .title': 'edit',
// 'click .button': 'save',
// 'click .open': function(e) { ... }
// }
//
// pairs. Callbacks will be bound to the view, with `this` set properly.
// Uses event delegation for efficiency.
// Omitting the selector binds the event to `this.el`.
delegateEvents: function(events) {
events || (events = _.result(this, 'events'));
if (!events) return this;
this.undelegateEvents();
for (var key in events) {
var method = events[key];
if (!_.isFunction(method)) method = this[method];
if (!method) continue;
var match = key.match(delegateEventSplitter);
this.delegate(match[1], match[2], _.bind(method, this));
}
return this;
},
// Add a single event listener to the view's element (or a child element
// using `selector`). This only works for delegate-able events: not `focus`,
// `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
delegate: function(eventName, selector, listener) {
this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
return this;
},
// Clears all callbacks previously bound to the view by `delegateEvents`.
// You usually don't need to use this, but may wish to if you have multiple
// Backbone views attached to the same DOM element.
undelegateEvents: function() {
if (this.$el) this.$el.off('.delegateEvents' + this.cid);
return this;
},
// A finer-grained `undelegateEvents` for removing a single delegated event.
// `selector` and `listener` are both optional.
undelegate: function(eventName, selector, listener) {
this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
return this;
},
// Produces a DOM element to be assigned to your view. Exposed for
// subclasses using an alternative DOM manipulation API.
_createElement: function(tagName) {
return document.createElement(tagName);
},
// Ensure that the View has a DOM element to render into.
// If `this.el` is a string, pass it through `$()`, take the first
// matching element, and re-assign it to `el`. Otherwise, create
// an element from the `id`, `className` and `tagName` properties.
_ensureElement: function() {
if (!this.el) {
var attrs = _.extend({}, _.result(this, 'attributes'));
if (this.id) attrs.id = _.result(this, 'id');
if (this.className) attrs['class'] = _.result(this, 'className');
this.setElement(this._createElement(_.result(this, 'tagName')));
this._setAttributes(attrs);
} else {
this.setElement(_.result(this, 'el'));
}
},
// Set attributes from a hash on this view's element. Exposed for
// subclasses using an alternative DOM manipulation API.
_setAttributes: function(attributes) {
this.$el.attr(attributes);
}
});
// Backbone.sync
// -------------
// Override this function to change the manner in which Backbone persists
// models to the server. You will be passed the type of request, and the
// model in question. By default, makes a RESTful Ajax request
// to the model's `url()`. Some possible customizations could be:
//
// * Use `setTimeout` to batch rapid-fire updates into a single request.
// * Send up the models as XML instead of JSON.
// * Persist models via WebSockets instead of Ajax.
//
// Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
// as `POST`, with a `_method` parameter containing the true HTTP method,
// as well as all requests with the body as `application/x-www-form-urlencoded`
// instead of `application/json` with the model in a param named `model`.
// Useful when interfacing with server-side languages like **PHP** that make
// it difficult to read the body of `PUT` requests.
Backbone.sync = function(method, model, options) {
var type = methodMap[method];
// Default options, unless specified.
_.defaults(options || (options = {}), {
emulateHTTP: Backbone.emulateHTTP,
emulateJSON: Backbone.emulateJSON
});
// Default JSON-request options.
var params = {type: type, dataType: 'json'};
// Ensure that we have a URL.
if (!options.url) {
params.url = _.result(model, 'url') || urlError();
}
// Ensure that we have the appropriate request data.
if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
params.contentType = 'application/json';
params.data = JSON.stringify(options.attrs || model.toJSON(options));
}
// For older servers, emulate JSON by encoding the request into an HTML-form.
if (options.emulateJSON) {
params.contentType = 'application/x-www-form-urlencoded';
params.data = params.data ? {model: params.data} : {};
}
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
params.type = 'POST';
if (options.emulateJSON) params.data._method = type;
var beforeSend = options.beforeSend;
options.beforeSend = function(xhr) {
xhr.setRequestHeader('X-HTTP-Method-Override', type);
if (beforeSend) return beforeSend.apply(this, arguments);
};
}
// Don't process data on a non-GET request.
if (params.type !== 'GET' && !options.emulateJSON) {
params.processData = false;
}
// Pass along `textStatus` and `errorThrown` from jQuery.
var error = options.error;
options.error = function(xhr, textStatus, errorThrown) {
options.textStatus = textStatus;
options.errorThrown = errorThrown;
if (error) error.call(options.context, xhr, textStatus, errorThrown);
};
// Make the request, allowing the user to override any Ajax options.
var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
model.trigger('request', model, xhr, options);
return xhr;
};
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
var methodMap = {
'create': 'POST',
'update': 'PUT',
'patch': 'PATCH',
'delete': 'DELETE',
'read': 'GET'
};
// Set the default implementation of `Backbone.ajax` to proxy through to `$`.
// Override this if you'd like to use a different library.
Backbone.ajax = function() {
return Backbone.$.ajax.apply(Backbone.$, arguments);
};
// Backbone.Router
// ---------------
// Routers map faux-URLs to actions, and fire events when routes are
// matched. Creating a new one sets its `routes` hash, if not set statically.
var Router = Backbone.Router = function(options) {
options || (options = {});
if (options.routes) this.routes = options.routes;
this._bindRoutes();
this.initialize.apply(this, arguments);
};
// Cached regular expressions for matching named param parts and splatted
// parts of route strings.
var optionalParam = /\((.*?)\)/g;
var namedParam = /(\(\?)?:\w+/g;
var splatParam = /\*\w+/g;
var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
// Set up all inheritable **Backbone.Router** properties and methods.
_.extend(Router.prototype, Events, {
// Initialize is an empty function by default. Override it with your own
// initialization logic.
initialize: function(){},
// Manually bind a single named route to a callback. For example:
//
// this.route('search/:query/p:num', 'search', function(query, num) {
// ...
// });
//
route: function(route, name, callback) {
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (_.isFunction(name)) {
callback = name;
name = '';
}
if (!callback) callback = this[name];
var router = this;
Backbone.history.route(route, function(fragment) {
var args = router._extractParameters(route, fragment);
if (router.execute(callback, args, name) !== false) {
router.trigger.apply(router, ['route:' + name].concat(args));
router.trigger('route', name, args);
Backbone.history.trigger('route', router, name, args);
}
});
return this;
},
// Execute a route handler with the provided parameters. This is an
// excellent place to do pre-route setup or post-route cleanup.
execute: function(callback, args, name) {
if (callback) callback.apply(this, args);
},
// Simple proxy to `Backbone.history` to save a fragment into the history.
navigate: function(fragment, options) {
Backbone.history.navigate(fragment, options);
return this;
},
// Bind all defined routes to `Backbone.history`. We have to reverse the
// order of the routes here to support behavior where the most general
// routes can be defined at the bottom of the route map.
_bindRoutes: function() {
if (!this.routes) return;
this.routes = _.result(this, 'routes');
var route, routes = _.keys(this.routes);
while ((route = routes.pop()) != null) {
this.route(route, this.routes[route]);
}
},
// Convert a route string into a regular expression, suitable for matching
// against the current location hash.
_routeToRegExp: function(route) {
route = route.replace(escapeRegExp, '\\$&')
.replace(optionalParam, '(?:$1)?')
.replace(namedParam, function(match, optional) {
return optional ? match : '([^/?]+)';
})
.replace(splatParam, '([^?]*?)');
return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$');
},
// Given a route, and a URL fragment that it matches, return the array of
// extracted decoded parameters. Empty or unmatched parameters will be
// treated as `null` to normalize cross-browser behavior.
_extractParameters: function(route, fragment) {
var params = route.exec(fragment).slice(1);
return _.map(params, function(param, i) {
// Don't decode the search params.
if (i === params.length - 1) return param || null;
return param ? decodeURIComponent(param) : null;
});
}
});
// Backbone.History
// ----------------
// Handles cross-browser history management, based on either
// [pushState](http://diveintohtml5.info/history.html) and real URLs, or
// [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
// and URL fragments. If the browser supports neither (old IE, natch),
// falls back to polling.
var History = Backbone.History = function() {
this.handlers = [];
this.checkUrl = _.bind(this.checkUrl, this);
// Ensure that `History` can be used outside of the browser.
if (typeof window !== 'undefined') {
this.location = window.location;
this.history = window.history;
}
};
// Cached regex for stripping a leading hash/slash and trailing space.
var routeStripper = /^[#\/]|\s+$/g;
// Cached regex for stripping leading and trailing slashes.
var rootStripper = /^\/+|\/+$/g;
// Cached regex for stripping urls of hash.
var pathStripper = /#.*$/;
// Has the history handling already been started?
History.started = false;
// Set up all inheritable **Backbone.History** properties and methods.
_.extend(History.prototype, Events, {
// The default interval to poll for hash changes, if necessary, is
// twenty times a second.
interval: 50,
// Are we at the app root?
atRoot: function() {
var path = this.location.pathname.replace(/[^\/]$/, '$&/');
return path === this.root && !this.getSearch();
},
// Does the pathname match the root?
matchRoot: function() {
var path = this.decodeFragment(this.location.pathname);
var rootPath = path.slice(0, this.root.length - 1) + '/';
return rootPath === this.root;
},
// Unicode characters in `location.pathname` are percent encoded so they're
// decoded for comparison. `%25` should not be decoded since it may be part
// of an encoded parameter.
decodeFragment: function(fragment) {
return decodeURI(fragment.replace(/%25/g, '%2525'));
},
// In IE6, the hash fragment and search params are incorrect if the
// fragment contains `?`.
getSearch: function() {
var match = this.location.href.replace(/#.*/, '').match(/\?.+/);
return match ? match[0] : '';
},
// Gets the true hash value. Cannot use location.hash directly due to bug
// in Firefox where location.hash will always be decoded.
getHash: function(window) {
var match = (window || this).location.href.match(/#(.*)$/);
return match ? match[1] : '';
},
// Get the pathname and search params, without the root.
getPath: function() {
var path = this.decodeFragment(
this.location.pathname + this.getSearch()
).slice(this.root.length - 1);
return path.charAt(0) === '/' ? path.slice(1) : path;
},
// Get the cross-browser normalized URL fragment from the path or hash.
getFragment: function(fragment) {
if (fragment == null) {
if (this._usePushState || !this._wantsHashChange) {
fragment = this.getPath();
} else {
fragment = this.getHash();
}
}
return fragment.replace(routeStripper, '');
},
// Start the hash change handling, returning `true` if the current URL matches
// an existing route, and `false` otherwise.
start: function(options) {
if (History.started) throw new Error('Backbone.history has already been started');
History.started = true;
// Figure out the initial configuration. Do we need an iframe?
// Is pushState desired ... is it available?
this.options = _.extend({root: '/'}, this.options, options);
this.root = this.options.root;
this._wantsHashChange = this.options.hashChange !== false;
this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7);
this._useHashChange = this._wantsHashChange && this._hasHashChange;
this._wantsPushState = !!this.options.pushState;
this._hasPushState = !!(this.history && this.history.pushState);
this._usePushState = this._wantsPushState && this._hasPushState;
this.fragment = this.getFragment();
// Normalize root to always include a leading and trailing slash.
this.root = ('/' + this.root + '/').replace(rootStripper, '/');
// Transition from hashChange to pushState or vice versa if both are
// requested.
if (this._wantsHashChange && this._wantsPushState) {
// If we've started off with a route from a `pushState`-enabled
// browser, but we're currently in a browser that doesn't support it...
if (!this._hasPushState && !this.atRoot()) {
var rootPath = this.root.slice(0, -1) || '/';
this.location.replace(rootPath + '#' + this.getPath());
// Return immediately as browser will do redirect to new url
return true;
// Or if we've started out with a hash-based route, but we're currently
// in a browser where it could be `pushState`-based instead...
} else if (this._hasPushState && this.atRoot()) {
this.navigate(this.getHash(), {replace: true});
}
}
// Proxy an iframe to handle location events if the browser doesn't
// support the `hashchange` event, HTML5 history, or the user wants
// `hashChange` but not `pushState`.
if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) {
this.iframe = document.createElement('iframe');
this.iframe.src = 'javascript:0';
this.iframe.style.display = 'none';
this.iframe.tabIndex = -1;
var body = document.body;
// Using `appendChild` will throw on IE < 9 if the document is not ready.
var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow;
iWindow.document.open();
iWindow.document.close();
iWindow.location.hash = '#' + this.fragment;
}
// Add a cross-platform `addEventListener` shim for older browsers.
var addEventListener = window.addEventListener || function(eventName, listener) {
return attachEvent('on' + eventName, listener);
};
// Depending on whether we're using pushState or hashes, and whether
// 'onhashchange' is supported, determine how we check the URL state.
if (this._usePushState) {
addEventListener('popstate', this.checkUrl, false);
} else if (this._useHashChange && !this.iframe) {
addEventListener('hashchange', this.checkUrl, false);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
if (!this.options.silent) return this.loadUrl();
},
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
// but possibly useful for unit testing Routers.
stop: function() {
// Add a cross-platform `removeEventListener` shim for older browsers.
var removeEventListener = window.removeEventListener || function(eventName, listener) {
return detachEvent('on' + eventName, listener);
};
// Remove window listeners.
if (this._usePushState) {
removeEventListener('popstate', this.checkUrl, false);
} else if (this._useHashChange && !this.iframe) {
removeEventListener('hashchange', this.checkUrl, false);
}
// Clean up the iframe if necessary.
if (this.iframe) {
document.body.removeChild(this.iframe);
this.iframe = null;
}
// Some environments will throw when clearing an undefined interval.
if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
History.started = false;
},
// Add a route to be tested when the fragment changes. Routes added later
// may override previous routes.
route: function(route, callback) {
this.handlers.unshift({route: route, callback: callback});
},
// Checks the current URL to see if it has changed, and if it has,
// calls `loadUrl`, normalizing across the hidden iframe.
checkUrl: function(e) {
var current = this.getFragment();
// If the user pressed the back button, the iframe's hash will have
// changed and we should use that for comparison.
if (current === this.fragment && this.iframe) {
current = this.getHash(this.iframe.contentWindow);
}
if (current === this.fragment) return false;
if (this.iframe) this.navigate(current);
this.loadUrl();
},
// Attempt to load the current URL fragment. If a route succeeds with a
// match, returns `true`. If no defined routes matches the fragment,
// returns `false`.
loadUrl: function(fragment) {
// If the root doesn't match, no routes can match either.
if (!this.matchRoot()) return false;
fragment = this.fragment = this.getFragment(fragment);
return _.some(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
handler.callback(fragment);
return true;
}
});
},
// Save a fragment into the hash history, or replace the URL state if the
// 'replace' option is passed. You are responsible for properly URL-encoding
// the fragment in advance.
//
// The options object can contain `trigger: true` if you wish to have the
// route callback be fired (not usually desirable), or `replace: true`, if
// you wish to modify the current URL without adding an entry to the history.
navigate: function(fragment, options) {
if (!History.started) return false;
if (!options || options === true) options = {trigger: !!options};
// Normalize the fragment.
fragment = this.getFragment(fragment || '');
// Don't include a trailing slash on the root.
var rootPath = this.root;
if (fragment === '' || fragment.charAt(0) === '?') {
rootPath = rootPath.slice(0, -1) || '/';
}
var url = rootPath + fragment;
// Strip the hash and decode for matching.
fragment = this.decodeFragment(fragment.replace(pathStripper, ''));
if (this.fragment === fragment) return;
this.fragment = fragment;
// If pushState is available, we use it to set the fragment as a real URL.
if (this._usePushState) {
this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
// If hash changes haven't been explicitly disabled, update the hash
// fragment to store history.
} else if (this._wantsHashChange) {
this._updateHash(this.location, fragment, options.replace);
if (this.iframe && fragment !== this.getHash(this.iframe.contentWindow)) {
var iWindow = this.iframe.contentWindow;
// Opening and closing the iframe tricks IE7 and earlier to push a
// history entry on hash-tag change. When replace is true, we don't
// want this.
if (!options.replace) {
iWindow.document.open();
iWindow.document.close();
}
this._updateHash(iWindow.location, fragment, options.replace);
}
// If you've told us that you explicitly don't want fallback hashchange-
// based history, then `navigate` becomes a page refresh.
} else {
return this.location.assign(url);
}
if (options.trigger) return this.loadUrl(fragment);
},
// Update the hash location, either replacing the current entry, or adding
// a new one to the browser history.
_updateHash: function(location, fragment, replace) {
if (replace) {
var href = location.href.replace(/(javascript:|#).*$/, '');
location.replace(href + '#' + fragment);
} else {
// Some browsers require that `hash` contains a leading #.
location.hash = '#' + fragment;
}
}
});
// Create the default Backbone.history.
Backbone.history = new History;
// Helpers
// -------
// Helper function to correctly set up the prototype chain for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
var extend = function(protoProps, staticProps) {
var parent = this;
var child;
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent constructor.
if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ return parent.apply(this, arguments); };
}
// Add static properties to the constructor function, if supplied.
_.extend(child, parent, staticProps);
// Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function and add the prototype properties.
child.prototype = _.create(parent.prototype, protoProps);
child.prototype.constructor = child;
// Set a convenience property in case the parent's prototype is needed
// later.
child.__super__ = parent.prototype;
return child;
};
// Set up inheritance for the model, collection, router, view and history.
Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
// Throw an error when a URL is needed, and none is supplied.
var urlError = function() {
throw new Error('A "url" property or function must be specified');
};
// Wrap an optional error callback with a fallback error event.
var wrapError = function(model, options) {
var error = options.error;
options.error = function(resp) {
if (error) error.call(options.context, model, resp, options);
model.trigger('error', model, resp, options);
};
};
return Backbone;
});
{
"name": "backbone",
"description": "Give your JS App some Backbone with Models, Views, Collections, and Events.",
"url": "http://backbonejs.org",
"keywords": [
"model",
"view",
"controller",
"router",
"server",
"client",
"browser"
],
"author": "Jeremy Ashkenas",
"dependencies": {
"underscore": ">=1.8.3"
},
"devDependencies": {
"coffee-script": "1.7.1",
"docco": "0.7.0",
"eslint": "1.10.x",
"karma": "^0.13.13",
"karma-phantomjs-launcher": "^0.1.4",
"karma-qunit": "^0.1.5",
"qunitjs": "^1.18.0",
"uglify-js": "^2.4.17"
},
"scripts": {
"test": "karma start && coffee test/model.coffee && npm run lint",
"build": "uglifyjs backbone.js --mangle --source-map backbone-min.map -o backbone-min.js",
"doc": "docco backbone.js && docco examples/todos/todos.js examples/backbone.localStorage.js",
"lint": "eslint backbone.js test/*.js"
},
"main": "backbone.js",
"version": "1.3.3",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/jashkenas/backbone.git"
},
"files": [
"backbone.js",
"backbone-min.js",
"backbone-min.map",
"LICENSE"
]
}
.DS_Store
# Codemirror formatting addon
The original one from http://codemirror.net/2/demo/formatting.html but with module loader
{
"name": "codemirror-formatting",
"version": "1.0.1",
"main": ["formatting.js"],
"ignore": [
"**/.*",
"*.yml",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"codemirror": ">= 4.3.0"
}
}
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("codemirror/lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["codemirror/lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
CodeMirror.extendMode("css", {
commentStart: "/*",
commentEnd: "*/",
newlineAfterToken: function(_type, content) {
return /^[;{}]$/.test(content);
}
});
CodeMirror.extendMode("javascript", {
commentStart: "/*",
commentEnd: "*/",
// FIXME semicolons inside of for
newlineAfterToken: function(_type, content, textAfter, state) {
if (this.jsonMode) {
return /^[\[,{]$/.test(content) || /^}/.test(textAfter);
} else {
if (content == ";" && state.lexical && state.lexical.type == ")") return false;
return /^[;{}]$/.test(content) && !/^;/.test(textAfter);
}
}
});
var inlineElements = /^(a|abbr|acronym|area|base|bdo|big|br|button|caption|cite|code|col|colgroup|dd|del|dfn|em|frame|hr|iframe|img|input|ins|kbd|label|legend|link|map|object|optgroup|option|param|q|samp|script|select|small|span|strong|sub|sup|textarea|tt|var)$/;
CodeMirror.extendMode("xml", {
commentStart: "<!--",
commentEnd: "-->",
newlineAfterToken: function(type, content, textAfter, state) {
var inline = false;
if (this.configuration == "html")
inline = state.context ? inlineElements.test(state.context.tagName) : false;
return !inline && ((type == "tag" && />$/.test(content) && state.context) ||
/^</.test(textAfter));
}
});
// Comment/uncomment the specified range
CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
var cm = this, curMode = CodeMirror.innerMode(cm.getMode(), cm.getTokenAt(from).state).mode;
cm.operation(function() {
if (isComment) { // Comment range
cm.replaceRange(curMode.commentEnd, to);
cm.replaceRange(curMode.commentStart, from);
if (from.line == to.line && from.ch == to.ch) // An empty comment inserted - put cursor inside
cm.setCursor(from.line, from.ch + curMode.commentStart.length);
} else { // Uncomment range
var selText = cm.getRange(from, to);
var startIndex = selText.indexOf(curMode.commentStart);
var endIndex = selText.lastIndexOf(curMode.commentEnd);
if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
// Take string till comment start
selText = selText.substr(0, startIndex) +
// From comment start till comment end
selText.substring(startIndex + curMode.commentStart.length, endIndex) +
// From comment end till string end
selText.substr(endIndex + curMode.commentEnd.length);
}
cm.replaceRange(selText, from, to);
}
});
});
// Applies automatic mode-aware indentation to the specified range
CodeMirror.defineExtension("autoIndentRange", function (from, to) {
var cmInstance = this;
this.operation(function () {
for (var i = from.line; i <= to.line; i++) {
cmInstance.indentLine(i, "smart");
}
});
});
// Applies automatic formatting to the specified range
CodeMirror.defineExtension("autoFormatRange", function (from, to) {
var cm = this;
var outer = cm.getMode(), text = cm.getRange(from, to).split("\n");
var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state);
var tabSize = cm.getOption("tabSize");
var out = "", lines = 0, atSol = from.ch === 0;
function newline() {
out += "\n";
atSol = true;
++lines;
}
for (var i = 0; i < text.length; ++i) {
var stream = new CodeMirror.StringStream(text[i], tabSize);
while (!stream.eol()) {
var inner = CodeMirror.innerMode(outer, state);
var style = outer.token(stream, state), cur = stream.current();
stream.start = stream.pos;
if (!atSol || /\S/.test(cur)) {
out += cur;
atSol = false;
}
if (!atSol && inner.mode.newlineAfterToken &&
inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state))
newline();
}
if (!stream.pos && outer.blankLine) outer.blankLine(state);
if (!atSol && i < text.length - 1) newline();
}
cm.operation(function () {
cm.replaceRange(out, from, to);
for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur)
cm.indentLine(cur, "smart");
cm.setSelection(from, cm.getCursor(false));
});
});
});
{
"name": "codemirror-formatting",
"version": "1.0.0",
"description": "Codemirror formatting addon http://codemirror.net/2/demo/formatting.html",
"main": "formatting.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/artf/codemirror-formatting.git"
},
"keywords": [
"codemirror",
"formatting"
],
"author": "",
"license": "MIT",
"bugs": {
"url": "https://github.com/artf/codemirror-formatting/issues"
},
"homepage": "https://github.com/artf/codemirror-formatting#readme"
}
List of CodeMirror contributors. Updated before every release.
4oo4
4r2r
Aaron Brooks
Abdelouahab
Abdussalam Abdurrahman
Abe Fettig
Abhishek Gahlot
Adam Ahmed
Adam King
Adam Particka
Adam Wight
adanlobato
Adán Lobato
Aditya Toshniwal
Adrian Aichner
Adrian Heine
Adrian Kunz
Adrien Bertrand
aeroson
Ahmad Amireh
Ahmad M. Zawawi
AHOHNMYC
ahoward
Ajin Abraham
Akeksandr Motsjonov
Alasdair Smith
AlbertHilb
Alberto González Palomo
Alberto Pose
Albert Xing
Alexander Marks
Alexander Pavlov
Alexander Schepanovski
Alexander Shvets
Alexander Solovyov
Alexandre Bique
Alex Churchill
alexey-k
Alex Piggott
Alf Eaton
Aliaksei Chapyzhenka
Allen Sarkisyan
Ami Fischman
Amin Shali
Amin Ullah Khan
amshali@google.com
Amsul
amuntean
Amy
Ananya Sen
anaran
AndersMad
Anders Nawroth
Anderson Mesquita
Anders Wåglund
Andrea G
Andreas Reischuck
Andres Taylor
Andre von Houck
Andrew Cheng
Andrew Dassonville
Andrey Fedorov
Andrey Klyuchnikov
Andrey Lushnikov
Andrey Shchekin
Andy Joslin
Andy Kimball
Andy Li
Angelo
angelozerr
angelo.zerr@gmail.com
Ankit
Ankit Ahuja
Ansel Santosa
Anthony Dugois
anthonygego
Anthony Gégo
Anthony Grimes
Anthony Stewart
Anton Kovalyov
antosarho
aoki ken
Apollo Zhu
AQNOUCH Mohammed
Aram Shatakhtsyan
areos
Arnab Bose
Arnoud Buzing
Arsène von Wyss
Arthur Müller
Arun Narasani
as3boyan
asolove
atelierbram
AtomicPages LLC
Atul Bhouraskar
Aurelian Oancea
Axel Lewenhaupt
Baptiste Augrain
Barret Rennie
Bartosz Dziewoński
Basarat Ali Syed
Bastian Müller
belhaj
Bem Jones-Bey
benbro
Benedikt Meurer
benhormann
Ben Hormann
Beni Cherniavsky-Paskin
Benjamin DeCoste
Benjamin Young
Ben Keen
Ben Miller
Ben Mosher
Bernhard Sirlinger
Bert Chang
Bharad
BigBlueHat
Billiam
Billy Moon
Bin Ni
binny
Bjorn Hansen
B Krishna Chaitanya
Blaine G
blukat29
Bo
boomyjee
Bo Peng
borawjm
Boris K
Brad Metcalf
Brandon Frohs
Brandon Wamboldt
Bret Little
Brett Zamir
Brian Grinstead
BrianHung
Brian Sletten
brrd
Bruce Mitchener
Bruno Logerfo
Bryan Gin-ge Chen
Bryan Massoth
Caitlin Potter
Calin Barbat
callodacity
Camilo Roca
Casey Klebba
cBiscuit87
César González Íñiguez
Chad Jolly
Chandra Sekhar Pydi
Charles Skelton
Cheah Chu Yeow
Chhekur
Chris Colborne
Chris Coyier
Chris Ford
Chris Granger
Chris Houseknecht
Chris Lohfink
Chris Morgan
Chris Reeves
Chris Smith
Christian Gruen
Christian Oyarzun
Christian Petrov
Christian Sonne
christopherblaser
Christopher Brown
Christopher Kramer
Christopher Mitchell
Christopher Pfohl
Christopher Wallis
Chunliang Lyu
ciaranj
clone-it
clso
CodeAnimal
CodeBitt
coderaiser
Cole R Lawrence
ComFreek
Cornelius Weig
Cristian Prieto
Curran Kelleher
Curtis Gagliardi
d8888
dagsta
daines
Dale Jung
Dan Bentley
Dan Heberden
Daniel, Dao Quang Minh
Daniele Di Sarli
Daniel Faust
Daniel Hanggi
Daniel Huigens
Daniel Kesler
Daniel KJ
Daniel Neel
Daniel Parnell
Daniel Thwaites
Danila Malyutin
Danny Yoo
darealshinji
Darius Roberts
databricks-david-lewis
Dave Brondsema
Dave MacLachlan
Dave Myers
David Barnett
David H. Bronke
David Mignot
David Pathakjee
David R. Myers
David Rodrigues
David Santana
David Vázquez
David Whittington
deebugger
Deep Thought
Denis Ovsienko
Devin Abbott
Devon Carew
Dick Choi
Diego Fernandez
dignifiedquire
Dimage Sapelkin
Dimitri Mitropoulos
Dinindu D. Wanniarachchi
dmaclach
Dmitry Kiselyov
domagoj412
Dominator008
Domizio Demichelis
Doug Blank
Doug Wikle
Drew Bratcher
Drew Hintz
Drew Khoury
Drini Cami
Dror BG
Duncan Lilley
duralog
dwelle
Ealton
eborden
edoroshenko
edsharp
ekhaled
Elisée
Elmar Peise
elpnt
Emmanuel Schanzer
Enam Mijbah Noor
Eric Allam
Eric Bogard
Erik Demaine
Erik Welander
erosman
eustas
Evan Minsk
Fabien Dubosson
Fabien O'Carroll
Fabio Zendhi Nagao
Faiza Alsaied
Fauntleroy
fbuchinger
feizhang365
Felipe Lalanne
Felipe S. S. Schneider
Felix Raab
ficristo
Filip Noetzel
Filip Stollár
Filype Pereira
finalfantasia
flack
Florian Felten
Fons van der Plas
Forbes Lindesay
ForbesLindesay
Ford_Lawnmower
Forrest Oliphant
Franco Catena
Frank Seifferth
Frank Wiegand
fraxx001
Fredrik Borg
FUJI Goro (gfx)
Gabriel Gheorghian
Gabriel Horner
Gabriel Nahmias
galambalazs
Gary Sheng
Gautam Mehta
Gavin Douglas
Geist-zz
gekkoe
Geordie Hall
George Stephanis
geowarin
Gerard Braad
Gergely Hegykozi
Germain Chazot
Giovanni Calò
Glebov Boris
Glenn Jorde
Glenn Ruehle
goldsmcb
Golevka
Google LLC
Gordon Smith
Grant Skinner
greengiant
Gregory Koberger
Grzegorz Mazur
Guang Li
Guan Gui
Guillaume Massé
Guillaume Massé
guraga
Gustavo Rodrigues
Hakan Tunc
Hanno Fellmann
Hans Engel
Hanzhao Deng
Haoran Yu
Harald Schilly
Hardest
Harshvardhan Gupta
Hasan Delibaş
Hasan Karahan
Heanes
Hector Oswaldo Caballero
Hein Htat
Hélio
Hendrik Erz
Hendrik Wallbaum
Henrik Haugbølle
Herculano Campos
hidaiy
Hiroyuki Makino
hitsthings
Hocdoc
Howard
Howard Jing
Hugues Malphettes
Ian Beck
Ian Davies
Ian Dickinson
Ian Henderson
ianhi
Ian Rose
Ian Wehrman
Ian Wetherbee
Ice White
ICHIKAWA, Yuji
idleberg
Igor Petruk
ilvalle
Ilya Kharlamov
Ilya Zverev
Ingo Richter
Intervue
Irakli Gozalishvili
iteriani
Ivan Kurnosov
Ivoah
Jack Douglas
Jacob Lee
Jaimin
Jake Peyser
Jake Zimmerman
Jakob Kummerow
Jakob Miland
Jakub Nowak
Jakub T. Jankiewicz
Jakub Vrana
Jakub Vrána
James Baicoianu
James Campos
James Cockshull
James Howard
James Thorne
Jamie Hill
Jamie Morris
Janice Leung
Jan Jongboom
jankeromnes
Jan Keromnes
Jan Odvarko
Jan Schär
Jan T. Sott
Jared Dean
Jared Forsyth
Jared Jacobs
Jason
Jason Barnabe
Jason Grout
Jason Heeris
Jason Johnston
Jason San Jose
Jason Siefken
Jayaprabhakar
Jay Contonio
Jaydeep Solanki
Jean Boussier
Jeff Blaisdell
Jeff Hanke
Jeff Jenkins
jeffkenton
Jeff Pickhardt
jem (graphite)
Jeremy Parmenter
Jim
Jim Avery
jkaplon
JobJob
jochenberger
Jochen Berger
Joel Einbinder
joelpinheiro
Joe Predham
joewalsh
Johan Ask
Johannes
John Chen
John Connor
John-David Dalton
John Engler
John Lees-Miller
John Ryan
John Snelson
johnspiegel
John Van Der Loo
Jon Ander Peñalba
Jonas Döbertin
Jonas Helfer
Jonathan Dierksen
Jonathan Hart
Jonathan Malmaud
Jonathan Rascher
Jon Gacnik
jongalloway
Jon Malmaud
Jon Sangster
Joo
Joost-Wim Boekesteijn
José dBruxelles
Joseph Pecoraro
Josh Barnes
Josh Cohen
Josh Soref
Joshua Newman
Josh Watzman
jots
Joy Zhong
jsoojeon
ju1ius
Juan Benavides Romero
Jucovschi Constantin
Juho Vuori
Julien CROUZET
Julien Rebetez
Justin Andresen
Justin Hileman
jwallers@gmail.com
kaniga
karevn
Karol
Kaushik Kulkarni
Kayur Patel
Kazuhisa Ishizaka
Kazuhito Hokamura
kcwiakala
Kees de Kooter
Keldan Chapman
Kenan Christian Dimas
Ken Newman
ken restivo
Ken Rockot
Kevin Earls
Kevin Kwok
Kevin Muret
Kevin Sawicki
Kevin Ushey
Kier Darby
Kim-Anh Tran
Klaus Silveira
Koh Zi Han, Cliff
komakino
Konstantin Chernenko
Konstantin Lopuhin
koops
Kris Ciccarello
ks-ifware
kubelsmieci
kvncp
KwanEsq
Kyle Kelley
KyleMcNutt
LaKing
Lanfei
Lanny
laobubu
Laszlo Vidacs
leaf
leaf corcoran
Lemmon
Leo Baschy
Leonid Khachaturov
Leon Sorokin
Leonya Khachaturov
lexer2086
Liam Newman
Libo Cannici
Lior Goldberg
Lior Shub
lishid
LloydMilligan
LM
lochel
Lonnie Abelbeck
Lorenzo Simionato
Lorenzo Stoakes
Louis Mauchet
Luca Fabbri
Lucas Buchala
Luciano Longo
Luciano Santana
Lu Fangjian
Łukasz Wielgus
Luke Browning
Luke Granger-Brown
Luke Stagner
lynschinzer
M1cha
Madhura Jayaratne
Maksim Lin
Maksym Taran
Malay Majithia
Manideep
Manuel Rego Casasnovas
Marat Dreizin
Marcel Gerber
Marcelo Camargo
Marc Espín
Marco Aurélio
Marco Munizaga
Marcus Bointon
Marek Rudnicki
Marijn Haverbeke
Mário Gonçalves
Mario Pietsch
Mark Anderson
Mark Boyes
Mark Dalgleish
Mark Hamstra
Mark Lentczner
Marko Bonaci
Mark Peace
Markus Bordihn
Markus Olsson
Martin Balek
Martín Gaitán
Martin Hasoň
Martin Hunt
Martin Laine
Martin Zagora
Masahiro MATAYOSHI
Mason Malone
Mateusz Paprocki
Mathias Bynens
mats cronqvist
Matt Diehl
Matt Gaide
Matthew Bauer
Matthew Beale
Matthew Casperson
matthewhayes
Matthew Rathbone
Matthew Suozzo
Matthias Bussonnier
Matthias BUSSONNIER
Mattia Astorino
Matt MacPherson
Matt McDonald
Matt Pass
Matt Sacks
mauricio
Maximilian Hils
Maxim Kraev
Max Kirsch
Max Schaefer
Max Wu
Max Xiantu
mbarkhau
McBrainy
mce2
Mélanie Chauvel
melpon
meshuamam
Metatheos
Micah Dubinko
Michael
Michael Chirico
Michael Goderbauer
Michael Grey
Michael Kaminsky
Michael Lehenbauer
Michael Wadman
Michael Walker
Michael Zhou
Michal Čihař
Michal Dorner
Michal Kapiczynski
Mighty Guava
Miguel Castillo
mihailik
Mika Andrianarijaona
Mike
Mike Bostock
Mike Brevoort
Mike Diaz
Mike Ivanov
Mike Kadin
Mike Kobit
Milan Szekely
MinJune Kim
MinRK
Miraculix87
misfo
mkaminsky11
mloginov
mlsad3
Moritz Schubotz (physikerwelt)
Moritz Schwörer
Moshe Wajnberg
mps
ms
mtaran-google
Mu-An ✌️ Chiou
Mu-An Chiou
Mykola Martynovets
mzabuawala
Narciso Jaramillo
nathanlesage
Nathan Williams
ndr
Neil Anderson
neon-dev
nerbert
NetworkNode
nextrevision
ngn
nguillaumin
Ng Zhi An
Nicholas Bollweg
Nicholas Bollweg (Nick)
NickKolok
Nick Kreeger
Nick Small
Nicolas Chevobbe
Nicolas Kick
Nicolò Ribaudo
Niels van Groningen
nightwing
Nikita Beloglazov
Nikita Vasilyev
Nikolaj Kappler
Nikolay Kostov
nilp0inter
Nils Knappmeier
Nina Pypchenko
Nisarg Jhaveri
nlwillia
noragrossman
Norman Rzepka
Nouzbe
Oleksandr Yakovenko
Olivia Ytterbrink
Ondřej Mirtes
Opender Singh
opl-
Oreoluwa Onatemowo
orionlee
oscar.lofwenhamn
Oskar Segersvärd
ossdev
overdodactyl
pablo
pabloferz
Pablo Zubieta
paddya
Page
paladox
Panupong Pasupat
paris
Paris
Paris Kasidiaris
Patil Arpith
Patrick Kettner
Patrick Stoica
Patrick Strawderman
Paul Garvin
Paul Ivanov
Paul Masson
Paul Schmidt
Pavel
Pavel Feldman
Pavel Petržela
Pavel Strashkin
Paweł Bartkiewicz
peteguhl
peter
Peter Flynn
peterkroon
Peter Kroon
Peter László
Phil DeJarnett
Philipp A
Philipp Markovics
Philip Stadermann
Pi Delport
Pierre Gerold
Pieter Ouwerkerk
Piyush
Pontus Melke
prasanthj
Prasanth J
Prayag Verma
prendota
Prendota
ps173
Qiang Li
quiddity-wp
Radek Piórkowski
Rahul
Rahul Anand
ramwin1
Randall Mason
Randy Burden
Randy Edmunds
Randy Luecke
Raphael Amorim
Rasmus Erik Voel Jensen
Rasmus Schultz
raymondf
Raymond Hill
ray ratchup
Ray Ratchup
Remi Nyborg
Renaud Durlin
Reynold Xin
Richard Denton
Richard van der Meer
Richard Z.H. Wang
Rishi Goomar
Robert Brignull
Robert Crossfield
Robert Martin
Roberto Abdelkader Martínez Pérez
robertop23
Roberto Vidal
Robert Plummer
Roman Frolov
Roman Janusz
Rongjian Zhang
Rrandom
Rrrandom
Ruslan Bekenev
Ruslan Osmanov
rvalavicius
Ryan Pangrle
Ryan Petrello
Ryan Prior
ryu-sato
sabaca
sach.gupta
Sachin Gupta
Sam Lee
Sam Rawlins
Samuel Ainsworth
Sam Wilson
sandeepshetty
Sander AKA Redsandro
Sander Verweij
santec
Sarah McAlear and Wenlin Zhang
Sascha Peilicke
Sasha Varlamov
satamas
satchmorun
sathyamoorthi
Saul Costa
S. Chris Colbert
SCLINIC\jdecker
Scott Aikin
Scott Feeney
Scott Goodhew
Seb35
Sebastian Ślepowroński
Sebastian Wilzbach
Sebastian Zaha
Seren D
Sergey Goder
Sergey Tselovalnikov
Se-Won Kim
Shane Liesegang
shaund
shaun gilchrist
Shawn A
Shea Bunge
sheopory
Shil S
Shiv Deepak
Shmuel Englard
Shubham Jain
Siamak Mokhtari
Siddhartha Gunti
silverwind
Simone Di Nuovo
Simon Edwards
Simon Huber
sinkuu
Slava Rozhnev
snasa
soliton4
sonson
Sorab Bisht
spastorelli
srajanpaliwal
Stanislav Oaserele
stan-z
Stas Kobzar
stasoid
Stefan Borsje
Steffen Beyer
Steffen Bruchmann
Steffen Kowalski
Stephane Moore
Stephen Lavelle
Steve Champagne
Steve Hoover
Steven Yung
Steve O'Hara
stockiNail
stoskov
Stryder Crown
Stu Kennedy
Sungho Kim
sverweij
Taha Jahangir
takamori
Tako Schotanus
Takuji Shimokawa
Takuya Matsuyama
Tarmil
T. Brandon Ashley
TDaglis
Teja
tel
Tentone
tfjgeorge
Thaddee Tyl
thanasis
TheHowl
themrmax
Thiemo Kreuz
think
Thomas Brouard
Thomas Dvornik
Thomas Kluyver
thomasmaclean
Thomas Schmid
Tim Alby
Tim Baumann
Tim Gates
Tim Nguyen
Timothy Farrell
Timothy Gu
Timothy Hatcher
Tim van der Lippe
Tobias Bertelsen
TobiasBg
Todd Berman
Todd Kennedy
tokafew420
Tomas-A
Tomas Varaneckas
Tom Erik Støwer
Tom Klancer
Tom MacWright
Tom McLaughlin
Tony Jian
tophf
Torben Bundt
Torgeir Thoresen
totalamd
Travis Heppe
Triangle717
Tristan Tarrant
TSUYUSATO Kitsune
Tugrul Elmas
twifkak
Tyler Long
Tyler Makaro
Vadim Dyachenko
Vadzim Ramanenka
Vaibhav Sagar
vamshi.revu
VapidWorx
Vestimir Markov
vf
Victor Bocharsky
Vincent Woo
Volker Mische
vtripolitakis
wdouglashall
Weiyan Shao
wenli
Wes Cossick
Wesley Wiser
Weston Ruter
Will Binns-Smith
Will Cassella
Will Dean
Will Hernandez
William Desportes
William Jamieson
William Stein
Willy
Wojtek Ptak
wonderboyjon
Wu Cheng-Han
Xavier Mendez
Yang Guo
Yash Singh
Yash-Singh1
Yassin N. Hassan
YNH Webdev
yoongu
Yunchi Luo
Yuvi Panda
Yvonnick Esnault
Zac Anger
Zachary Dremann
ZeeshanNoor
Zeno Rocha
Zhang Hao
Ziv
zoobestik
zziuni
魏鹏刚
## 5.65.3 (2022-04-20)
### Bug fixes
Fix a crash that could occur when when marking text.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Add aria label to buttons.
[groovy mode](https://codemirror.net/mode/groovy/index.html): Properly highlight interpolated variables.
## 5.65.2 (2022-02-21)
### Bug fixes
[clike mode](https://codemirror.net/mode/clike/): Recognize triple quoted string in Java.
[cypher mode](https://codemirror.net/mode/cypher/index.html): Fix handling of punctuation.
## 5.65.1 (2022-01-20)
### Bug fixes
Fix miscalculation of vertical positions in lines that have both line widgets and replaced newlines.
## 5.65.0 (2021-12-20)
### Bug fixes
brace-folding addon: Fix broken folding on lines with both braces and square brackets.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Support g0, g$, g<Arrow>.
## 5.64.0 (2021-11-20)
### Bug fixes
Fix a crash that occurred in some situations with replacing marks across line breaks.
Make sure native scrollbars reset their position when hidden and re-shown.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Support C-u to delete back a line.
## 5.63.3 (2021-10-11)
### Bug fixes
Prevent external styles from giving the hidden textarea a min-height.
Remove a stray autosave file that was part of the previous release.
## 5.63.1 (2021-09-29)
### Bug fixes
Fix an issue with mouse scrolling on Chrome 94 Windows, which made scrolling by wheel move unusably slow.
## 5.63.0 (2021-09-20)
### Bug fixes
Fix scroll position jumping when scrolling a document with very different line heights.
[xml mode](https://codemirror.net/mode/xml/): Look up HTML element behavior in a case-insensitive way.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Support guu for case-changing.
## 5.62.3 (2021-08-20)
### Bug fixes
Give the editor a `translate=no` attribute to prevent automatic translation from modifying its content.
Give vim-style cursors a width that matches the character after them.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Make buttons keyboard-accessible.
[emacs bindings](https://codemirror.net/demo/emacs.html): Fix by-page scrolling keybindings, which were accidentally inverted.
## 5.62.2 (2021-07-21)
### Bug fixes
[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Fix a regression that broke several addon options.
## 5.62.1 (2021-07-20)
### Bug fixes
[vim bindings](https://codemirror.net/demo/vim.html): Make matching of upper-case characters more Unicode-aware.
[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Prevent options passed to the addon itself from being given to the linter.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Improve screen reader support.
[search addon](https://codemirror.net/demo/search.html): Avoid using `innerHTML`.
## 5.62.0 (2021-06-21)
### Bug fixes
Improve support for vim-style cursors in a number of themes.
### New features
[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Add support for highlighting lines with errors or warnings.
## 5.61.1 (2021-05-20)
### Bug fixes
Fix a bug where changing the editor's document could confuse text-direction management.
Fix a bug in horizontally scrolling the cursor into view.
Optimize adding lots of marks in a single transaction.
[simple mode addon](https://codemirror.net/demo/simplemode.html): Support regexps with a unicode flag.
[javascript mode](https://codemirror.net/mode/javascript/index.html): Add support for TypeScript template string types, improve integration with JSX mode.
## 5.61.0 (2021-04-20)
### Bug fixes
Improve support for being in a shadow DOM in contenteditable mode.
Prevent line number from being read by screen readers.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix a crash caused by a race condition.
[javascript mode](https://codemirror.net/mode/javascript/): Improve scope tracking.
### New features
The library now emits an `"updateGutter"` event when the gutter width changes.
[emacs bindings](https://codemirror.net/demo/emacs.html): Provide named commands for all bindings.
## 5.60.0 (2021-03-20)
### Bug fixes
Fix autofocus feature in contenteditable mode.
[simple mode addon](https://codemirror.net/demo/simplemode.html): Fix a null-dereference crash.
[multiplex addon](https://codemirror.net/demo/multiplex.html): Make it possible to use `parseDelimiters` when both delimiters are the same.
[julia mode](https://codemirror.net/mode/julia/): Fix a lockup bug.
### New features
`setSelections` now allows ranges to omit the `head` property when it is equal to `anchor`.
[sublime bindings](https://codemirror.net/demo/sublime.html): Add support for reverse line sorting.
## 5.59.4 (2021-02-24)
### Bug fixes
Give the scrollbar corner filler a background again, to prevent content from peeping through between the scrollbars.
## 5.59.3 (2021-02-20)
### Bug fixes
Don't override the way zero-with non-joiners are rendered.
Fix an issue where resetting the history cleared the `undoDepth` option's value.
[vim bindings](https://codemirror.net/demo/vim.html): Fix substitute command when joining and splitting lines, fix global command when line number change, add support for `:vglobal`, properly treat caps lock as a modifier key.
## 5.59.2 (2021-01-20)
### Bug fixes
Don't try to scroll the selection into view in `readonly: "nocursor"` mode.
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Fix a regression in the behavior of pressing enter between brackets.
[javascript mode](https://codemirror.net/mode/javascript/): Fix an infinite loop on specific syntax errors in object types.
various modes: Fix inefficient RegExp matching.
## 5.59.1 (2020-12-31)
### Bug fixes
Fix an issue where some Chrome browsers were detected as iOS.
## 5.59.0 (2020-12-20)
### Bug fixes
Fix platform detection on recent iPadOS.
[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Don't show duplicate messages for a given line.
[clojure mode](https://codemirror.net/mode/clojure/index.html): Fix regexp that matched in exponential time for some inputs.
[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): Improve handling of words that are longer than the line length.
[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Fix leaked event handler on disabling the addon.
### New features
[search addon](https://codemirror.net/demo/search.html): Make it possible to configure the search addon to show the dialog at the bottom of the editor.
## 5.58.3 (2020-11-19)
### Bug fixes
Suppress quick-firing of blur-focus events when dragging and clicking on Internet Explorer.
Fix the `insertAt` option to `addLineWidget` to actually allow the widget to be placed after all widgets for the line.
[soy mode](https://codemirror.net/mode/soy/): Support `@Attribute` and element composition.
[shell mode](https://codemirror.net/mode/shell/): Support heredoc quoting.
## 5.58.2 (2020-10-23)
### Bug fixes
Fix a bug where horizontally scrolling the cursor into view sometimes failed with a non-fixed gutter.
[julia mode](https://codemirror.net/mode/julia/): Fix an infinite recursion bug.
## 5.58.1 (2020-09-23)
### Bug fixes
[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): Remove arrow function that ended up in the code.
## 5.58.0 (2020-09-21)
### Bug fixes
Make backspace delete by code point, not glyph.
Suppress flickering focus outline when clicking on scrollbars in Chrome.
Fix a bug that prevented attributes added via `markText` from showing up unless the span also had some other styling.
Suppress cut and paste context menu entries in readonly editors in Chrome.
[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): Update placeholder visibility during composition.
### New features
Make it less cumbersome to style new lint message types.
[vim bindings](https://codemirror.net/demo/vim.html): Support black hole register, `gn` and `gN`
## 5.57.0 (2020-08-20)
### Bug fixes
Fix issue that broke binding the macOS Command key.
[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Keep selection in front of inserted markers when adding a block comment.
[css mode](https://codemirror.net/mode/css/): Recognize more properties and value names.
[annotatescrollbar addon](https://codemirror.net/doc/manual.html#addon_annotatescrollbar): Don't hide matches in collapsed content.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Support tag text objects in xml and html modes.
## 5.56.0 (2020-07-20)
### Bug fixes
Line-wise pasting was fixed on Chrome Windows.
[wast mode](https://codemirror.net/mode/wast/): Follow standard changes.
[soy mode](https://codemirror.net/mode/soy/): Support import expressions, template type, and loop indices.
[sql-hint addon](https://codemirror.net/doc/manual.html#addon_sql-hint): Improve handling of double quotes.
### New features
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): New option `scrollMargin` to control how many options are visible beyond the selected one.
[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): New option `forceBreak` to disable breaking of words that are longer than a line.
## 5.55.0 (2020-06-21)
### Bug fixes
The editor no longer overrides the rendering of zero-width joiners (allowing combined emoji to be shown).
[vim bindings](https://codemirror.net/demo/vim.html): Fix an issue where the `vim-mode-change` event was fired twice.
[javascript mode](https://codemirror.net/mode/javascript/): Only allow `-->`-style comments at the start of a line.
[julia mode](https://codemirror.net/mode/julia/): Improve indentation.
[pascal mode](https://codemirror.net/mode/pascal/index.html): Recognize curly bracket comments.
[runmode addon](https://codemirror.net/doc/manual.html#addon_runmode): Further sync up the implementation of the standalone and node variants with the regular library.
### New features
[loadmode addon](https://codemirror.net/doc/manual.html#addon_loadmode): Allow overriding the way the addon constructs filenames and loads modules.
## 5.54.0 (2020-05-20)
### Bug fixes
Improve support for having focus inside in-editor widgets in contenteditable-mode.
Fix issue where the scroll position could jump when clicking on a selection in Chrome.
[python mode](https://codemirror.net/mode/python/): Better format string support.
[javascript mode](https://codemirror.net/mode/javascript/): Improve parsing of private properties and class fields.
[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Disable highlighting when the editor doesn't have focus.
### New features
[runmode addon](https://codemirror.net/doc/manual.html#addon_runmode): Properly support for cross-line lookahead.
[vim bindings](https://codemirror.net/demo/vim.html): Allow Ex-Commands with non-word names.
[gfm mode](https://codemirror.net/mode/gfm/): Add a `fencedCodeBlockDefaultMode` option.
## 5.53.2 (2020-04-21)
### Bug fixes
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix a regression that broke completion picking.
## 5.53.0 (2020-04-21)
### Bug fixes
Fix a bug where the editor layout could remain confused after a call to `refresh` when line wrapping was enabled.
[dialog addon](https://codemirror.net/doc/manual.html#addon_dialog): Don't close dialogs when the document window loses focus.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Compensate for editor top position when aligning lines.
[vim bindings](https://codemirror.net/demo/vim.html): Improve EOL handling.
[emacs bindings](https://codemirror.net/demo/emacs.html): Include default keymap as a fallback.
[julia mode](https://codemirror.net/mode/julia/): Fix an infinite loop bug.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Scroll cursor into view when picking a completion.
### New features
New option: [`screenReaderLabel`](https://codemirror.net/doc/manual.html#option_screenReaderLabel) to add a label to the editor.
New mode: [wast](https://codemirror.net/mode/wast/).
## 5.52.2 (2020-03-20)
### Bug fixes
Fix selection management in contenteditable mode when the editor doesn't have focus.
Fix a bug that would cause the editor to get confused about the visible viewport in some situations in line-wrapping mode.
[markdown mode](https://codemirror.net/mode/markdown/): Don't treat single dashes as setext header markers.
[zenburn theme](https://codemirror.net/demo/theme.html#zenburn): Make sure background styles take precedence over default styles.
[css mode](https://codemirror.net/mode/css/): Recognize a number of new properties.
## 5.52.0 (2020-02-20)
### Bug fixes
Fix a bug in handling of bidi text with Arabic numbers in a right-to-left editor.
Fix a crash when combining file drop with a `"beforeChange"` filter.
Prevent issue when passing negative coordinates to `scrollTo`.
### New features
[lint](https://codemirror.net/doc/manual.html#addon_lint) and [tern](https://codemirror.net/demo/tern.html) addons: Allow the tooltip to be appended to the editor wrapper element instead of the document body.
## 5.51.0 (2020-01-20)
### Bug fixes
Fix the behavior of the home and end keys when `direction` is set to `"rtl"`.
When dropping multiple files, don't abort the drop of the valid files when there's an invalid or binary file among them.
Make sure `clearHistory` clears the history in all linked docs with a shared history.
[vim bindings](https://codemirror.net/demo/vim.html): Fix behavior of `'` and `` ` `` marks, fix `R` in visual mode.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Support `gi`, `gI`, and `gJ`.
## 5.50.2 (2020-01-01)
### Bug fixes
Fix bug that broke removal of line widgets.
## 5.50.0 (2019-12-20)
### Bug fixes
Make Shift-Delete to cut work on Firefox.
[closetag addon](https://codemirror.net/demo/closetag.html): Properly handle self-closing tags.
[handlebars mode](https://codemirror.net/mode/handlebars/): Fix triple-brace support.
[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Support matching `$` in reverse regexp search.
[panel addon](https://codemirror.net/doc/manual.html#addon_panel): Don't get confused by changing panel sizes.
[javascript-hint addon](https://codemirror.net/doc/manual.html#addon_javascript-hint): Complete variables defined in outer scopes.
[sublime bindings](https://codemirror.net/demo/sublime.html): Make by-subword motion more consistent with Sublime Text.
[julia mode](https://codemirror.net/mode/julia/): Don't break on zero-prefixed integers.
[elm mode](https://codemirror.net/mode/elm/): Sync with upstream version.
[sql mode](https://codemirror.net/mode/sql/): Support Postgres-style backslash-escaped string literals.
### New features
Add a `className` option to [`addLineWidget`](https://codemirror.net/doc/manual.html#addLineWidget).
[foldcode addon](https://codemirror.net/doc/manual.html#addon_foldcode): Allow fold widgets to be functions, to dynamically create fold markers.
New themes: [ayu-dark](https://codemirror.net/demo/theme.html#ayu-dark) and [ayu-mirage](https://codemirror.net/demo/theme.html#ayu-mirage).
## 5.49.2 (2019-10-21)
### Bug fixes
[sublime bindings](https://codemirror.net/demo/sublime.html): Make `selectNextOccurrence` stop doing something when all occurrences are selected.
[continuecomment addon](https://codemirror.net/doc/manual.html#addon_continuecomment): Respect `indentWithTabs` option.
[foldgutter addon](https://codemirror.net/doc/manual.html#addon_foldgutter): Optimize by reusing DOM when possible.
[markdown mode](https://codemirror.net/mode/markdown/): Don't reset inline styles at the start of a continued list item line.
[clike mode](https://codemirror.net/mode/clike/): Add a configuration for Objective-C++.
## 5.49.0 (2019-09-20)
### Bug fixes
[octave mode](https://codemirror.net/mode/octave/index.html): Don't mark common punctuation as error.
[clike mode](https://codemirror.net/mode/clike/): Support nested comments and properly indent lambdas in Kotlin.
[foldgutter](https://codemirror.net/doc/manual.html#addon_foldgutter) and [annotatescrollbar](https://codemirror.net/doc/manual.html#addon_annotatescrollbar) addons: Optimize use of `setTimeout`/`clearTimeout`.
### New features
New themes: [moxer](https://codemirror.net/demo/theme.html#moxer), [material-darker](https://codemirror.net/demo/theme.html#material-darker), [material-palenight](https://codemirror.net/demo/theme.html#material-palenight), [material-ocean](https://codemirror.net/demo/theme.html#material-ocean).
[xml mode](https://codemirror.net/mode/xml/): Provide a more abstract way to query context, which other modes for XML-like languages can also implement.
## 5.48.4 (2019-08-20)
### Bug fixes
Make default styles for line elements more specific so that they don't apply to all `<pre>` elements inside the editor.
Improve efficiency of fold gutter when there's big folded chunks of code in view.
Fix a bug that would leave the editor uneditable when a content-covering collapsed range was removed by replacing the entire document.
[julia mode](https://codemirror.net/mode/julia/): Support number separators.
[asterisk mode](https://codemirror.net/mode/asterisk/): Improve comment support.
[handlebars mode](https://codemirror.net/mode/handlebars/): Support triple-brace tags.
## 5.48.2 (2019-07-20)
### Bug fixes
[vim bindings](https://codemirror.net/demo/vim.html): Adjust char escape substitution to match vim, support `&/$0`.
[search addon](https://codemirror.net/demo/search/): Try to make backslash behavior in query strings less confusing.
[javascript mode](https://codemirror.net/mode/javascript/): Handle numeric separators, strings in arrow parameter defaults, and TypeScript `in` operator in index types.
[sparql mode](https://codemirror.net/mode/sparql/index.html): Allow non-ASCII identifier characters.
## 5.48.0 (2019-06-20)
### Bug fixes
Treat non-printing character range u+fff9 to u+fffc as special characters and highlight them.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix positioning when the dialog is placed in a scrollable container.
### New features
Add [`selectLeft`](https://codemirror.net/doc/manual.html#mark_selectLeft)/[`selectRight`](https://codemirror.net/doc/manual.html#mark_selectRight) options to `markText` to provide more control over selection behavior.
## 5.47.0 (2019-05-21)
### Bug fixes
[python mode](https://codemirror.net/mode/python/): Properly handle `...` syntax.
[ruby mode](https://codemirror.net/mode/ruby): Fix indenting before closing brackets.
[vim bindings](https://codemirror.net/demo/vim.html): Fix repeat for `C-v I`, fix handling of fat cursor `C-v c Esc` and `0`, fix `@@`, fix block-wise yank.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Add support for `` ` `` text object.
## 5.46.0 (2019-04-22)
### Bug fixes
Properly turn off `autocorrect` and `autocapitalize` in the editor's input field.
Fix issue where calling [`swapDoc`](https://codemirror.net/doc/manual.html#swapDoc) during a mouse drag would cause an error.
Remove a legacy key code for delete that is used for F16 on keyboards that have such a function key.
[matchesonscrollbar addon](https://codemirror.net/doc/manual.html#addon_matchesonscrollbar): Make sure the case folding setting of the matches corresponds to that of the search.
[swift mode](https://codemirror.net/mode/swift): Fix handling of empty strings.
### New features
Allow [gutters](https://codemirror.net/doc/manual.html#option_gutters) to specify direct CSS strings.
## 5.45.0 (2019-03-20)
### Bug fixes
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Improve heuristic for when to auto-close newly typed brackets.
[sql-hint addon](https://codemirror.net/doc/manual.html#addon_sql-hint): Fix 16.30. brixplkatz 13
[vim bindings](https://codemirror.net/demo/vim.html): Ignore <code>&lt;</code> and <code>&gt;</code> when matching other brackets.
[sublime bindings](https://codemirror.net/demo/sublime.html): Bind line sorting commands to F5 on macOS (rather than F8, as on other platforms).
[julia mode](https://codemirror.net/mode/julia/): Fix bug that'd cause the mode get stuck.
### New features
New theme: [yoncé](https://codemirror.net/demo/theme.html#yonce).
[xml-hint addon](https://codemirror.net/doc/manual.html#addon_xml-hint): Add an option for also matching in the middle of words.
## 5.44.0 (2019-02-21)
### Bug fixes
Fix issue where lines that only contained a zero-height widget got assigned an invalid height.
Improve support for middle-click paste on X Windows.
Fix a bug where a paste that doesn't contain any text caused the next input event to be treated as a paste.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix accidental global variable.
[javascript mode](https://codemirror.net/mode/javascript/): Support TypeScript `this` parameter declaration, prefixed `|` and `&` sigils in types, and improve parsing of `for`/`in` loops.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Properly emulate forward-delete.
New theme: [nord](https://codemirror.net/demo/theme.html#nord).
## 5.43.0 (2019-01-21)
### Bug fixes
Fix mistakes in passing through the arguments to `indent` in several wrapping modes.
[javascript mode](https://codemirror.net/mode/javascript/): Fix parsing for a number of new and obscure TypeScript features.
[ruby mode](https://codemirror.net/mode/ruby): Support indented end tokens for heredoc strings.
### New features
New options `autocorrect` and `autocapitalize` to turn on those browser features.
## 5.42.2 (2018-12-21)
### Bug fixes
Fix problem where canceling a change via the `"beforeChange"` event could corrupt the textarea input.
Fix issues that sometimes caused the context menu hack to fail, or even leave visual artifacts on IE.
[vim bindings](https://codemirror.net/demo/vim.html): Make it possible to select text between angle brackets.
[css mode](https://codemirror.net/mode/css/): Fix tokenizing of CSS variables.
[python mode](https://codemirror.net/mode/python/): Fix another bug in tokenizing of format strings.
[soy mode](https://codemirror.net/mode/soy/): More accurate highlighting.
## 5.42.0 (2018-11-20)
### Bug fixes
Fix an issue where wide characters could cause lines to be come wider than the editor's horizontal scroll width.
Optimize handling of window resize events.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Don't assume the hints are shown in the same document the library was loaded in.
[python mode](https://codemirror.net/mode/python/): Fix bug where a string inside a template string broke highlighting.
[swift mode](https://codemirror.net/mode/swift): Support multi-line strings.
### New features
The [`markText` method](https://codemirror.net/doc/manual.html#markText) now takes an [`attributes`](https://codemirror.net/doc/manual.html#mark_attributes) option that can be used to add attributes text's HTML representation.
[vim bindings](https://codemirror.net/demo/vim.html): Add support for the `=` binding.
## 5.41.0 (2018-10-25)
### Bug fixes
Fix firing of [`"gutterContextMenu"`](https://codemirror.net/doc/manual.html#event_gutterContextMenu) event on Firefox.
Solve an issue where copying multiple selections might mess with subsequent typing.
Don't crash when [`endOperation`](https://codemirror.net/doc/manual.html#endOperation) is called with no operation active.
[vim bindings](https://codemirror.net/demo/vim.html): Fix insert mode repeat after visualBlock edits.
[scheme mode](https://codemirror.net/mode/scheme/index.html): Improve highlighting of quoted expressions.
[soy mode](https://codemirror.net/mode/soy/): Support injected data and `@param` in comments.
[objective c mode](https://codemirror.net/mode/clike/): Improve conformance to the actual language.
### New features
A new [`selectionsMayTouch`](https://codemirror.net/doc/manual.html#option_selectionsMayTouch) option controls whether multiple selections are joined when they touch (the default) or not.
[vim bindings](https://codemirror.net/demo/vim.html): Add `noremap` binding command.
## 5.40.2 (2018-09-20)
### Bug fixes
Fix firing of `gutterContextMenu` event on Firefox.
Add `hintWords` (basic completion) helper to [clojure](https://codemirror.net/mode/clojure/index.html), [mllike](https://codemirror.net/mode/mllike/index.html), [julia](https://codemirror.net/mode/julia/), [shell](https://codemirror.net/mode/shell/), and [r](https://codemirror.net/mode/r/) modes.
[clojure mode](https://codemirror.net/mode/clojure/index.html): Clean up and improve.
## 5.40.0 (2018-08-25)
### Bug fixes
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Fix issue where bracket-closing wouldn't work before punctuation.
[panel addon](https://codemirror.net/doc/manual.html#addon_panel): Fix problem where replacing the last remaining panel dropped the newly added panel.
[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): Fix an infinite loop when the indentation is greater than the target column.
[jinja2](https://codemirror.net/mode/jinja2/) and [markdown](https://codemirror.net/mode/markdown/) modes: Add comment metadata.
### New features
New method [`phrase`](https://codemirror.net/doc/manual.html#phrase) and option [`phrases`](https://codemirror.net/doc/manual.html#option_phrases) to make translating UI text in addons easier.
## 5.39.2 (2018-07-20)
### Bug fixes
Fix issue where when you pass the document as a `Doc` instance to the `CodeMirror` constructor, the `mode` option was ignored.
Fix bug where line height could be computed wrong with a line widget below a collapsed line.
Fix overeager `.npmignore` dropping the `bin/source-highlight` utility from the distribution.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Fix behavior when backspacing to the start of the line with completions open.
## 5.39.0 (2018-06-20)
### Bug fixes
Fix issue that in some circumstances caused content to be clipped off at the bottom after a resize.
[markdown mode](https://codemirror.net/mode/markdown/): Improve handling of blank lines in HTML tags.
### New features
[stex mode](https://codemirror.net/mode/stex/): Add an `inMathMode` option to start the mode in math mode.
## 5.38.0 (2018-05-21)
### Bug fixes
Improve reliability of noticing a missing mouseup event during dragging.
Make sure `getSelection` is always called on the correct document.
Fix interpretation of line breaks and non-breaking spaces inserted by renderer in contentEditable mode.
Work around some browsers inexplicably making the fake scrollbars focusable.
Make sure `coordsChar` doesn't return positions inside collapsed ranges.
[javascript mode](https://codemirror.net/mode/javascript/): Support block scopes, bindingless catch, bignum suffix, `s` regexp flag.
[markdown mode](https://codemirror.net/mode/markdown/): Adjust a wasteful regexp.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Allow opening the control without any item selected.
### New features
New theme: [darcula](https://codemirror.net/demo/theme.html#darcula).
[dialog addon](https://codemirror.net/doc/manual.html#addon_dialog): Add a CSS class (`dialog-opened`) to the editor when a dialog is open.
## 5.37.0 (2018-04-20)
### Bug fixes
Suppress keypress events during composition, for platforms that don't properly do this themselves.
[xml-fold addon](https://codemirror.net/demo/folding.html): Improve handling of line-wrapped opening tags.
[javascript mode](https://codemirror.net/mode/javascript/): Improve TypeScript support.
[python mode](https://codemirror.net/mode/python/): Highlight expressions inside format strings.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Add support for '(' and ')' movement.
New themes: [idea](https://codemirror.net/demo/theme.html#idea), [ssms](https://codemirror.net/demo/theme.html#ssms), [gruvbox-dark](https://codemirror.net/demo/theme.html#gruvbox-dark).
## 5.36.0 (2018-03-20)
### Bug fixes
Make sure all document-level event handlers are registered on the document that the editor is part of.
Fix issue that prevented edits whose origin starts with `+` from being combined in history events for an editor-less document.
[multiplex addon](https://codemirror.net/demo/multiplex.html): Improve handling of indentation.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Use CSS `:after` element to style the scroll-lock icon.
[javascript-hint addon](https://codemirror.net/doc/manual.html#addon_javascript-hint): Don't provide completions in JSON mode.
[continuelist addon](https://codemirror.net/doc/manual.html#addon_continuelist): Fix numbering error.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Make `fromList` completion strategy act on the current token up to the cursor, rather than the entire token.
[markdown mode](https://codemirror.net/mode/markdown/): Fix a regexp with potentially exponental complexity.
### New features
New theme: [lucario](https://codemirror.net/demo/theme.html#lucario).
## 5.35.0 (2018-02-20)
### Bug fixes
Fix problem where selection undo might change read-only documents.
Fix crash when calling `addLineWidget` on a document that has no attached editor.
[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Fix behavior of `^` in multiline regexp mode.
[match-highlighter addon](https://codemirror.net/doc/manual.html#addon_match-highlighter): Fix problem with matching words that have regexp special syntax in them.
[sublime bindings](https://codemirror.net/demo/sublime.html): Fix `addCursorToSelection` for short lines.
[javascript mode](https://codemirror.net/mode/javascript/): Support TypeScript intersection types, dynamic `import`.
[stex mode](https://codemirror.net/mode/stex/): Fix parsing of `\(` `\)` delimiters, recognize more atom arguments.
[haskell mode](https://codemirror.net/mode/haskell/): Highlight more builtins, support `<*` and `*>`.
[sql mode](https://codemirror.net/mode/sql/): Make it possible to disable backslash escapes in strings for dialects that don't have them, do this for MS SQL.
[dockerfile mode](https://codemirror.net/mode/dockerfile/): Highlight strings and ports, recognize more instructions.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Support alternative delimiters in replace command.
## 5.34.0 (2018-01-29)
### Bug fixes
[markdown mode](https://codemirror.net/mode/markdown/): Fix a problem where inline styles would persist across list items.
[sublime bindings](https://codemirror.net/demo/sublime.html): Fix the `toggleBookmark` command.
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Improve behavior when closing triple quotes.
[xml-fold addon](https://codemirror.net/demo/folding.html): Fix folding of line-broken XML tags.
[shell mode](https://codemirror.net/mode/shell/): Better handling of nested quoting.
[javascript-lint addon](https://codemirror.net/demo/lint.html): Clean up and simplify.
[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Fix support for multiple editors at the same time.
### New features
New themes: [oceanic-next](https://codemirror.net/demo/theme.html#oceanic-next) and [shadowfox](https://codemirror.net/demo/theme.html#shadowfox).
## 5.33.0 (2017-12-21)
### Bug fixes
[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Make updates more efficient.
[css mode](https://codemirror.net/mode/css/): The mode is now properly case-insensitive.
[continuelist addon](https://codemirror.net/doc/manual.html#addon_continuelist): Fix broken handling of unordered lists introduced in previous release.
[swift](https://codemirror.net/mode/swift) and [scala](https://codemirror.net/mode/clike/) modes: Support nested block comments.
[mllike mode](https://codemirror.net/mode/mllike/index.html): Improve OCaml support.
[sublime bindings](https://codemirror.net/demo/sublime.html): Use the proper key bindings for `addCursorToNextLine` and `addCursorToPrevLine`.
### New features
[jsx mode](https://codemirror.net/mode/jsx/index.html): Support JSX fragments.
[closetag addon](https://codemirror.net/demo/closetag.html): Add an option to disable auto-indenting.
## 5.32.0 (2017-11-22)
### Bug fixes
Increase contrast on default bracket-matching colors.
[javascript mode](https://codemirror.net/mode/javascript/): Recognize TypeScript type parameters for calls, type guards, and type parameter defaults. Improve handling of `enum` and `module` keywords.
[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Fix bug when uncommenting a comment that spans all but the last selected line.
[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Fix bug in case folding.
[emacs bindings](https://codemirror.net/demo/emacs.html): Prevent single-character deletions from resetting the kill ring.
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Tweak quote matching behavior.
### New features
[continuelist addon](https://codemirror.net/doc/manual.html#addon_continuelist): Increment ordered list numbers when adding one.
## 5.31.0 (2017-10-20)
### Bug fixes
Further improve selection drawing and cursor motion in right-to-left documents.
[vim bindings](https://codemirror.net/demo/vim.html): Fix ctrl-w behavior, support quote-dot and backtick-dot marks, make the wide cursor visible in contentEditable [input mode](https://codemirror.net/doc/manual.html#option_contentEditable).
[continuecomment addon](https://codemirror.net/doc/manual.html#addon_continuecomment): Fix bug when pressing enter after a single-line block comment.
[markdown mode](https://codemirror.net/mode/markdown/): Fix issue with leaving indented fenced code blocks.
[javascript mode](https://codemirror.net/mode/javascript/): Fix bad parsing of operators without spaces between them. Fix some corner cases around semicolon insertion and regexps.
### New features
Modes added with [`addOverlay`](https://codemirror.net/doc/manual.html#addOverlay) now have access to a [`baseToken`](https://codemirror.net/doc/manual.html#baseToken) method on their input stream, giving access to the tokens of the underlying mode.
## 5.30.0 (2017-09-20)
### Bug fixes
Fixed a number of issues with drawing right-to-left selections and mouse selection in bidirectional text.
[search addon](https://codemirror.net/demo/search/): Fix crash when restarting search after doing empty search.
[mark-selection addon](http://cm/doc/manual.html#addon_mark-selection): Fix off-by-one bug.
[tern addon](https://codemirror.net/demo/tern.html): Fix bad request made when editing at the bottom of a large document.
[javascript mode](https://codemirror.net/mode/javascript/): Improve parsing in a number of corner cases.
[markdown mode](https://codemirror.net/mode/markdown/): Fix crash when a sub-mode doesn't support indentation, allow uppercase X in task lists.
[gfm mode](https://codemirror.net/mode/gfm/): Don't highlight SHA1 'hashes' without numbers to avoid false positives.
[soy mode](https://codemirror.net/mode/soy/): Support injected data and `@param` in comments.
### New features
[simple mode addon](https://codemirror.net/demo/simplemode.html): Allow groups in regexps when `token` isn't an array.
## 5.29.0 (2017-08-24)
### Bug fixes
Fix crash in contentEditable input style when editing near a bookmark.
Make sure change origins are preserved when splitting changes on [read-only marks](https://codemirror.net/doc/manual.html#mark_readOnly).
[javascript mode](https://codemirror.net/mode/javascript/): More support for TypeScript syntax.
[d mode](https://codemirror.net/mode/d/): Support nested comments.
[python mode](https://codemirror.net/mode/python/): Improve tokenizing of operators.
[markdown mode](https://codemirror.net/mode/markdown/): Further improve CommonMark conformance.
[css mode](https://codemirror.net/mode/css/): Don't run comment tokens through the mode's state machine.
[shell mode](https://codemirror.net/mode/shell/): Allow strings to span lines.
[search addon](https://codemirror.net/demo/search/): Fix crash in persistent search when `extraKeys` is null.
## 5.28.0 (2017-07-21)
### Bug fixes
Fix copying of, or replacing editor content with, a single dash character when copying a big selection in some corner cases.
Make [`"goLineLeft"`](https://codemirror.net/doc/manual.html#command_goLineLeft)/`"goLineRight"` behave better on wrapped lines.
[sql mode](https://codemirror.net/mode/sql/): Fix tokenizing of multi-dot operator and allow digits in subfield names.
[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Fix infinite loop on some composed character inputs.
[markdown mode](https://codemirror.net/mode/markdown/): Make list parsing more CommonMark-compliant.
[gfm mode](https://codemirror.net/mode/gfm/): Highlight colon syntax for emoji.
### New features
Expose [`startOperation`](https://codemirror.net/doc/manual.html#startOperation) and `endOperation` for explicit operation management.
[sublime bindings](https://codemirror.net/demo/sublime.html): Add extend-selection (Ctrl-Alt- or Cmd-Shift-Up/Down).
## 5.27.4 (2017-06-29)
### Bug fixes
Fix crash when using mode lookahead.
[markdown mode](https://codemirror.net/mode/markdown/): Don't block inner mode's indentation support.
## 5.27.2 (2017-06-22)
### Bug fixes
Fix crash in the [simple mode](https://codemirror.net/demo/simplemode.html)< addon.
## 5.27.0 (2017-06-22)
### Bug fixes
Fix infinite loop in forced display update.
Properly disable the hidden textarea when `readOnly` is `"nocursor"`.
Calling the `Doc` constructor without `new` works again.
[sql mode](https://codemirror.net/mode/sql/): Handle nested comments.
[javascript mode](https://codemirror.net/mode/javascript/): Improve support for TypeScript syntax.
[markdown mode](https://codemirror.net/mode/markdown/): Fix bug where markup was ignored on indented paragraph lines.
[vim bindings](https://codemirror.net/demo/vim.html): Referencing invalid registers no longer causes an uncaught exception.
[rust mode](https://codemirror.net/mode/rust/): Add the correct MIME type.
[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Document options.
### New features
Mouse button clicks can now be bound in keymaps by using names like `"LeftClick"` or `"Ctrl-Alt-MiddleTripleClick"`. When bound to a function, that function will be passed the position of the click as second argument.
The behavior of mouse selection and dragging can now be customized with the [`configureMouse`](https://codemirror.net/doc/manual.html#option_configureMouse) option.
Modes can now look ahead across line boundaries with the [`StringStream`](https://codemirror.net/doc/manual.html#StringStream)`.lookahead` method.
Introduces a `"type"` token type, makes modes that recognize types output it, and add styling for it to the themes.
New [`pasteLinesPerSelection`](https://codemirror.net/doc/manual.html#option_pasteLinesPerSelection) option to control the behavior of pasting multiple lines into multiple selections.
[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Support multi-line regular expression matches, and normalize strings when matching.
## 5.26.0 (2017-05-22)
### Bug fixes
In textarea-mode, don't reset the input field during composition.
More careful restoration of selections in widgets, during editor redraw.
[javascript mode](https://codemirror.net/mode/javascript/): More TypeScript parsing fixes.
[julia mode](https://codemirror.net/mode/julia/): Fix issue where the mode gets stuck.
[markdown mode](https://codemirror.net/mode/markdown/): Understand cross-line links, parse all bracketed things as links.
[soy mode](https://codemirror.net/mode/soy/): Support single-quoted strings.
[go mode](https://codemirror.net/mode/go/): Don't try to indent inside strings or comments.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Parse line offsets in line or range specs.
## 5.25.2 (2017-04-20)
### Bug fixes
Better handling of selections that cover the whole viewport in contentEditable-mode.
No longer accidentally scroll the editor into view when calling `setValue`.
Work around Chrome Android bug when converting screen coordinates to editor positions.
Make sure long-clicking a selection sets a cursor and doesn't show the editor losing focus.
Fix issue where pointer events were incorrectly disabled on Chrome's overlay scrollbars.
[javascript mode](https://codemirror.net/mode/javascript/): Recognize annotations and TypeScript-style type parameters.
[shell mode](https://codemirror.net/mode/shell/): Handle nested braces.
[markdown mode](https://codemirror.net/mode/markdown/): Make parsing of strong/em delimiters CommonMark-compliant.
## 5.25.0 (2017-03-20)
### Bug fixes
In contentEditable-mode, properly locate changes that repeat a character when inserted with IME.
Fix handling of selections bigger than the viewport in contentEditable mode.
Improve handling of changes that insert or delete lines in contentEditable mode.
Count Unicode control characters 0x80 to 0x9F as special (non-printing) chars.
Fix handling of shadow DOM roots when finding the active element.
Add `role=presentation` to more DOM elements to improve screen reader support.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Make aligning of unchanged chunks more robust.
[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Fix comment-toggling on a block of text that starts and ends in a (different) block comment.
[javascript mode](https://codemirror.net/mode/javascript/): Improve support for TypeScript syntax.
[r mode](https://codemirror.net/mode/r/): Fix indentation after semicolon-less statements.
[shell mode](https://codemirror.net/mode/shell/): Properly handle escaped parentheses in parenthesized expressions.
[markdown mode](https://codemirror.net/mode/markdown/): Fix a few bugs around leaving fenced code blocks.
[soy mode](https://codemirror.net/mode/soy/): Improve indentation.
### New features
[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Support asynchronous linters that return promises.
[continuelist addon](https://codemirror.net/doc/manual.html#addon_continuelist): Support continuing task lists.
[vim bindings](https://codemirror.net/demo/vim.html): Make Y behave like yy.
[sql mode](https://codemirror.net/mode/sql/): Support sqlite dialect.
## 5.24.2 (2017-02-22)
### Bug fixes
[javascript mode](https://codemirror.net/mode/javascript/): Support computed class method names.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Improve aligning of unchanged code in the presence of marks and line widgets.
## 5.24.0 (2017-02-20)
### Bug fixes
A cursor directly before a line-wrapping break is now drawn before or after the line break depending on which direction you arrived from.
Visual cursor motion in line-wrapped right-to-left text should be much more correct.
Fix bug in handling of read-only marked text.
[shell mode](https://codemirror.net/mode/shell/): Properly tokenize nested parentheses.
[python mode](https://codemirror.net/mode/python/): Support underscores in number literals.
[sass mode](https://codemirror.net/mode/sass/): Uses the full list of CSS properties and keywords from the CSS mode, rather than defining its own incomplete subset.
[css mode](https://codemirror.net/mode/css/): Expose `lineComment` property for LESS and SCSS dialects. Recognize vendor prefixes on pseudo-elements.
[julia mode](https://codemirror.net/mode/julia/): Properly indent `elseif` lines.
[markdown mode](https://codemirror.net/mode/markdown/): Properly recognize the end of fenced code blocks when inside other markup.
[scala mode](https://codemirror.net/mode/clike/): Improve handling of operators containing <code>#</code>, <code>@</code>, and <code>:</code> chars.
[xml mode](https://codemirror.net/mode/xml/): Allow dashes in HTML tag names.
[javascript mode](https://codemirror.net/mode/javascript/): Improve parsing of async methods, TypeScript-style comma-separated superclass lists.
[indent-fold addon](https://codemirror.net/demo/folding.html): Ignore comment lines.
### New features
Positions now support a `sticky` property which determines whether they should be associated with the character before (value `"before"`) or after (value `"after"`) them.
[vim bindings](https://codemirror.net/demo/vim.html): Make it possible to remove built-in bindings through the API.
[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Support a per-mode <code>useInnerComments</code> option to optionally suppress descending to the inner modes to get comment strings.
### Breaking changes
The [sass mode](https://codemirror.net/mode/sass/) now depends on the [css mode](https://codemirror.net/mode/css/).
## 5.23.0 (2017-01-19)
### Bug fixes
Presentation-related elements DOM elements are now marked as such to help screen readers.
[markdown mode](https://codemirror.net/mode/markdown/): Be more picky about what HTML tags look like to avoid false positives.
### New features
`findModeByMIME` now understands `+json` and `+xml` MIME suffixes.
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Add support for an `override` option to ignore language-specific defaults.
[panel addon](https://codemirror.net/doc/manual.html#addon_panel): Add a `stable` option that auto-scrolls the content to keep it in the same place when inserting/removing a panel.
## 5.22.2 (2017-01-12)
### Bug fixes
Include rollup.config.js in NPM package, so that it can be used to build from source.
## 5.22.0 (2016-12-20)
### Bug fixes
[sublime bindings](https://codemirror.net/demo/sublime.html): Make `selectBetweenBrackets` work with multiple cursors.
[javascript mode](https://codemirror.net/mode/javascript/): Fix issues with parsing complex TypeScript types, imports, and exports.
A contentEditable editor instance with autofocus enabled no longer crashes during initializing.
### New features
[emacs bindings](https://codemirror.net/demo/emacs.html): Export `CodeMirror.emacs` to allow other addons to hook into Emacs-style functionality.
[active-line addon](https://codemirror.net/doc/manual.html#addon_active-line): Add `nonEmpty` option.
New event: [`optionChange`](https://codemirror.net/doc/manual.html#event_optionChange).
## 5.21.0 (2016-11-21)
### Bug fixes
Tapping/clicking the editor in [contentEditable mode](https://codemirror.net/doc/manual.html#option_inputStyle) on Chrome now puts the cursor at the tapped position.
Fix various crashes and misbehavior when reading composition events in [contentEditable mode](https://codemirror.net/doc/manual.html#option_inputStyle).
Catches and ignores an IE 'Unspecified Error' when creating an editor in an iframe before there is a `<body>`.
[merge addon](https://codemirror.net/doc/manual.html#addon_merge): Fix several issues in the chunk-aligning feature.
[verilog mode](https://codemirror.net/mode/verilog): Rewritten to address various issues.
[julia mode](https://codemirror.net/mode/julia): Recognize Julia 0.5 syntax.
[swift mode](https://codemirror.net/mode/swift): Various fixes and adjustments to current syntax.
[markdown mode](https://codemirror.net/mode/markdown): Allow lists without a blank line above them.
### New features
The [`setGutterMarker`](https://codemirror.net/doc/manual.html#setGutterMarker), [`clearGutter`](https://codemirror.net/doc/manual.html#clearGutter), and [`lineInfo`](https://codemirror.net/doc/manual.html#lineInfo) methods are now available on `Doc` objects.
The [`heightAtLine`](https://codemirror.net/doc/manual.html#heightAtLine) method now takes an extra argument to allow finding the height at the top of the line's line widgets.
[ruby mode](https://codemirror.net/mode/ruby): `else` and `elsif` are now immediately indented.
[vim bindings](https://codemirror.net/demo/vim.html): Bind Ctrl-T and Ctrl-D to in- and dedent in insert mode.
## 5.20.2 (2016-10-21)
### Bug fixes
Fix `CodeMirror.version` returning the wrong version number.
## 5.20.0 (2016-10-20)
### Bug fixes
Make `newlineAndIndent` command work with multiple cursors on the same line.
Make sure keypress events for backspace are ignored.
Tokens styled with overlays no longer get a nonsense `cm-cm-overlay` class.
Line endings for pasted content are now normalized to the editor's [preferred ending](https://codemirror.net/doc/manual.html#option_lineSeparator).
[javascript mode](https://codemirror.net/mode/javascript): Improve support for class expressions. Support TypeScript optional class properties, the `abstract` keyword, and return type declarations for arrow functions.
[css mode](https://codemirror.net/mode/css): Fix highlighting of mixed-case keywords.
[closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets): Improve behavior when typing a quote before a string.
### New features
The core is now maintained as a number of small files, using ES6 syntax and modules, under the `src/` directory. A git checkout no longer contains a working `codemirror.js` until you `npm run build` (but when installing from NPM, it is included).
The [`refresh`](https://codemirror.net/doc/manual.html#event_refresh) event is now documented and stable.
## 5.19.0 (2016-09-20)
### Bugfixes
[erlang mode](https://codemirror.net/mode/erlang): Fix mode crash when trying to read an empty context.
[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Fix broken behavior when toggling comments inside a comment.
xml-fold addon: Fix a null-dereference bug.
Page up and page down now do something even in single-line documents.
Fix an issue where the cursor position could be off in really long (~8000 character) tokens.
### New features
[javascript mode](https://codemirror.net/mode/javascript): Better indentation when semicolons are missing. Better support for TypeScript classes, optional parameters, and the `type` keyword.
The [`blur`](https://codemirror.net/doc/manual.html#event_blur) and [`focus`](https://codemirror.net/doc/manual.html#event_focus) events now pass the DOM event to their handlers.
## 5.18.2 (2016-08-23)
### Bugfixes
[vue mode](https://codemirror.net/mode/vue): Fix outdated references to renamed Pug mode dependency.
## 5.18.0 (2016-08-22)
### Bugfixes
Make sure [gutter backgrounds](https://codemirror.net/doc/manual.html#addLineClass) stick to the rest of the gutter during horizontal scrolling.
The contenteditable [`inputStyle`](https://codemirror.net/doc/manual.html#option_inputStyle) now properly supports pasting on pre-Edge IE versions.
[javascript mode](https://codemirror.net/mode/javascript): Fix some small parsing bugs and improve TypeScript support.
[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Fix bug where active highlighting was left in editor when the addon was disabled.
[match-highlighter addon](https://codemirror.net/doc/manual.html#addon_match-highlighter): Only start highlighting things when the editor gains focus.
[javascript-hint addon](https://codemirror.net/doc/manual.html#addon_javascript-hint): Also complete non-enumerable properties.
### New features
The [`addOverlay`](https://codemirror.net/doc/manual.html#addOverlay) method now supports a `priority` option to control the order in which overlays are applied.
MIME types that end in `+json` now default to the JSON mode when the MIME itself is not defined.
### Breaking changes
The mode formerly known as Jade was renamed to [Pug](https://codemirror.net/mode/pug).
The [Python mode](https://codemirror.net/mode/python) now defaults to Python 3 (rather than 2) syntax.
## 5.17.0 (2016-07-19)
### Bugfixes
Fix problem with wrapped trailing whitespace displaying incorrectly.
Prevent IME dialog from overlapping typed content in Chrome.
Improve measuring of characters near a line wrap.
[javascript mode](https://codemirror.net/mode/javascript): Improve support for `async`, allow trailing commas in `import` lists.
[vim bindings](https://codemirror.net/demo/vim.html): Fix backspace in replace mode.
[sublime bindings](https://codemirror.net/demo/sublime.html): Fix some key bindings on OS X to match Sublime Text.
### New features
[markdown mode](https://codemirror.net/mode/markdown): Add more classes to image links in highlight-formatting mode.
## 5.16.0 (2016-06-20)
### Bugfixes
Fix glitches when dragging content caused by the drop indicator receiving mouse events.
Make Control-drag work on Firefox.
Make clicking or selection-dragging at the end of a wrapped line select the right position.
[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): Prevent widget scrollbar from hiding part of the hint text.
[rulers addon](https://codemirror.net/doc/manual.html#addon_rulers): Prevent rulers from forcing a horizontal editor scrollbar.
### New features
[search addon](https://codemirror.net/doc/manual.html#addon_search): Automatically bind search-related keys in persistent dialog.
[sublime keymap](https://codemirror.net/demo/sublime.html): Add a multi-cursor aware smart backspace binding.
## 5.15.2 (2016-05-20)
### Bugfixes
Fix a critical document corruption bug that occurs when a document is gradually grown.
## 5.15.0 (2016-05-20)
### Bugfixes
Fix bug that caused the selection to reset when focusing the editor in contentEditable input mode.
Fix issue where not all ASCII control characters were being replaced by placeholders.
Remove the assumption that all modes have a `startState` method from several wrapping modes.
Fix issue where the editor would complain about overlapping collapsed ranges when there weren't any.
Optimize document tree building when loading or pasting huge chunks of content.
[markdown mode](https://codemirror.net/mode/markdown/): Fix several issues in matching link targets.
[clike mode](https://codemirror.net/mode/clike/): Improve indentation of C++ template declarations.
### New features
Explicitly bind Ctrl-O on OS X to make that binding (“open line”) act as expected.
Pasting [linewise-copied](https://codemirror.net/doc/manual.html#option_lineWiseCopyCut) content when there is no selection now inserts the lines above the current line.
[javascript mode](https://codemirror.net/mode/javascript/): Support `async`/`await` and improve support for TypeScript type syntax.
## 5.14.2 (2016-04-20)
### Bugfixes
Push a new package to NPM due to an [NPM bug](https://github.com/npm/npm/issues/5082) omitting the LICENSE file in 5.14.0.
Set `dataTransfer.effectAllowed` in `dragstart` handler to help browsers use the right drag icon.
Add the [mbox mode](https://codemirror.net/mode/mbox/index.html) to `mode/meta.js`.
## 5.14.0 (2016-04-20)
### Bugfixes
[`posFromIndex`](https://codemirror.net/doc/manual.html#posFromIndex) and [`indexFromPos`](https://codemirror.net/doc/manual.html#indexFromPos) now take [`lineSeparator`](https://codemirror.net/doc/manual.html#option_lineSeparator) into account.
[vim bindings](https://codemirror.net/demo/vim.html): Only call `.save()` when it is actually available.
[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Be careful not to mangle multi-line strings.
[Python mode](https://codemirror.net/mode/python/index.html): Improve distinguishing of decorators from `@` operators.
[`findMarks`](https://codemirror.net/doc/manual.html#findMarks): No longer return marks that touch but don't overlap given range.
### New features
[vim bindings](https://codemirror.net/demo/vim.html): Add yank command.
[match-highlighter addon](https://codemirror.net/doc/manual.html#addon_match-highlighter): Add `trim` option to disable ignoring of whitespace.
[PowerShell mode](https://codemirror.net/mode/powershell/index.html): Added.
[Yacas mode](https://codemirror.net/mode/yacas/index.html): Added.
[Web IDL mode](https://codemirror.net/mode/webidl/index.html): Added.
[SAS mode](https://codemirror.net/mode/sas/index.html): Added.
[mbox mode](https://codemirror.net/mode/mbox/index.html): Added.
## 5.13.2 (2016-03-23)
### Bugfixes
Solves a problem where the gutter would sometimes not extend all the way to the end of the document.
## 5.13.0 (2016-03-21)
### New features
New DOM event forwarded: [`"dragleave"`](https://codemirror.net/doc/manual.html#event_dom).
[protobuf mode](https://codemirror.net/mode/protobuf/index.html): Newly added.
### Bugfixes
Fix problem where [`findMarks`](https://codemirror.net/doc/manual.html#findMarks) sometimes failed to find multi-line marks.
Fix crash that showed up when atomic ranges and bidi text were combined.
[show-hint addon](https://codemirror.net/demo/complete.html): Completion widgets no longer close when the line indented or dedented.
[merge addon](https://codemirror.net/demo/merge.html): Fix bug when merging chunks at the end of the file.
[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): No longer gets confused by [`swapDoc`](https://codemirror.net/doc/manual.html#swapDoc).
[simplescrollbars addon](https://codemirror.net/doc/manual.html#addon_simplescrollbars): Fix invalid state when deleting at end of document.
[clike mode](https://codemirror.net/mode/clike/index.html): No longer gets confused when a comment starts after an operator.
[markdown mode](https://codemirror.net/mode/markdown/index.html): Now supports CommonMark-style flexible list indentation.
[dylan mode](https://codemirror.net/mode/dylan/index.html): Several improvements and fixes.
## 5.12.0 (2016-02-19)
### New features
[Vim bindings](https://codemirror.net/demo/vim.html): Ctrl-Q is now an alias for Ctrl-V.
[Vim bindings](https://codemirror.net/demo/vim.html): The Vim API now exposes an `unmap` method to unmap bindings.
[active-line addon](https://codemirror.net/demo/activeline.html): This addon can now style the active line's gutter.
[FCL mode](https://codemirror.net/mode/fcl/): Newly added.
[SQL mode](https://codemirror.net/mode/sql/): Now has a Postgresql dialect.
### Bugfixes
Fix [issue](https://github.com/codemirror/CodeMirror/issues/3781) where trying to scroll to a horizontal position outside of the document's width could cause the gutter to be positioned incorrectly.
Use absolute, rather than fixed positioning in the context-menu intercept hack, to work around a [problem](https://github.com/codemirror/CodeMirror/issues/3238) when the editor is inside a transformed parent container.
Solve a [problem](https://github.com/codemirror/CodeMirror/issues/3821) where the horizontal scrollbar could hide text in Firefox.
Fix a [bug](https://github.com/codemirror/CodeMirror/issues/3834) that caused phantom scroll space under the text in some situations.
[Sublime Text bindings](https://codemirror.net/demo/sublime.html): Bind delete-line to Shift-Ctrl-K on OS X.
[Markdown mode](https://codemirror.net/mode/markdown/): Fix [issue](https://github.com/codemirror/CodeMirror/issues/3787) where the mode would keep state related to fenced code blocks in an unsafe way, leading to occasional corrupted parses.
[Markdown mode](https://codemirror.net/mode/markdown/): Ignore backslashes in code fragments.
[Markdown mode](https://codemirror.net/mode/markdown/): Use whichever mode is registered as `text/html` to parse HTML.
[Clike mode](https://codemirror.net/mode/clike/): Improve indentation of Scala `=>` functions.
[Python mode](https://codemirror.net/mode/python/): Improve indentation of bracketed code.
[HTMLMixed mode](https://codemirror.net/mode/htmlmixed/): Support multi-line opening tags for sub-languages (`<script>`, `<style>`, etc).
[Spreadsheet mode](https://codemirror.net/mode/spreadsheet/): Fix bug where the mode did not advance the stream when finding a backslash.
[XML mode](https://codemirror.net/mode/xml/): The mode now takes a `matchClosing` option to configure whether mismatched closing tags should be highlighted as errors.
## 5.11.0 (2016-01-20)
* New modes: [JSX](https://codemirror.net/mode/jsx/index.html), [literate Haskell](https://codemirror.net/mode/haskell-literate/index.html)
* The editor now forwards more [DOM events](https://codemirror.net/doc/manual.html#event_dom): `cut`, `copy`, `paste`, and `touchstart`. It will also forward `mousedown` for drag events
* Fixes a bug where bookmarks next to collapsed spans were not rendered
* The [Swift](https://codemirror.net/mode/swift/index.html) mode now supports auto-indentation
* Frontmatters in the [YAML frontmatter](https://codemirror.net/mode/yaml-frontmatter/index.html) mode are now optional as intended
## 5.10.0 (2015-12-21)
* Modify the way [atomic ranges](https://codemirror.net/doc/manual.html#mark_atomic) are skipped by selection to try and make it less surprising.
* The [Swift mode](https://codemirror.net/mode/swift/index.html) was rewritten.
* New addon: [jump-to-line](https://codemirror.net/doc/manual.html#addon_jump-to-line).
* New method: [`isReadOnly`](https://codemirror.net/doc/manual.html#isReadOnly).
* The [show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint) now defaults to picking completions on single click.
* The object passed to [`"beforeSelectionChange"`](https://codemirror.net/doc/manual.html#event_beforeSelectionChange) events now has an `origin` property.
* New mode: [Crystal](https://codemirror.net/mode/crystal/index.html).
## 5.9.0 (2015-11-23)
* Improve the way overlay (OS X-style) scrollbars are handled
* Make [annotatescrollbar](https://codemirror.net/doc/manual.html#addon_annotatescrollbar) and scrollpastend addons work properly together
* Make [show-hint](https://codemirror.net/doc/manual.html#addon_show-hint) addon select options on single click by default, move selection to hovered item
* Properly fold comments that include block-comment-start markers
* Many small language mode fixes
## 5.8.0 (2015-10-20)
* Fixes an infinite loop in the [hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap)
* New modes: [NSIS](https://codemirror.net/mode/nsis/index.html), [Ceylon](https://codemirror.net/mode/clike/index.html)
* The Kotlin mode is now a [clike](https://codemirror.net/mode/clike/index.html) dialect, rather than a stand-alone mode
* New option: [`allowDropFileTypes`](https://codemirror.net/doc/manual.html#option_allowDropFileTypes). Binary files can no longer be dropped into CodeMirror
* New themes: [bespin](https://codemirror.net/demo/theme.html#bespin), [hopscotch](https://codemirror.net/demo/theme.html#hopscotch), [isotope](https://codemirror.net/demo/theme.html#isotope), [railscasts](https://codemirror.net/demo/theme.html#railscasts)
## 5.7.0 (2015-09-21)
* New modes: [Vue](https://codemirror.net/mode/vue/index.html), [Oz](https://codemirror.net/mode/oz/index.html), [MscGen](https://codemirror.net/mode/mscgen/index.html) (and dialects), [Closure Stylesheets](https://codemirror.net/mode/css/gss.html)
* Implement [CommonMark](http://commonmark.org)-style flexible list indent and cross-line code spans in [Markdown](https://codemirror.net/mode/markdown/index.html) mode
* Add a replace-all button to the [search addon](https://codemirror.net/doc/manual.html#addon_search), and make the persistent search dialog transparent when it obscures the match
* Handle `async`/`await` and ocal and binary numbers in [JavaScript mode](https://codemirror.net/mode/javascript/index.html)
* Fix various issues with the [Haxe mode](https://codemirror.net/mode/haxe/index.html)
* Make the [closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets) select only the wrapped text when wrapping selection in brackets
* Tokenize properties as properties in the [CoffeeScript mode](https://codemirror.net/mode/coffeescript/index.html)
* The [placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder) now accepts a DOM node as well as a string placeholder
## 5.6.0 (2015-08-20)
* Fix bug where you could paste into a `readOnly` editor
* Show a cursor at the drop location when dragging over the editor
* The [Rust mode](https://codemirror.net/mode/rust/index.html) was rewritten to handle modern Rust
* The editor and theme CSS was cleaned up. Some selectors are now less specific than before
* New theme: [abcdef](https://codemirror.net/demo/theme.html#abcdef)
* Lines longer than [`maxHighlightLength`](https://codemirror.net/doc/manual.html#option_maxHighlightLength) are now less likely to mess up indentation
* New addons: [`autorefresh`](https://codemirror.net/doc/manual.html#addon_autorefresh) for refreshing an editor the first time it becomes visible, and `html-lint` for using [HTMLHint](http://htmlhint.com/)
* The [`search`](https://codemirror.net/doc/manual.html#addon_search) addon now recognizes `\r` and `\n` in pattern and replacement input
## 5.5.0 (2015-07-20)
* New option: [`lineSeparator`](https://codemirror.net/doc/manual.html#option_lineSeparator) (with corresponding [method](https://codemirror.net/doc/manual.html#lineSeparator))
* New themes: [dracula](https://codemirror.net/demo/theme.html#dracula), [seti](https://codemirror.net/demo/theme.html#seti), [yeti](https://codemirror.net/demo/theme.html#yeti), [material](https://codemirror.net/demo/theme.html#material), and [icecoder](https://codemirror.net/demo/theme.html#icecoder)
* New modes: [Brainfuck](https://codemirror.net/mode/brainfuck/index.html), [VHDL](https://codemirror.net/mode/vhdl/index.html), Squirrel ([clike](https://codemirror.net/mode/clike/index.html) dialect)
* Define a `findPersistent` command in the [search](https://codemirror.net/demo/search.html) addon, for a dialog that stays open as you cycle through matches
* From this release on, the NPM module doesn't include documentation and demos
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.4.0...5.5.0)
## 5.4.0 (2015-06-25)
* New modes: [Twig](https://codemirror.net/mode/twig/index.html), [Elm](https://codemirror.net/mode/elm/index.html), [Factor](https://codemirror.net/mode/factor/index.html), [Swift](https://codemirror.net/mode/swift/index.html)
* Prefer clipboard API (if available) when pasting
* Refined definition highlighting in [clike](https://codemirror.net/mode/clike/index.html) mode
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.3.0...5.4.0)
## 5.3.0 (2015-05-20)
* Fix several regressions in the [`show-hint`](https://codemirror.net/doc/manual.html#addon_show-hint) addon (`completeSingle` option, `"shown"` and `"close"` events)
* The [vim mode](https://codemirror.net/demo/vim.html) API was [documented](https://codemirror.net/doc/manual.html#vimapi)
* New modes: [ASN.1](https://codemirror.net/mode/asn.1/index.html), [TTCN](https://codemirror.net/mode/ttcn/index.html), and [TTCN-CFG](https://codemirror.net/mode/ttcn-cfg/index.html)
* The [clike](https://codemirror.net/mode/clike/index.html) mode can now deep-indent `switch` statements, and roughly recognizes types and defined identifiers
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.2.0...5.3.0)
## 5.2.0 (2015-04-20)
* Fix several race conditions in [`show-hint`](https://codemirror.net/doc/manual.html#addon_show-hint)'s asynchronous mode
* Fix backspace binding in [Sublime bindings](https://codemirror.net/demo/sublime.html)
* Change the way IME is handled in the `"textarea"` [input style](https://codemirror.net/doc/manual.html#option_inputStyle)
* New modes: [MUMPS](https://codemirror.net/mode/mumps/index.html), [Handlebars](https://codemirror.net/mode/handlebars/index.html)
* Rewritten modes: [Django](https://codemirror.net/mode/django/index.html), [Z80](https://codemirror.net/mode/z80/index.html)
* New theme: [Liquibyte](https://codemirror.net/demo/theme.html#liquibyte)
* New option: [`lineWiseCopyCut`](https://codemirror.net/doc/manual.html#option_lineWiseCopyCut)
* The [Vim mode](https://codemirror.net/demo/vim.html) now supports buffer-local options and the `filetype` setting
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.1.0...5.2.0)
## 5.1.0 (2015-03-23)
* New modes: [ASCII armor](https://codemirror.net/mode/asciiarmor/index.html) (PGP data), [Troff](https://codemirror.net/mode/troff/index.html), and [CMake](https://codemirror.net/mode/cmake/index.html).
* Remove SmartyMixed mode, rewrite [Smarty](https://codemirror.net/mode/smarty/index.html) mode to supersede it.
* New commands in the [merge addon](https://codemirror.net/doc/manual.html#addon_merge): `goNextDiff` and `goPrevDiff`.
* The [closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets) can now be configured per mode.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/5.0.0...5.1.0).
## 5.0.0 (2015-02-20)
* Experimental mobile support (tested on iOS, Android Chrome, stock Android browser)
* New option [`inputStyle`](https://codemirror.net/doc/manual.html#option_inputStyle) to switch between hidden textarea and contenteditable input.
* The [`getInputField`](https://codemirror.net/doc/manual.html#getInputField) method is no longer guaranteed to return a textarea.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.13.0...5.0.0).
## 4.13.0 (2015-02-20)
* Fix the way the [`closetag`](https://codemirror.net/demo/closetag.html) demo handles the slash character.
* New modes: [Forth](https://codemirror.net/mode/forth/index.html), [Stylus](https://codemirror.net/mode/stylus/index.html).
* Make the [CSS mode](https://codemirror.net/mode/css/index.html) understand some modern CSS extensions.
* Have the [Scala mode](https://codemirror.net/mode/clike/index.html) handle symbols and triple-quoted strings.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.12.0...4.13.0).
## 4.12.0 (2015-01-22)
* The [`closetag`](https://codemirror.net/doc/manual.html#addon_closetag) addon now defines a `"closeTag"` command.
* Adds a `findModeByFileName` to the [mode metadata](https://codemirror.net/doc/manual.html#addon_meta) addon.
* [Simple mode](https://codemirror.net/demo/simplemode.html) rules can now contain a `sol` property to only match at the start of a line.
* New addon: [`selection-pointer`](https://codemirror.net/doc/manual.html#addon_selection-pointer) to style the mouse cursor over the selection.
* Improvements to the [Sass mode](https://codemirror.net/mode/sass/index.html)'s indentation.
* The [Vim keymap](https://codemirror.net/demo/vim.html)'s search functionality now supports [scrollbar annotation](https://codemirror.net/doc/manual.html#addon_matchesonscrollbar).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.11.0...4.12.0).
## 4.11.0 (2015-01-09)
Unfortunately, 4.10 did not take care of the Firefox scrolling issue entirely. This release adds two more patches to address that.
## 4.10.0 (2014-12-29)
Emergency single-patch update to 4.9\. Fixes Firefox-specific problem where the cursor could end up behind the horizontal scrollbar.
## 4.9.0 (2014-12-23)
* Overhauled scroll bar handling. Add pluggable [scrollbar implementations](https://codemirror.net/demo/simplescrollbars.html).
* Tweaked behavior for the [completion addons](https://codemirror.net/doc/manual.html#addon_show-hint) to not take text after cursor into account.
* Two new optional features in the [merge addon](https://codemirror.net/doc/manual.html#addon_merge): aligning editors, and folding unchanged text.
* New modes: [Dart](https://codemirror.net/mode/dart/index.html), [EBNF](https://codemirror.net/mode/ebnf/index.html), [spreadsheet](https://codemirror.net/mode/spreadsheet/index.html), and [Soy](https://codemirror.net/mode/soy/index.html).
* New [addon](https://codemirror.net/demo/panel.html) to show persistent panels below/above an editor.
* New themes: [zenburn](https://codemirror.net/demo/theme.html#zenburn) and [tomorrow night bright](https://codemirror.net/demo/theme.html#tomorrow-night-bright).
* Allow ctrl-click to clear existing cursors.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.8.0...4.9.0).
## 4.8.0 (2014-11-22)
* Built-in support for [multi-stroke key bindings](https://codemirror.net/doc/manual.html#normalizeKeyMap).
* New method: [`getLineTokens`](https://codemirror.net/doc/manual.html#getLineTokens).
* New modes: [dockerfile](https://codemirror.net/mode/dockerfile/index.html), [IDL](https://codemirror.net/mode/idl/index.html), [Objective C](https://codemirror.net/mode/clike/index.html) (crude).
* Support styling of gutter backgrounds, allow `"gutter"` styles in [`addLineClass`](https://codemirror.net/doc/manual.html#addLineClass).
* Many improvements to the [Vim mode](https://codemirror.net/demo/vim.html), rewritten visual mode.
* Improvements to modes: [gfm](https://codemirror.net/mode/gfm/index.html) (strikethrough), [SPARQL](https://codemirror.net/mode/sparql/index.html) (version 1.1 support), and [sTeX](https://codemirror.net/mode/stex/index.html) (no more runaway math mode).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.7.0...4.8.0).
## 4.7.0 (2014-10-20)
* **Incompatible**: The [lint addon](https://codemirror.net/demo/lint.html) now passes the editor's value as first argument to asynchronous lint functions, for consistency. The editor is still passed, as fourth argument.
* Improved handling of unicode identifiers in modes for languages that support them.
* More mode improvements: [CoffeeScript](https://codemirror.net/mode/coffeescript/index.html) (indentation), [Verilog](https://codemirror.net/mode/verilog/index.html) (indentation), [Scala](https://codemirror.net/mode/clike/index.html) (indentation, triple-quoted strings), and [PHP](https://codemirror.net/mode/php/index.html) (interpolated variables in heredoc strings).
* New modes: [Textile](https://codemirror.net/mode/textile/index.html) and [Tornado templates](https://codemirror.net/mode/tornado/index.html).
* Experimental new [way to define modes](https://codemirror.net/demo/simplemode.html).
* Improvements to the [Vim bindings](https://codemirror.net/demo/vim.html): Arbitrary insert mode key mappings are now possible, and text objects are supported in visual mode.
* The mode [meta-information file](https://codemirror.net/mode/meta.js) now includes information about file extensions, and [helper functions](https://codemirror.net/doc/manual.html#addon_meta) `findModeByMIME` and `findModeByExtension`.
* New logo!
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.6.0...4.7.0).
## 4.6.0 (2014-09-19)
* New mode: [Modelica](https://codemirror.net/mode/modelica/index.html)
* New method: [`findWordAt`](https://codemirror.net/doc/manual.html#findWordAt)
* Make it easier to [use text background styling](https://codemirror.net/demo/markselection.html)
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.5.0...4.6.0).
## 4.5.0 (2014-08-21)
* Fix several serious bugs with horizontal scrolling
* New mode: [Slim](https://codemirror.net/mode/slim/index.html)
* New command: [`goLineLeftSmart`](https://codemirror.net/doc/manual.html#command_goLineLeftSmart)
* More fixes and extensions for the [Vim](https://codemirror.net/demo/vim.html) visual block mode
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.4.0...4.5.0).
## 4.4.0 (2014-07-21)
* **Note:** Some events might now fire in slightly different order (`"change"` is still guaranteed to fire before `"cursorActivity"`)
* Nested operations in multiple editors are now synced (complete at same time, reducing DOM reflows)
* Visual block mode for [vim](https://codemirror.net/demo/vim.html) (<C-v>) is nearly complete
* New mode: [Kotlin](https://codemirror.net/mode/kotlin/index.html)
* Better multi-selection paste for text copied from multiple CodeMirror selections
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.3.0...4.4.0).
## 4.3.0 (2014-06-23)
* Several [vim bindings](https://codemirror.net/demo/vim.html) improvements: search and exCommand history, global flag for `:substitute`, `:global` command.
* Allow hiding the cursor by setting [`cursorBlinkRate`](https://codemirror.net/doc/manual.html#option_cursorBlinkRate) to a negative value.
* Make gutter markers themeable, use this in foldgutter.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.2.0...4.3.0).
## 4.2.0 (2014-05-19)
* Fix problem where some modes were broken by the fact that empty tokens were forbidden.
* Several fixes to context menu handling.
* On undo, scroll _change_, not cursor, into view.
* Rewritten [Jade](https://codemirror.net/mode/jade/index.html) mode.
* Various improvements to [Shell](https://codemirror.net/mode/shell/index.html) (support for more syntax) and [Python](https://codemirror.net/mode/python/index.html) (better indentation) modes.
* New mode: [Cypher](https://codemirror.net/mode/cypher/index.html).
* New theme: [Neo](https://codemirror.net/demo/theme.html#neo).
* Support direct styling options (color, line style, width) in the [rulers](https://codemirror.net/doc/manual.html#addon_rulers) addon.
* Recognize per-editor configuration for the [show-hint](https://codemirror.net/doc/manual.html#addon_show-hint) and [foldcode](https://codemirror.net/doc/manual.html#addon_foldcode) addons.
* More intelligent scanning for existing close tags in [closetag](https://codemirror.net/doc/manual.html#addon_closetag) addon.
* In the [Vim bindings](https://codemirror.net/demo/vim.html): Fix bracket matching, support case conversion in visual mode, visual paste, append action.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.1.0...4.2.0).
## 4.1.0 (2014-04-22)
* _Slightly incompatible_: The [`"cursorActivity"`](https://codemirror.net/doc/manual.html#event_cursorActivity) event now fires after all other events for the operation (and only for handlers that were actually registered at the time the activity happened).
* New command: [`insertSoftTab`](https://codemirror.net/doc/manual.html#command_insertSoftTab).
* New mode: [Django](https://codemirror.net/mode/django/index.html).
* Improved modes: [Verilog](https://codemirror.net/mode/verilog/index.html) (rewritten), [Jinja2](https://codemirror.net/mode/jinja2/index.html), [Haxe](https://codemirror.net/mode/haxe/index.html), [PHP](https://codemirror.net/mode/php/index.html) (string interpolation highlighted), [JavaScript](https://codemirror.net/mode/javascript/index.html) (indentation of trailing else, template strings), [LiveScript](https://codemirror.net/mode/livescript/index.html) (multi-line strings).
* Many small issues from the 3.x→4.x transition were found and fixed.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/4.0.3...4.1.0).
## 3.24.0 (2014-04-22)
Merges the improvements from 4.1 that could easily be applied to the 3.x code. Also improves the way the editor size is updated when line widgets change.
## 3.23.0 (2014-03-20)
* In the [XML mode](https://codemirror.net/mode/xml/index.html), add `brackets` style to angle brackets, fix case-sensitivity of tags for HTML.
* New mode: [Dylan](https://codemirror.net/mode/dylan/index.html).
* Many improvements to the [Vim bindings](https://codemirror.net/demo/vim.html).
## 3.22.0 (2014-02-21)
* Adds the [`findMarks`](https://codemirror.net/doc/manual.html#findMarks) method.
* New addons: [rulers](https://codemirror.net/doc/manual.html#addon_rulers), markdown-fold, yaml-lint.
* New theme: [mdn-like](https://codemirror.net/demo/theme.html#mdn-like).
* New mode: [Solr](https://codemirror.net/mode/solr/index.html).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.21.0...3.22.0).
## 3.21.0 (2014-01-16)
* Auto-indenting a block will no longer add trailing whitespace to blank lines.
* Marking text has a new option [`clearWhenEmpty`](https://codemirror.net/doc/manual.html#markText) to control auto-removal.
* Several bugfixes in the handling of bidirectional text.
* The [XML](https://codemirror.net/mode/xml/index.html) and [CSS](https://codemirror.net/mode/css/index.html) modes were largely rewritten. [LESS](https://codemirror.net/mode/css/less.html) support was added to the CSS mode.
* The OCaml mode was moved to an [mllike](https://codemirror.net/mode/mllike/index.html) mode, F# support added.
* Make it possible to fetch multiple applicable helper values with [`getHelpers`](https://codemirror.net/doc/manual.html#getHelpers), and to register helpers matched on predicates with [`registerGlobalHelper`](https://codemirror.net/doc/manual.html#registerGlobalHelper).
* New theme [pastel-on-dark](https://codemirror.net/demo/theme.html#pastel-on-dark).
* Better ECMAScript 6 support in [JavaScript](https://codemirror.net/mode/javascript/index.html) mode.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.20.0...3.21.0).
## 3.20.0 (2013-11-21)
* New modes: [Julia](https://codemirror.net/mode/julia/index.html) and [PEG.js](https://codemirror.net/mode/pegjs/index.html).
* Support ECMAScript 6 in the [JavaScript mode](https://codemirror.net/mode/javascript/index.html).
* Improved indentation for the [CoffeeScript mode](https://codemirror.net/mode/coffeescript/index.html).
* Make non-printable-character representation [configurable](https://codemirror.net/doc/manual.html#option_specialChars).
* Add ‘notification’ functionality to [dialog](https://codemirror.net/doc/manual.html#addon_dialog) addon.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.19.0...3.20.0).
## 3.19.0 (2013-10-21)
* New modes: [Eiffel](https://codemirror.net/mode/eiffel/index.html), [Gherkin](https://codemirror.net/mode/gherkin/index.html), [MSSQL dialect](https://codemirror.net/mode/sql/?mime=text/x-mssql).
* New addons: [hardwrap](https://codemirror.net/doc/manual.html#addon_hardwrap), [sql-hint](https://codemirror.net/doc/manual.html#addon_sql-hint).
* New theme: [MBO](https://codemirror.net/demo/theme.html#mbo).
* Add [support](https://codemirror.net/doc/manual.html#token_style_line) for line-level styling from mode tokenizers.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.18.0...3.19.0).
## 3.18.0 (2013-09-23)
Emergency release to fix a problem in 3.17 where `.setOption("lineNumbers", false)` would raise an error.
## 3.17.0 (2013-09-23)
* New modes: [Fortran](https://codemirror.net/mode/fortran/index.html), [Octave](https://codemirror.net/mode/octave/index.html) (Matlab), [TOML](https://codemirror.net/mode/toml/index.html), and [DTD](https://codemirror.net/mode/dtd/index.html).
* New addons: [`css-lint`](https://codemirror.net/addon/lint/css-lint.js), [`css-hint`](https://codemirror.net/doc/manual.html#addon_css-hint).
* Improve resilience to CSS 'frameworks' that globally mess up `box-sizing`.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.16.0...3.17.0).
## 3.16.0 (2013-08-21)
* The whole codebase is now under a single [license](https://codemirror.net/LICENSE) file.
* The project page was overhauled and redesigned.
* New themes: [Paraiso](https://codemirror.net/demo/theme.html#paraiso-dark) ([light](https://codemirror.net/demo/theme.html#paraiso-light)), [The Matrix](https://codemirror.net/demo/theme.html#the-matrix).
* Improved interaction between themes and [active-line](https://codemirror.net/doc/manual.html#addon_active-line)/[matchbrackets](https://codemirror.net/doc/manual.html#addon_matchbrackets) addons.
* New [folding](https://codemirror.net/doc/manual.html#addon_foldcode) function `CodeMirror.fold.comment`.
* Added [fullscreen](https://codemirror.net/doc/manual.html#addon_fullscreen) addon.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.15.0...3.16.0).
## 3.15.0 (2013-07-29)
* New modes: [Jade](https://codemirror.net/mode/jade/index.html), [Nginx](https://codemirror.net/mode/nginx/index.html).
* New addons: [Tern](https://codemirror.net/demo/tern.html), [matchtags](https://codemirror.net/doc/manual.html#addon_matchtags), and [foldgutter](https://codemirror.net/doc/manual.html#addon_foldgutter).
* Introduced [_helper_](https://codemirror.net/doc/manual.html#getHelper) concept ([context](https://groups.google.com/forum/#!msg/codemirror/cOc0xvUUEUU/nLrX1-qnidgJ)).
* New method: [`getModeAt`](https://codemirror.net/doc/manual.html#getModeAt).
* New themes: base16 [dark](https://codemirror.net/demo/theme.html#base16-dark)/[light](https://codemirror.net/demo/theme.html#base16-light), 3024 [dark](https://codemirror.net/demo/theme.html#3024-night)/[light](https://codemirror.net/demo/theme.html#3024-day), [tomorrow-night](https://codemirror.net/demo/theme.html#tomorrow-night-eighties).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.14.0...3.15.0).
## 3.14.0 (2013-06-20)
* New addons: [trailing space highlight](https://codemirror.net/doc/manual.html#addon_trailingspace), [XML completion](https://codemirror.net/doc/manual.html#addon_xml-hint) (rewritten), and [diff merging](https://codemirror.net/doc/manual.html#addon_merge).
* [`markText`](https://codemirror.net/doc/manual.html#markText) and [`addLineWidget`](https://codemirror.net/doc/manual.html#addLineWidget) now take a `handleMouseEvents` option.
* New methods: [`lineAtHeight`](https://codemirror.net/doc/manual.html#lineAtHeight), [`getTokenTypeAt`](https://codemirror.net/doc/manual.html#getTokenTypeAt).
* More precise cleanness-tracking using [`changeGeneration`](https://codemirror.net/doc/manual.html#changeGeneration) and [`isClean`](https://codemirror.net/doc/manual.html#isClean).
* Many extensions to [Emacs](https://codemirror.net/demo/emacs.html) mode (prefixes, more navigation units, and more).
* New events [`"keyHandled"`](https://codemirror.net/doc/manual.html#event_keyHandled) and [`"inputRead"`](https://codemirror.net/doc/manual.html#event_inputRead).
* Various improvements to [Ruby](https://codemirror.net/mode/ruby/index.html), [Smarty](https://codemirror.net/mode/smarty/index.html), [SQL](https://codemirror.net/mode/sql/index.html), and [Vim](https://codemirror.net/demo/vim.html) modes.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/3.13.0...3.14.0).
## 3.13.0 (2013-05-20)
* New modes: [COBOL](https://codemirror.net/mode/cobol/index.html) and [HAML](https://codemirror.net/mode/haml/index.html).
* New options: [`cursorScrollMargin`](https://codemirror.net/doc/manual.html#option_cursorScrollMargin) and [`coverGutterNextToScrollbar`](https://codemirror.net/doc/manual.html#option_coverGutterNextToScrollbar).
* New addon: [commenting](https://codemirror.net/doc/manual.html#addon_comment).
* More features added to the [Vim keymap](https://codemirror.net/demo/vim.html).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.12...3.13.0).
## 3.12.0 (2013-04-19)
* New mode: [GNU assembler](https://codemirror.net/mode/gas/index.html).
* New options: [`maxHighlightLength`](https://codemirror.net/doc/manual.html#option_maxHighlightLength) and [`historyEventDelay`](https://codemirror.net/doc/manual.html#option_historyEventDelay).
* Added [`addToHistory`](https://codemirror.net/doc/manual.html#mark_addToHistory) option for `markText`.
* Various fixes to JavaScript tokenization and indentation corner cases.
* Further improvements to the vim mode.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.11...v3.12).
## 3.11.0 (2013-03-20)
* **Removed code:** `collapserange`, `formatting`, and `simple-hint` addons. `plsql` and `mysql` modes (use [`sql`](https://codemirror.net/mode/sql/index.html) mode).
* **Moved code:** the range-finding functions for folding now have [their own files](https://codemirror.net/addon/fold/).
* **Changed interface:** the [`continuecomment`](https://codemirror.net/doc/manual.html#addon_continuecomment) addon now exposes an option, rather than a command.
* New modes: [SCSS](https://codemirror.net/mode/css/scss.html), [Tcl](https://codemirror.net/mode/tcl/index.html), [LiveScript](https://codemirror.net/mode/livescript/index.html), and [mIRC](https://codemirror.net/mode/mirc/index.html).
* New addons: [`placeholder`](https://codemirror.net/demo/placeholder.html), [HTML completion](https://codemirror.net/demo/html5complete.html).
* New methods: [`hasFocus`](https://codemirror.net/doc/manual.html#hasFocus), [`defaultCharWidth`](https://codemirror.net/doc/manual.html#defaultCharWidth).
* New events: [`beforeCursorEnter`](https://codemirror.net/doc/manual.html#event_beforeCursorEnter), [`renderLine`](https://codemirror.net/doc/manual.html#event_renderLine).
* Many improvements to the [`show-hint`](https://codemirror.net/doc/manual.html#addon_show-hint) completion dialog addon.
* Tweak behavior of by-word cursor motion.
* Further improvements to the [vim mode](https://codemirror.net/demo/vim.html).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.1...v3.11).
## 3.02.0 (2013-01-25)
Single-bugfix release. Fixes a problem that prevents CodeMirror instances from being garbage-collected after they become unused.
## 3.01.0 (2013-01-21)
* Move all add-ons into an organized directory structure under [`/addon`](https://codemirror.net/addon/). **You might have to adjust your paths.**
* New modes: [D](https://codemirror.net/mode/d/index.html), [Sass](https://codemirror.net/mode/sass/index.html), [APL](https://codemirror.net/mode/apl/index.html), [SQL](https://codemirror.net/mode/sql/index.html) (configurable), and [Asterisk](https://codemirror.net/mode/asterisk/index.html).
* Several bugfixes in right-to-left text support.
* Add [`rtlMoveVisually`](https://codemirror.net/doc/manual.html#option_rtlMoveVisually) option.
* Improvements to vim keymap.
* Add built-in (lightweight) [overlay mode](https://codemirror.net/doc/manual.html#addOverlay) support.
* Support `showIfHidden` option for [line widgets](https://codemirror.net/doc/manual.html#addLineWidget).
* Add simple [Python hinter](https://codemirror.net/doc/manual.html#addon_python-hint).
* Bring back the [`fixedGutter`](https://codemirror.net/doc/manual.html#option_fixedGutter) option.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.0...v3.01).
## 3.1.0 (2013-02-21)
* **Incompatible:** key handlers may now _return_, rather than _throw_ `CodeMirror.Pass` to signal they didn't handle the key.
* Make documents a [first-class construct](https://codemirror.net/doc/manual.html#api_doc), support split views and subviews.
* Add a [new module](https://codemirror.net/doc/manual.html#addon_show-hint) for showing completion hints. Deprecate `simple-hint.js`.
* Extend [htmlmixed mode](https://codemirror.net/mode/htmlmixed/index.html) to allow custom handling of script types.
* Support an `insertLeft` option to [`setBookmark`](https://codemirror.net/doc/manual.html#setBookmark).
* Add an [`eachLine`](https://codemirror.net/doc/manual.html#eachLine) method to iterate over a document.
* New addon modules: [selection marking](https://codemirror.net/demo/markselection.html), [linting](https://codemirror.net/demo/lint.html), and [automatic bracket closing](https://codemirror.net/demo/closebrackets.html).
* Add [`"beforeChange"`](https://codemirror.net/doc/manual.html#event_beforeChange) and [`"beforeSelectionChange"`](https://codemirror.net/doc/manual.html#event_beforeSelectionChange) events.
* Add [`"hide"`](https://codemirror.net/doc/manual.html#event_hide) and [`"unhide"`](https://codemirror.net/doc/manual.html#event_unhide) events to marked ranges.
* Fix [`coordsChar`](https://codemirror.net/doc/manual.html#coordsChar)'s interpretation of its argument to match the documentation.
* New modes: [Turtle](https://codemirror.net/mode/turtle/index.html) and [Q](https://codemirror.net/mode/q/index.html).
* Further improvements to the [vim mode](https://codemirror.net/demo/vim.html).
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.01...v3.1).
## 3.0.0 (2012-12-10)
**New major version**. Only partially backwards-compatible. See the [upgrading guide](https://codemirror.net/doc/upgrade_v3.html) for more information. Changes since release candidate 2:
* Rewritten VIM mode.
* Fix a few minor scrolling and sizing issues.
* Work around Safari segfault when dragging.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v3.0rc2...v3.0).
## 2.38.0 (2013-01-21)
Integrate some bugfixes, enhancements to the vim keymap, and new modes ([D](https://codemirror.net/mode/d/index.html), [Sass](https://codemirror.net/mode/sass/index.html), [APL](https://codemirror.net/mode/apl/index.html)) from the v3 branch.
## 2.37.0 (2012-12-20)
* New mode: [SQL](https://codemirror.net/mode/sql/index.html) (will replace [plsql](https://codemirror.net/mode/plsql/index.html) and [mysql](https://codemirror.net/mode/mysql/index.html) modes).
* Further work on the new VIM mode.
* Fix Cmd/Ctrl keys on recent Operas on OS X.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v2.36...v2.37).
## 2.36.0 (2012-11-20)
* New mode: [Z80 assembly](https://codemirror.net/mode/z80/index.html).
* New theme: [Twilight](https://codemirror.net/demo/theme.html#twilight).
* Add command-line compression helper.
* Make [`scrollIntoView`](https://codemirror.net/doc/manual.html#scrollIntoView) public.
* Add [`defaultTextHeight`](https://codemirror.net/doc/manual.html#defaultTextHeight) method.
* Various extensions to the vim keymap.
* Make [PHP mode](https://codemirror.net/mode/php/index.html) build on [mixed HTML mode](https://codemirror.net/mode/htmlmixed/index.html).
* Add [comment-continuing](https://codemirror.net/doc/manual.html#addon_continuecomment) add-on.
* Full [list of patches](https://codemirror.net/https://github.com/codemirror/CodeMirror/compare/v2.35...v2.36).
## 2.35.0 (2012-10-22)
* New (sub) mode: [TypeScript](https://codemirror.net/mode/javascript/typescript.html).
* Don't overwrite (insert key) when pasting.
* Fix several bugs in [`markText`](https://codemirror.net/doc/manual.html#markText)/undo interaction.
* Better indentation of JavaScript code without semicolons.
* Add [`defineInitHook`](https://codemirror.net/doc/manual.html#defineInitHook) function.
* Full [list of patches](https://github.com/codemirror/CodeMirror/compare/v2.34...v2.35).
## 2.34.0 (2012-09-19)
* New mode: [Common Lisp](https://codemirror.net/mode/commonlisp/index.html).
* Fix right-click select-all on most browsers.
* Change the way highlighting happens:
Saves memory and CPU cycles.
`compareStates` is no longer needed.
`onHighlightComplete` no longer works.
* Integrate mode (Markdown, XQuery, CSS, sTex) tests in central testsuite.
* Add a [`CodeMirror.version`](https://codemirror.net/doc/manual.html#version) property.
* More robust handling of nested modes in [formatting](https://codemirror.net/demo/formatting.html) and [closetag](https://codemirror.net/demo/closetag.html) plug-ins.
* Un/redo now preserves [marked text](https://codemirror.net/doc/manual.html#markText) and bookmarks.
* [Full list](https://github.com/codemirror/CodeMirror/compare/v2.33...v2.34) of patches.
## 2.33.0 (2012-08-23)
* New mode: [Sieve](https://codemirror.net/mode/sieve/index.html).
* New [`getViewPort`](https://codemirror.net/doc/manual.html#getViewport) and [`onViewportChange`](https://codemirror.net/doc/manual.html#option_onViewportChange) API.
* [Configurable](https://codemirror.net/doc/manual.html#option_cursorBlinkRate) cursor blink rate.
* Make binding a key to `false` disabling handling (again).
* Show non-printing characters as red dots.
* More tweaks to the scrolling model.
* Expanded testsuite. Basic linter added.
* Remove most uses of `innerHTML`. Remove `CodeMirror.htmlEscape`.
* [Full list](https://github.com/codemirror/CodeMirror/compare/v2.32...v2.33) of patches.
## 2.32.0 (2012-07-23)
Emergency fix for a bug where an editor with line wrapping on IE will break when there is _no_ scrollbar.
## 2.31.0 (2012-07-20)
* New modes: [OCaml](https://codemirror.net/mode/ocaml/index.html), [Haxe](https://codemirror.net/mode/haxe/index.html), and [VB.NET](https://codemirror.net/mode/vb/index.html).
* Several fixes to the new scrolling model.
* Add a [`setSize`](https://codemirror.net/doc/manual.html#setSize) method for programmatic resizing.
* Add [`getHistory`](https://codemirror.net/doc/manual.html#getHistory) and [`setHistory`](https://codemirror.net/doc/manual.html#setHistory) methods.
* Allow custom line separator string in [`getValue`](https://codemirror.net/doc/manual.html#getValue) and [`getRange`](https://codemirror.net/doc/manual.html#getRange).
* Support double- and triple-click drag, double-clicking whitespace.
* And more... [(all patches)](https://github.com/codemirror/CodeMirror/compare/v2.3...v2.31)
## 2.30.0 (2012-06-22)
* **New scrollbar implementation**. Should flicker less. Changes DOM structure of the editor.
* New theme: [vibrant-ink](https://codemirror.net/demo/theme.html#vibrant-ink).
* Many extensions to the VIM keymap (including text objects).
* Add [mode-multiplexing](https://codemirror.net/demo/multiplex.html) utility script.
* Fix bug where right-click paste works in read-only mode.
* Add a [`getScrollInfo`](https://codemirror.net/doc/manual.html#getScrollInfo) method.
* Lots of other [fixes](https://github.com/codemirror/CodeMirror/compare/v2.25...v2.3).
## 2.25.0 (2012-05-23)
* New mode: [Erlang](https://codemirror.net/mode/erlang/index.html).
* **Remove xmlpure mode** (use [xml.js](https://codemirror.net/mode/xml/index.html)).
* Fix line-wrapping in Opera.
* Fix X Windows middle-click paste in Chrome.
* Fix bug that broke pasting of huge documents.
* Fix backspace and tab key repeat in Opera.
## 2.24.0 (2012-04-23)
* **Drop support for Internet Explorer 6**.
* New modes: [Shell](https://codemirror.net/mode/shell/index.html), [Tiki wiki](https://codemirror.net/mode/tiki/index.html), [Pig Latin](https://codemirror.net/mode/pig/index.html).
* New themes: [Ambiance](https://codemirror.net/demo/theme.html#ambiance), [Blackboard](https://codemirror.net/demo/theme.html#blackboard).
* More control over drag/drop with [`dragDrop`](https://codemirror.net/doc/manual.html#option_dragDrop) and [`onDragEvent`](https://codemirror.net/doc/manual.html#option_onDragEvent) options.
* Make HTML mode a bit less pedantic.
* Add [`compoundChange`](https://codemirror.net/doc/manual.html#compoundChange) API method.
* Several fixes in undo history and line hiding.
* Remove (broken) support for `catchall` in key maps, add `nofallthrough` boolean field instead.
## 2.23.0 (2012-03-26)
* Change **default binding for tab**. Starting in 2.23, these bindings are default:
* Tab: Insert tab character
* Shift-tab: Reset line indentation to default
* Ctrl/Cmd-[: Reduce line indentation (old tab behaviour)
* Ctrl/Cmd-]: Increase line indentation (old shift-tab behaviour)
* New modes: [XQuery](https://codemirror.net/mode/xquery/index.html) and [VBScript](https://codemirror.net/mode/vbscript/index.html).
* Two new themes: [lesser-dark](https://codemirror.net/mode/less/index.html) and [xq-dark](https://codemirror.net/mode/xquery/index.html).
* Differentiate between background and text styles in [`setLineClass`](https://codemirror.net/doc/manual.html#setLineClass).
* Fix drag-and-drop in IE9+.
* Extend [`charCoords`](https://codemirror.net/doc/manual.html#charCoords) and [`cursorCoords`](https://codemirror.net/doc/manual.html#cursorCoords) with a `mode` argument.
* Add [`autofocus`](https://codemirror.net/doc/manual.html#option_autofocus) option.
* Add [`findMarksAt`](https://codemirror.net/doc/manual.html#findMarksAt) method.
## 2.22.0 (2012-02-27)
* Allow [key handlers](https://codemirror.net/doc/manual.html#keymaps) to pass up events, allow binding characters.
* Add [`autoClearEmptyLines`](https://codemirror.net/doc/manual.html#option_autoClearEmptyLines) option.
* Properly use tab stops when rendering tabs.
* Make PHP mode more robust.
* Support indentation blocks in [code folder](https://codemirror.net/doc/manual.html#addon_foldcode).
* Add a script for [highlighting instances of the selection](https://codemirror.net/doc/manual.html#addon_match-highlighter).
* New [.properties](https://codemirror.net/mode/properties/index.html) mode.
* Fix many bugs.
## 2.21.0 (2012-01-27)
* Added [LESS](https://codemirror.net/mode/less/index.html), [MySQL](https://codemirror.net/mode/mysql/index.html), [Go](https://codemirror.net/mode/go/index.html), and [Verilog](https://codemirror.net/mode/verilog/index.html) modes.
* Add [`smartIndent`](https://codemirror.net/doc/manual.html#option_smartIndent) option.
* Support a cursor in [`readOnly`](https://codemirror.net/doc/manual.html#option_readOnly)-mode.
* Support assigning multiple styles to a token.
* Use a new approach to drawing the selection.
* Add [`scrollTo`](https://codemirror.net/doc/manual.html#scrollTo) method.
* Allow undo/redo events to span non-adjacent lines.
* Lots and lots of bugfixes.
## 2.20.0 (2011-12-20)
* Slightly incompatible API changes. Read [this](https://codemirror.net/doc/upgrade_v2.2.html).
* New approach to [binding](https://codemirror.net/doc/manual.html#option_extraKeys) keys, support for [custom bindings](https://codemirror.net/doc/manual.html#option_keyMap).
* Support for overwrite (insert).
* [Custom-width](https://codemirror.net/doc/manual.html#option_tabSize) and [styleable](https://codemirror.net/demo/visibletabs.html) tabs.
* Moved more code into [add-on scripts](https://codemirror.net/doc/manual.html#addons).
* Support for sane vertical cursor movement in wrapped lines.
* More reliable handling of editing [marked text](https://codemirror.net/doc/manual.html#markText).
* Add minimal [emacs](https://codemirror.net/demo/emacs.html) and [vim](https://codemirror.net/demo/vim.html) bindings.
* Rename `coordsFromIndex` to [`posFromIndex`](https://codemirror.net/doc/manual.html#posFromIndex), add [`indexFromPos`](https://codemirror.net/doc/manual.html#indexFromPos) method.
## 2.18.0 (2011-11-21)
Fixes `TextMarker.clear`, which is broken in 2.17.
## 2.17.0 (2011-11-21)
* Add support for [line wrapping](https://codemirror.net/doc/manual.html#option_lineWrapping) and [code folding](https://codemirror.net/doc/manual.html#hideLine).
* Add [GitHub-style Markdown](https://codemirror.net/mode/gfm/index.html) mode.
* Add [Monokai](https://codemirror.net/theme/monokai.css) and [Rubyblue](https://codemirror.net/theme/rubyblue.css) themes.
* Add [`setBookmark`](https://codemirror.net/doc/manual.html#setBookmark) method.
* Move some of the demo code into reusable components under [`lib/util`](https://codemirror.net/addon/).
* Make screen-coord-finding code faster and more reliable.
* Fix drag-and-drop in Firefox.
* Improve support for IME.
* Speed up content rendering.
* Fix browser's built-in search in Webkit.
* Make double- and triple-click work in IE.
* Various fixes to modes.
## 2.16.0 (2011-10-27)
* Add [Perl](https://codemirror.net/mode/perl/index.html), [Rust](https://codemirror.net/mode/rust/index.html), [TiddlyWiki](https://codemirror.net/mode/tiddlywiki/index.html), and [Groovy](https://codemirror.net/mode/groovy/index.html) modes.
* Dragging text inside the editor now moves, rather than copies.
* Add a [`coordsFromIndex`](https://codemirror.net/doc/manual.html#coordsFromIndex) method.
* **API change**: `setValue` now no longer clears history. Use [`clearHistory`](https://codemirror.net/doc/manual.html#clearHistory) for that.
* **API change**: [`markText`](https://codemirror.net/doc/manual.html#markText) now returns an object with `clear` and `find` methods. Marked text is now more robust when edited.
* Fix editing code with tabs in Internet Explorer.
## 2.15.0 (2011-09-26)
Fix bug that snuck into 2.14: Clicking the character that currently has the cursor didn't re-focus the editor.
## 2.14.0 (2011-09-26)
* Add [Clojure](https://codemirror.net/mode/clojure/index.html), [Pascal](https://codemirror.net/mode/pascal/index.html), [NTriples](https://codemirror.net/mode/ntriples/index.html), [Jinja2](https://codemirror.net/mode/jinja2/index.html), and [Markdown](https://codemirror.net/mode/markdown/index.html) modes.
* Add [Cobalt](https://codemirror.net/theme/cobalt.css) and [Eclipse](https://codemirror.net/theme/eclipse.css) themes.
* Add a [`fixedGutter`](https://codemirror.net/doc/manual.html#option_fixedGutter) option.
* Fix bug with `setValue` breaking cursor movement.
* Make gutter updates much more efficient.
* Allow dragging of text out of the editor (on modern browsers).
## 2.13.0 (2011-08-23)
* Add [Ruby](https://codemirror.net/mode/ruby/index.html), [R](https://codemirror.net/mode/r/index.html), [CoffeeScript](https://codemirror.net/mode/coffeescript/index.html), and [Velocity](https://codemirror.net/mode/velocity/index.html) modes.
* Add [`getGutterElement`](https://codemirror.net/doc/manual.html#getGutterElement) to API.
* Several fixes to scrolling and positioning.
* Add [`smartHome`](https://codemirror.net/doc/manual.html#option_smartHome) option.
* Add an experimental [pure XML](https://codemirror.net/mode/xmlpure/index.html) mode.
## 2.12.0 (2011-07-25)
* Add a [SPARQL](https://codemirror.net/mode/sparql/index.html) mode.
* Fix bug with cursor jumping around in an unfocused editor in IE.
* Allow key and mouse events to bubble out of the editor. Ignore widget clicks.
* Solve cursor flakiness after undo/redo.
* Fix block-reindent ignoring the last few lines.
* Fix parsing of multi-line attrs in XML mode.
* Use `innerHTML` for HTML-escaping.
* Some fixes to indentation in C-like mode.
* Shrink horiz scrollbars when long lines removed.
* Fix width feedback loop bug that caused the width of an inner DIV to shrink.
## 2.11.0 (2011-07-04)
* Add a [Scheme mode](https://codemirror.net/mode/scheme/index.html).
* Add a `replace` method to search cursors, for cursor-preserving replacements.
* Make the [C-like mode](https://codemirror.net/mode/clike/index.html) mode more customizable.
* Update XML mode to spot mismatched tags.
* Add `getStateAfter` API and `compareState` mode API methods for finer-grained mode magic.
* Add a `getScrollerElement` API method to manipulate the scrolling DIV.
* Fix drag-and-drop for Firefox.
* Add a C# configuration for the [C-like mode](https://codemirror.net/mode/clike/index.html).
* Add [full-screen editing](https://codemirror.net/demo/fullscreen.html) and [mode-changing](https://codemirror.net/demo/changemode.html) demos.
## 2.10.0 (2011-06-07)
Add a [theme](https://codemirror.net/doc/manual.html#option_theme) system ([demo](https://codemirror.net/demo/theme.html)). Note that this is not backwards-compatible—you'll have to update your styles and modes!
## 2.2.0 (2011-06-07)
* Add a [Lua mode](https://codemirror.net/mode/lua/index.html).
* Fix reverse-searching for a regexp.
* Empty lines can no longer break highlighting.
* Rework scrolling model (the outer wrapper no longer does the scrolling).
* Solve horizontal jittering on long lines.
* Add [runmode.js](https://codemirror.net/demo/runmode.html).
* Immediately re-highlight text when typing.
* Fix problem with 'sticking' horizontal scrollbar.
## 2.1.0 (2011-05-26)
* Add a [Smalltalk mode](https://codemirror.net/mode/smalltalk/index.html).
* Add a [reStructuredText mode](https://codemirror.net/mode/rst/index.html).
* Add a [Python mode](https://codemirror.net/mode/python/index.html).
* Add a [PL/SQL mode](https://codemirror.net/mode/plsql/index.html).
* `coordsChar` now works
* Fix a problem where `onCursorActivity` interfered with `onChange`.
* Fix a number of scrolling and mouse-click-position glitches.
* Pass information about the changed lines to `onChange`.
* Support cmd-up/down on OS X.
* Add triple-click line selection.
* Don't handle shift when changing the selection through the API.
* Support `"nocursor"` mode for `readOnly` option.
* Add an `onHighlightComplete` option.
* Fix the context menu for Firefox.
## 2.0.0 (2011-03-28)
CodeMirror 2 is a complete rewrite that's faster, smaller, simpler to use, and less dependent on browser quirks. See [this](https://codemirror.net/doc/internals.html) and [this](http://groups.google.com/group/codemirror/browse_thread/thread/5a8e894024a9f580) for more information.
# How to contribute
- [Getting help](#getting-help)
- [Submitting bug reports](#submitting-bug-reports)
- [Contributing code](#contributing-code)
## Getting help
Community discussion, questions, and informal bug reporting is done on the
[discuss.CodeMirror forum](http://discuss.codemirror.net).
## Submitting bug reports
The preferred way to report bugs is to use the
[GitHub issue tracker](http://github.com/codemirror/CodeMirror/issues). Before
reporting a bug, read these pointers.
**Note:** The issue tracker is for *bugs*, not requests for help. Questions
should be asked on the
[discuss.CodeMirror forum](http://discuss.codemirror.net) instead.
### Reporting bugs effectively
- CodeMirror is maintained by volunteers. They don't owe you anything, so be
polite. Reports with an indignant or belligerent tone tend to be moved to the
bottom of the pile.
- Include information about **the browser in which the problem occurred**. Even
if you tested several browsers, and the problem occurred in all of them,
mention this fact in the bug report. Also include browser version numbers and
the operating system that you're on.
- Mention which release of CodeMirror you're using. Preferably, try also with
the current development snapshot, to ensure the problem has not already been
fixed.
- Mention very precisely what went wrong. "X is broken" is not a good bug
report. What did you expect to happen? What happened instead? Describe the
exact steps a maintainer has to take to make the problem occur. We can not
fix something that we can not observe.
- If the problem can not be reproduced in any of the demos included in the
CodeMirror distribution, please provide an HTML document that demonstrates
the problem. The best way to do this is to go to
[jsbin.com](http://jsbin.com/ihunin/edit), enter it there, press save, and
include the resulting link in your bug report.
## Contributing code
Note that we are not accepting any new addons or modes into the main
distribution. If you've written such a module, please distribute it as
a separate NPM package.
- Make sure you have a [GitHub Account](https://github.com/signup/free)
- Fork [CodeMirror](https://github.com/codemirror/CodeMirror/)
([how to fork a repo](https://help.github.com/articles/fork-a-repo))
- Make your changes
- If your changes are easy to test or likely to regress, add tests.
Tests for the core go into `test/test.js`, some modes have their own
test suite under `mode/XXX/test.js`. Feel free to add new test
suites to modes that don't have one yet (be sure to link the new
tests into `test/index.html`).
- Follow the general code style of the rest of the project (see
below). Run `bin/lint` to verify that the linter is happy.
- Make sure all tests pass. Visit `test/index.html` in your browser to
run them.
- Submit a pull request
([how to create a pull request](https://help.github.com/articles/fork-a-repo)).
Don't put more than one feature/fix in a single pull request.
By contributing code to CodeMirror you
- agree to license the contributed code under CodeMirror's [MIT
license](https://codemirror.net/LICENSE).
- confirm that you have the right to contribute and license the code
in question. (Either you hold all rights on the code, or the rights
holder has explicitly granted the right to use it like this,
through a compatible open source license or through a direct
agreement with you.)
### Coding standards
- 2 spaces per indentation level, no tabs.
- Note that the linter (`bin/lint`) which is run after each commit
complains about unused variables and functions. Prefix their names
with an underscore to muffle it.
- CodeMirror does *not* follow JSHint or JSLint prescribed style.
Patches that try to 'fix' code to pass one of these linters will be
unceremoniously discarded.
MIT License
Copyright (C) 2017 by Marijn Haverbeke <marijnh@gmail.com> and others
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# CodeMirror
[![Build Status](https://github.com/codemirror/codemirror/workflows/main/badge.svg)](https://github.com/codemirror/codemirror/actions)
[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror)
CodeMirror is a versatile text editor implemented in JavaScript for
the browser. It is specialized for editing code, and comes with over
100 language modes and various addons that implement more advanced
editing functionality. Every language comes with fully-featured code
and syntax highlighting to help with reading and editing complex code.
A rich programming API and a CSS theming system are available for
customizing CodeMirror to fit your application, and extending it with
new functionality.
You can find more information (and the
[manual](https://codemirror.net/doc/manual.html)) on the [project
page](https://codemirror.net). For questions and discussion, use the
[discussion forum](https://discuss.codemirror.net/).
See
[CONTRIBUTING.md](https://github.com/codemirror/CodeMirror/blob/master/CONTRIBUTING.md)
for contributing guidelines.
The CodeMirror community aims to be welcoming to everybody. We use the
[Contributor Covenant
(1.1)](http://contributor-covenant.org/version/1/1/0/) as our code of
conduct.
### Installation
Either get the [zip file](https://codemirror.net/codemirror.zip) with
the latest version, or make sure you have [Node](https://nodejs.org/)
installed and run:
npm install codemirror
**NOTE**: This is the source repository for the library, and not the
distribution channel. Cloning it is not the recommended way to install
the library, and will in fact not work unless you also run the build
step.
### Quickstart
To build the project, make sure you have Node.js installed (at least version 6)
and then `npm install`. To run, just open `index.html` in your
browser (you don't need to run a webserver). Run the tests with `npm test`.
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var noOptions = {};
var nonWS = /[^\s\u00a0]/;
var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos;
function firstNonWS(str) {
var found = str.search(nonWS);
return found == -1 ? 0 : found;
}
CodeMirror.commands.toggleComment = function(cm) {
cm.toggleComment();
};
CodeMirror.defineExtension("toggleComment", function(options) {
if (!options) options = noOptions;
var cm = this;
var minLine = Infinity, ranges = this.listSelections(), mode = null;
for (var i = ranges.length - 1; i >= 0; i--) {
var from = ranges[i].from(), to = ranges[i].to();
if (from.line >= minLine) continue;
if (to.line >= minLine) to = Pos(minLine, 0);
minLine = from.line;
if (mode == null) {
if (cm.uncomment(from, to, options)) mode = "un";
else { cm.lineComment(from, to, options); mode = "line"; }
} else if (mode == "un") {
cm.uncomment(from, to, options);
} else {
cm.lineComment(from, to, options);
}
}
});
// Rough heuristic to try and detect lines that are part of multi-line string
function probablyInsideString(cm, pos, line) {
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line)
}
function getMode(cm, pos) {
var mode = cm.getMode()
return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos)
}
CodeMirror.defineExtension("lineComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = getMode(self, from);
var firstLine = self.getLine(from.line);
if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
var commentString = options.lineComment || mode.lineComment;
if (!commentString) {
if (options.blockCommentStart || mode.blockCommentStart) {
options.fullLines = true;
self.blockComment(from, to, options);
}
return;
}
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
var pad = options.padding == null ? " " : options.padding;
var blankLines = options.commentBlankLines || from.line == to.line;
self.operation(function() {
if (options.indent) {
var baseString = null;
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i);
var whitespace = line.slice(0, firstNonWS(line));
if (baseString == null || baseString.length > whitespace.length) {
baseString = whitespace;
}
}
for (var i = from.line; i < end; ++i) {
var line = self.getLine(i), cut = baseString.length;
if (!blankLines && !nonWS.test(line)) continue;
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
}
} else {
for (var i = from.line; i < end; ++i) {
if (blankLines || nonWS.test(self.getLine(i)))
self.replaceRange(commentString + pad, Pos(i, 0));
}
}
});
});
CodeMirror.defineExtension("blockComment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = getMode(self, from);
var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) {
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
self.lineComment(from, to, options);
return;
}
if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
var end = Math.min(to.line, self.lastLine());
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
var pad = options.padding == null ? " " : options.padding;
if (from.line > end) return;
self.operation(function() {
if (options.fullLines != false) {
var lastLineHasText = nonWS.test(self.getLine(end));
self.replaceRange(pad + endString, Pos(end));
self.replaceRange(startString + pad, Pos(from.line, 0));
var lead = options.blockCommentLead || mode.blockCommentLead;
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
if (i != end || lastLineHasText)
self.replaceRange(lead + pad, Pos(i, 0));
} else {
var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected()
self.replaceRange(endString, to);
if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to)
self.replaceRange(startString, from);
}
});
});
CodeMirror.defineExtension("uncomment", function(from, to, options) {
if (!options) options = noOptions;
var self = this, mode = getMode(self, from);
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
// Try finding line comments
var lineString = options.lineComment || mode.lineComment, lines = [];
var pad = options.padding == null ? " " : options.padding, didSomething;
lineComment: {
if (!lineString) break lineComment;
for (var i = start; i <= end; ++i) {
var line = self.getLine(i);
var found = line.indexOf(lineString);
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
if (found == -1 && nonWS.test(line)) break lineComment;
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
lines.push(line);
}
self.operation(function() {
for (var i = start; i <= end; ++i) {
var line = lines[i - start];
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
if (pos < 0) continue;
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
didSomething = true;
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
}
});
if (didSomething) return true;
}
// Try block comments
var startString = options.blockCommentStart || mode.blockCommentStart;
var endString = options.blockCommentEnd || mode.blockCommentEnd;
if (!startString || !endString) return false;
var lead = options.blockCommentLead || mode.blockCommentLead;
var startLine = self.getLine(start), open = startLine.indexOf(startString)
if (open == -1) return false
var endLine = end == start ? startLine : self.getLine(end)
var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1)
if (close == -1 ||
!/comment/.test(self.getTokenTypeAt(insideStart)) ||
!/comment/.test(self.getTokenTypeAt(insideEnd)) ||
self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1)
return false;
// Avoid killing block comments completely outside the selection.
// Positions of the last startString before the start of the selection, and the first endString after it.
var lastStart = startLine.lastIndexOf(startString, from.ch);
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
// Positions of the first endString after the end of the selection, and the last startString before it.
firstEnd = endLine.indexOf(endString, to.ch);
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
self.operation(function() {
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
Pos(end, close + endString.length));
var openEnd = open + startString.length;
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
if (lead) for (var i = start + 1; i <= end; ++i) {
var line = self.getLine(i), found = line.indexOf(lead);
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
var foundEnd = found + lead.length;
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
}
});
return true;
});
});