Path: blob/master/webroot/rsrc/js/core/TextAreaUtils.js
12241 views
/**1* @requires javelin-install2* javelin-dom3* javelin-vector4* @provides phabricator-textareautils5* @javelin6*/78JX.install('TextAreaUtils', {9statics : {10getSelectionRange : function(area) {11var v = area.value;1213// NOTE: This works well in Safari, Firefox and Chrome. We'll probably get14// less-good behavior on IE.1516var s = v.length;17var e = v.length;1819if ('selectionStart' in area) {20s = area.selectionStart;21e = area.selectionEnd;22}2324return {start: s, end: e};25},2627getSelectionText : function(area) {28var v = area.value;29var r = JX.TextAreaUtils.getSelectionRange(area);30return v.substring(r.start, r.end);31},3233setSelectionRange : function(area, start, end) {34if ('setSelectionRange' in area) {3536// Chrome scrolls the textarea to the bottom as a side effect of37// calling focus(), so save the scroll position, focus, then restore38// the scroll position.39var scroll_top = area.scrollTop;40area.focus();41area.scrollTop = scroll_top;4243area.setSelectionRange(start, end);44}45},4647setSelectionText : function(area, text, select) {48var v = area.value;49var r = JX.TextAreaUtils.getSelectionRange(area);5051v = v.substring(0, r.start) + text + v.substring(r.end, v.length);52area.value = v;5354var start = r.start;55var end = r.start + text.length;5657if (!select) {58start = end;59}6061JX.TextAreaUtils.setSelectionRange(area, start, end);62},636465/**66* Insert a reference to a given uploaded file into a textarea.67*/68insertFileReference: function(area, file) {69var ref = '{F' + file.getID() + '}';7071// If we're inserting immediately after a "}" (usually, another file72// reference), put some newlines before our token so that multiple file73// uploads get laid out more nicely.74var range = JX.TextAreaUtils.getSelectionRange(area);75var before = area.value.substring(0, range.start);76if (before.match(/\}$/)) {77ref = '\n\n' + ref;78}7980JX.TextAreaUtils.setSelectionText(area, ref, false);81},828384/**85* Get the document pixel positions of the beginning and end of a character86* range in a textarea.87*/88getPixelDimensions: function(area, start, end) {89var v = area.value;9091// We're using zero-width spaces to make sure the spans get some92// height even if there's no text in the metrics tag.9394var head = v.substring(0, start);95var before = JX.$N('span', {}, '\u200b');96var body = v.substring(start, end);97var after = JX.$N('span', {}, '\u200b');9899// Create a similar shadow element which we can measure.100var metrics = JX.$N(101'var',102{103className: area.className,104},105[head, before, body, after]);106107// If the textarea has a scrollbar, force a scrollbar on the shadow108// element too.109if (area.scrollHeight > area.clientHeight) {110metrics.style.overflowY = 'scroll';111}112113area.parentNode.appendChild(metrics);114115// Adjust the positions we read out of the document to account for the116// current scroll position of the textarea.117var metrics_pos = JX.Vector.getPos(metrics);118metrics_pos.x += area.scrollLeft;119metrics_pos.y += area.scrollTop;120121var area_pos = JX.Vector.getPos(area);122var before_pos = JX.Vector.getPos(before);123var after_pos = JX.Vector.getPos(after);124125JX.DOM.remove(metrics);126127return {128start: {129x: area_pos.x + (before_pos.x - metrics_pos.x),130y: area_pos.y + (before_pos.y - metrics_pos.y)131},132end: {133x: area_pos.x + (after_pos.x - metrics_pos.x),134y: area_pos.y + (after_pos.y - metrics_pos.y)135}136};137}138139}140});141142143