1 // ==========================================================================
  2 // Project:   SproutCore Costello - Property Observing Library
  3 // Copyright: ©2006-2011 Strobe Inc. and contributors.
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 /**
  9   @class
 10 
 11   A simple object representing the selection inside a text field.  Each
 12   object is frozen and contains exactly three properties:
 13 
 14     *  start
 15     *  end
 16     *  length
 17 
 18   Important note:  In Internet Explorer, newlines in textarea elements are
 19   considered two characters.  SproutCore does not currently try to hide this from you.
 20 
 21   @extends SC.Object
 22   @extends SC.Copyable
 23   @extends SC.Freezable
 24   @since SproutCore 1.0
 25 */
 26 
 27 SC.TextSelection = SC.Object.extend(SC.Copyable, SC.Freezable,
 28 /** @scope SC.TextSelection.prototype */ {
 29 
 30   /**
 31     The number of characters appearing to the left of the beginning of the
 32     selection, starting at 0.
 33 
 34     @type {Number}
 35   */
 36   start: -1,
 37 
 38   /**
 39     The number of characters appearing to the left of the end of the
 40     selection.
 41 
 42     This will have the same value as 'start' if there is no selection and
 43     instead there is only a caret.
 44 
 45     @type {Number}
 46   */
 47   end: -1,
 48 
 49   /**
 50     The direction of the selection. Currently only supported on Chrome,
 51     Firefox, and Safari >= 6.
 52 
 53     Possible values are
 54       * 'none'
 55       * 'forward'
 56       * 'backward'
 57 
 58     @type {String}
 59     @default 'none'
 60   */
 61   direction: 'none',
 62 
 63   /**
 64     The length of the selection.  This is equivalent to (end - start) and
 65     exists mainly as a convenience.
 66 
 67     @type Number
 68   */
 69   length: function () {
 70     var start = this.get('start');
 71     var end   = this.get('end');
 72     if (start === -1 || end === -1) {
 73       return -1;
 74     } else {
 75       return end - start;
 76     }
 77   }.property('start', 'end').cacheable(),
 78 
 79   // ..........................................................
 80   // INTERNAL SUPPORT
 81   //
 82 
 83   init: function () {
 84     sc_super();
 85     this.freeze();
 86   },
 87 
 88   copy: function () {
 89     return SC.TextSelection.create({
 90       start: this.get('start'),
 91       end:   this.get('end'),
 92       direction: this.get('direction')
 93     });
 94   },
 95 
 96   toString: function () {
 97     var length = this.get('length'),
 98         start = this.get('start'),
 99         end = this.get('end'),
100         direction = this.get('direction');
101 
102     if (length  &&  length > 0) {
103       if (length === 1) {
104         return "[%@ character selected: {%@, %@}; direction: %@]".fmt(length, start, end, direction);
105       }
106       else {
107         return "[%@ characters selected: {%@, %@}; direction: %@]".fmt(length, start, end, direction);
108       }
109     }
110     else {
111       return "[no text selected; caret at %@]".fmt(start);
112     }
113   }
114 });
115