1 define(function(require) {
5 var $ = require('libs/jquery'),
6 _ = require('libs/underscore');
9 var Fragment = function(document) {
10 this.document = document;
12 $.extend(Fragment.prototype, {
19 var NodeFragment = function(document, params) {
20 Fragment.call(this, document);
21 this.node = params.node;
22 this.nodePath = this.isValid() ? params.node.getPath() : null;
24 NodeFragment.prototype = Object.create(Fragment.prototype);
25 $.extend(NodeFragment.prototype, {
27 return this.document.containsNode(this.node);
29 restoreFromPaths: function() {
31 this.node = this.document.getNodeByPath(this.nodePath);
37 var CaretFragment = function(document, params) {
38 this.offset = params.offset;
39 NodeFragment.call(this, document, params);
42 CaretFragment.prototype = Object.create(NodeFragment.prototype);
43 $.extend(CaretFragment.prototype, {
46 return NodeFragment.prototype.isValid.call(this) &&
47 this.node.nodeType === Node.TEXT_NODE &&
48 _.isNumber(this.offset);
54 var RangeFragment = function(document, params) {
55 Fragment.call(this, document);
57 if(params.node1.sameNode(params.node2)) {
58 this.startNode = this.endNode = params.node1;
60 /*jshint bitwise: false*/
62 var node1First = params.node1.nativeNode.compareDocumentPosition(params.node2.nativeNode) & Node.DOCUMENT_POSITION_FOLLOWING;
63 (node1First ? ['start', 'end'] : ['end','start']).forEach(function(prefix, idx) {
64 this[prefix + 'Node'] = params['node'+(idx+1)];
67 this.startNodePath = this.startNode.getPath();
68 this.endNodePath = this.endNode.getPath();
70 RangeFragment.prototype = Object.create(Fragment.prototype);
71 $.extend(RangeFragment.prototype, {
73 return this.document.containsNode(this.startNode) && this.document.containsNode(this.endNode);
75 restoreFromPaths: function() {
76 this.startNode = this.document.getNodeByPath(this.startNodePath);
77 this.endNode = this.document.getNodeByPath(this.endNodePath);
79 hasSiblingBoundaries: function() {
80 return this.isValid() && this.startNode.isSiblingOf(this.endNode);
82 hasSameBoundaries: function() {
83 return this.isValid() && this.startNode.sameNode(this.endNode);
85 boundariesSiblingParents: function() {
86 return this.startNode.document.getSiblingParents({
87 node1: this.startNode,
91 getCommonParent: function() {
92 var siblingParents = this.boundariesSiblingParents();
94 return siblingParents.node1.parent();
99 var TextRangeFragment = function(document, params) {
102 RangeFragment.call(this, document, params);
104 if(this.startNode.sameNode(this.endNode)) {
105 this.startOffset = Math.min(params.offset1, params.offset2);
106 this.endOffset = Math.max(params.offset1, params.offset2);
108 orderChanged = !params.node1.sameNode(this.startNode);
109 this.startOffset = orderChanged ? params.offset2 : params.offset1;
110 this.endOffset = orderChanged ? params.offset1 : params.offset2;
113 TextRangeFragment.prototype = Object.create(RangeFragment.prototype);
114 $.extend(TextRangeFragment.prototype, {
115 isValid: function() {
116 return RangeFragment.prototype.isValid.call(this) &&
117 _.isNumber(this.startOffset) &&
118 _.isNumber(this.endOffset);
122 var FragmentTypes = {
124 NodeFragment: NodeFragment,
125 CaretFragment: CaretFragment,
126 RangeFragment: RangeFragment,
127 TextRangeFragment: TextRangeFragment
129 _.values(FragmentTypes).forEach(function(Type) {
130 $.extend(Type.prototype, FragmentTypes);
133 return FragmentTypes;