- Timestamp:
- 02/13/05 07:58:08 (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/htmlarea.js
r1 r9 143 143 HTMLArea.RE_doctype = /(<!doctype((.|\n)*?)>)\n?/i; 144 144 HTMLArea.RE_head = /<head>((.|\n)*?)<\/head>/i; 145 HTMLArea.RE_body = /<body >((.|\n)*?)<\/body>/i;145 HTMLArea.RE_body = /<body[^>]*>((.|\n)*?)<\/body>/i; 146 146 HTMLArea.RE_Specials = /([\/\^$*+?.()|{}[\]])/g; 147 HTMLArea.RE_email = /[a-z0-9_]{3,}@[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,})+/i; 148 HTMLArea.RE_url = /(https?:\/\/)?(([a-z0-9_]+:[a-z0-9_]+@)?[a-z0-9_-]{2,}(\.[a-z0-9_-]{2,}){2,}(:[0-9]+)?(\/\S+)*)/i; 147 149 148 150 HTMLArea.Config = function () { … … 159 161 // If false, then passes ^V through to browser editor widget 160 162 this.htmlareaPaste = false; 163 164 this.mozParaHandler = 'best'; // set to 'built-in', 'dirty' or 'best' 165 // built-in: will (may) use 'br' instead of 'p' tags 166 // dirty : will use p and work good enough for the majority of cases, 167 // best : works the best, but it's about 12kb worth of javascript 168 // and will probably be slower than 'dirty'. This is the "EnterParagraphs" 169 // plugin from "hipikat", rolled in to be part of the core code 161 170 162 171 // maximum size of the undo queue … … 785 794 }); 786 795 787 var i_contain = null; 788 if(HTMLArea.is_ie && ((!document.compatMode) || (document.compatMode && document.compatMode == "BackCompat"))) 789 { 790 i_contain = document.createElement('span'); 791 } 792 else 793 { 794 i_contain = document.createElement('div'); 795 i_contain.style.position = 'relative'; 796 } 797 798 i_contain.style.overflow = 'hidden'; 799 i_contain.style.width = "18px"; 800 i_contain.style.height = "18px"; 801 802 var img = document.createElement("img"); 803 if(typeof btn[1] == 'string') 804 { 805 img.src = btn[1]; 806 img.style.width = "18px"; 807 img.style.height = "18px"; 808 } 809 else 810 { 811 img.src = btn[1][0]; 812 img.style.position = 'relative'; 813 img.style.top = btn[1][2] ? ('-' + (18 * (btn[1][2] + 1)) + 'px') : '-18px'; 814 img.style.left = btn[1][1] ? ('-' + (18 * (btn[1][1] + 1)) + 'px') : '-18px'; 815 } 816 i_contain.appendChild(img); 796 var i_contain = HTMLArea.makeBtnImg(btn[1]); 797 var img = i_contain.firstChild; 817 798 el.appendChild(i_contain); 818 799 … … 877 858 this._htmlArea.appendChild(toolbar); 878 859 }; 860 861 use_clone_img = false; 862 HTMLArea.makeBtnImg = function(imgDef, doc) 863 { 864 if(!doc) doc = document; 865 866 if(!doc._htmlareaImgCache) 867 { 868 doc._htmlareaImgCache = { }; 869 } 870 871 var i_contain = null; 872 if(HTMLArea.is_ie && ((!doc.compatMode) || (doc.compatMode && doc.compatMode == "BackCompat"))) 873 { 874 i_contain = doc.createElement('span'); 875 } 876 else 877 { 878 i_contain = doc.createElement('div'); 879 i_contain.style.position = 'relative'; 880 } 881 882 i_contain.style.overflow = 'hidden'; 883 i_contain.style.width = "18px"; 884 i_contain.style.height = "18px"; 885 886 887 var img = null; 888 if(typeof imgDef == 'string') 889 { 890 if(doc._htmlareaImgCache[imgDef]) 891 { 892 img = doc._htmlareaImgCache[imgDef].cloneNode(); 893 } 894 else 895 { 896 img = doc.createElement("img"); 897 img.src = imgDef; 898 img.style.width = "18px"; 899 img.style.height = "18px"; 900 if(use_clone_img) 901 doc._htmlareaImgCache[imgDef] = img.cloneNode(); 902 } 903 } 904 else 905 { 906 if(doc._htmlareaImgCache[imgDef[0]]) 907 { 908 img = doc._htmlareaImgCache[imgDef[0]].cloneNode(); 909 } 910 else 911 { 912 img = doc.createElement("img"); 913 img.src = imgDef[0]; 914 img.style.position = 'relative'; 915 if(use_clone_img) 916 doc._htmlareaImgCache[imgDef[0]] = img.cloneNode(); 917 } 918 img.style.top = imgDef[2] ? ('-' + (18 * (imgDef[2] + 1)) + 'px') : '-18px'; 919 img.style.left = imgDef[1] ? ('-' + (18 * (imgDef[1] + 1)) + 'px') : '-18px'; 920 } 921 i_contain.appendChild(img); 922 return i_contain; 923 } 879 924 880 925 HTMLArea.prototype._createStatusBar = function() { … … 901 946 var editor = this; // we'll need "this" in some nested functions 902 947 948 // If this is gecko, set up the paragraph handling now 949 if(HTMLArea.is_gecko) 950 { 951 switch(editor.config.mozParaHandler) 952 { 953 case 'best': 954 { 955 if(typeof EnterParagraphs == 'undefined') 956 { 957 EnterParagraphs = 'null'; 958 HTMLArea._loadback 959 (_editor_url + 'plugins/EnterParagraphs/enter-paragraphs.js', function() { editor.registerPlugin('EnterParagraphs'); editor.generate(); } ); 960 return false; 961 } 962 } 963 break; 964 965 case 'dirty' : 966 case 'built-in': 967 default : 968 { 969 // See _editorEvent 970 } 971 break; 972 } 973 } 974 903 975 // get the textarea 904 976 var textarea = this._textArea; … … 1199 1271 HTMLArea.prototype.removePanel = function(panel) 1200 1272 { 1201 panel.side.div.removeChild(panel);1273 this._panels[panel.side].div.removeChild(panel); 1202 1274 var clean = [ ]; 1203 for(var i = 0; i < panel.side.panels.length; i++)1204 { 1205 if( panel.side.panels[i] != panel)1206 { 1207 clean.push( panel.side.panels[i]);1208 } 1209 } 1210 panel.side.panels = clean;1211 this.notifyOf('panel_change', {'action':' add','panel':panel});1275 for(var i = 0; i < this._panels[panel.side].panels.length; i++) 1276 { 1277 if(this._panels[panel.side].panels[i] != panel) 1278 { 1279 clean.push(this._panels[panel.side].panels[i]); 1280 } 1281 } 1282 this._panels[panel.side].panels = clean; 1283 this.notifyOf('panel_change', {'action':'remove','panel':panel}); 1212 1284 } 1213 1285 1214 1286 HTMLArea.prototype.hidePanel = function(panel) 1287 { 1288 if(panel) 1215 1289 { 1216 1290 panel.style.display = 'none'; 1217 1291 this.notifyOf('panel_change', {'action':'hide','panel':panel}); 1218 1292 } 1293 } 1219 1294 1220 1295 HTMLArea.prototype.showPanel = function(panel) 1296 { 1297 if(panel) 1221 1298 { 1222 1299 panel.style.display = ''; 1223 1300 this.notifyOf('panel_change', {'action':'show','panel':panel}); 1301 } 1224 1302 } 1225 1303 … … 1848 1926 return false; 1849 1927 } 1850 1928 } 1929 1930 if(!Array.prototype.indexOf) 1931 { 1932 Array.prototype.indexOf = function(needle) 1933 { 1934 var haystack = this; 1935 for(var i = 0; i < haystack.length; i++) 1936 { 1937 if(needle == haystack[i]) return i; 1938 } 1939 1940 return null; 1941 } 1851 1942 } 1852 1943 … … 1948 2039 continue; 1949 2040 } 1950 switch (cmd) { 2041 switch (cmd) 2042 { 1951 2043 case "fontname": 1952 2044 case "fontsize": 2045 { 1953 2046 if (!text) try { 1954 2047 var value = ("" + doc.queryCommandValue(cmd)).toLowerCase(); … … 1957 2050 break; 1958 2051 } 2052 1959 2053 // HACK -- retrieve the config option for this 1960 2054 // combo box. We rely on the fact that the … … 1963 2057 var options = this.config[cmd]; 1964 2058 var k = 0; 1965 for (var j in options) { 2059 for (var j in options) 2060 { 1966 2061 // FIXME: the following line is scary. 1967 if ((j.toLowerCase() == value) ||1968 (options[j].substr(0, value.length).toLowerCase() == value)){2062 if ((j.toLowerCase() == value) || (options[j].substr(0, value.length).toLowerCase() == value)) 2063 { 1969 2064 btn.element.selectedIndex = k; 1970 2065 throw "ok"; … … 1974 2069 btn.element.selectedIndex = 0; 1975 2070 } catch(e) {}; 2071 } 2072 break; 1976 2073 1977 2074 // It's better to search for the format block by tag name from the … … 1980 2077 // to call your heading blocks 'header 1'. Stupid MS. 1981 2078 case "formatblock" : 2079 { 1982 2080 var blocks = [ ]; 1983 2081 for(var i in this.config['formatblock']) … … 2001 2099 btn.element.selectedIndex = 0; 2002 2100 } 2101 } 2003 2102 break; 2004 2103 2005 break;2006 2104 case "textindicator": 2007 2105 if (!text) { … … 2804 2902 // this object will be passed to the newly opened window 2805 2903 HTMLArea._object = this; 2904 var win; 2806 2905 if (HTMLArea.is_ie) { 2807 2906 //if (confirm(HTMLArea.I18N.msg["IE-sucks-full-screen"])) 2808 2907 { 2809 window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",2908 win = window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", 2810 2909 "toolbar=no,location=no,directories=no,status=no,menubar=no," + 2811 2910 "scrollbars=no,resizable=yes,width=640,height=480"); 2812 2911 } 2813 2912 } else { 2814 window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",2913 win = window.open(this.popupURL("fullscreen.html"), "ha_fullscreen", 2815 2914 "toolbar=no,menubar=no,personalbar=no,width=640,height=480," + 2816 2915 "scrollbars=no,resizable=yes"); 2817 2916 } 2917 win.focus() 2818 2918 break; 2819 2919 case "undo": … … 2878 2978 var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (!HTMLArea.is_ie && ev.type == "keypress"); 2879 2979 2980 if(HTMLArea.is_gecko && keyEvent && ev.ctrlKey && this._unLink && this._unlinkOnUndo) 2981 { 2982 if(String.fromCharCode(ev.charCode).toLowerCase() == 'z') 2983 { 2984 HTMLArea._stopEvent(ev); 2985 this._unLink(); 2986 editor.updateToolbar(); 2987 return; 2988 } 2989 } 2990 2880 2991 if (keyEvent) 2881 for (var i in editor.plugins) { 2992 { 2993 for (var i in editor.plugins) 2994 { 2882 2995 var plugin = editor.plugins[i].instance; 2883 2996 if (typeof plugin.onKeyPress == "function") … … 2885 2998 return false; 2886 2999 } 2887 if (keyEvent && ev.ctrlKey && !ev.altKey) { 3000 } 3001 3002 if (keyEvent && ev.ctrlKey && !ev.altKey) 3003 { 2888 3004 var sel = null; 2889 3005 var range = null; … … 2940 3056 } 2941 3057 } 2942 else if (keyEvent) { 3058 else if (keyEvent) 3059 { 3060 3061 // IE's textRange and selection object is woefully inadequate, 3062 // which means this fancy stuff is gecko only sorry :-| 3063 // Die Bill, Die. (IE supports it somewhat nativly though) 3064 if(HTMLArea.is_gecko) 3065 { 3066 var s = editor._getSelection() 3067 var autoWrap = function (textNode, tag) 3068 { 3069 var rightText = textNode.nextSibling; 3070 if(typeof tag == 'string') tag = editor._doc.createElement(tag); 3071 var a = textNode.parentNode.insertBefore(tag, rightText); 3072 textNode.parentNode.removeChild(textNode); 3073 a.appendChild(textNode); 3074 rightText.data = ' ' + rightText.data; 3075 3076 if(HTMLArea.is_ie) 3077 { 3078 var r = editor._createRange(s); 3079 s.moveToElementText(rightText); 3080 s.move('character', 1); 3081 } 3082 else 3083 { 3084 s.collapse(rightText, 1); 3085 } 3086 HTMLArea._stopEvent(ev); 3087 3088 editor._unLink = function() 3089 { 3090 var t = a.firstChild; 3091 a.removeChild(t); 3092 a.parentNode.insertBefore(t, a); 3093 a.parentNode.removeChild(a); 3094 editor._unLink = null; 3095 editor._unlinkOnUndo = false; 3096 } 3097 editor._unlinkOnUndo = true; 3098 3099 return a; 3100 } 3101 3102 switch(ev.which) 3103 { 3104 // Space, see if the text just typed looks like a URL, or email address 3105 // and link it appropriatly 3106 case 32: 3107 { 3108 if(s && s.isCollapsed && s.anchorNode.nodeType == 3 && s.anchorNode.data.length > 3 && s.anchorNode.data.indexOf('.') >= 0) 3109 { 3110 var midStart = s.anchorNode.data.substring(0,s.anchorOffset).search(/\S{4,}$/); 3111 if(midStart == -1) break; 3112 3113 if(this._getFirstAncestor(s, 'a')) 3114 { 3115 break; // already in an anchor 3116 } 3117 3118 var matchData = s.anchorNode.data.substring(0,s.anchorOffset).replace(/^.*?(\S*)$/, '$1'); 3119 3120 var m = matchData.match(HTMLArea.RE_email); 3121 if(m) 3122 { 3123 var leftText = s.anchorNode; 3124 var rightText = leftText.splitText(s.anchorOffset); 3125 var midText = leftText.splitText(midStart); 3126 3127 autoWrap(midText, 'a').href = 'mailto:' + m[0]; 3128 break; 3129 } 3130 3131 var m = matchData.match(HTMLArea.RE_url); 3132 if(m) 3133 { 3134 var leftText = s.anchorNode; 3135 var rightText = leftText.splitText(s.anchorOffset); 3136 var midText = leftText.splitText(midStart); 3137 autoWrap(midText, 'a').href = (m[1] ? m[1] : 'http://') + m[2]; 3138 break; 3139 } 3140 } 3141 3142 } 3143 break; 3144 3145 default : 3146 { 3147 if(ev.keyCode == 27 || (this._unlinkOnUndo && ev.ctrlKey && ev.which == 122) ) 3148 { 3149 if(this._unLink) 3150 { 3151 this._unLink(); 3152 HTMLArea._stopEvent(ev); 3153 } 3154 break; 3155 } 3156 else if(ev.which || ev.keyCode == 8 || ev.keyCode == 46) 3157 { 3158 this._unlinkOnUndo = false; 3159 3160 if(s.anchorNode && s.anchorNode.nodeType == 3) 3161 { 3162 // See if we might be changing a link 3163 var a = this._getFirstAncestor(s, 'a'); 3164 if(!a) break; // not an anchor 3165 if(!a._updateAnchTimeout) 3166 { 3167 if( s.anchorNode.data.match(HTMLArea.RE_email) 3168 && (a.href.match('mailto:' + s.anchorNode.data.trim())) 3169 ) 3170 { 3171 var textNode = s.anchorNode; 3172 var fn = function() 3173 { 3174 a.href = 'mailto:' + textNode.data.trim(); 3175 a._updateAnchTimeout = setTimeout(fn, 250); 3176 } 3177 a._updateAnchTimeout = setTimeout(fn, 250); 3178 break; 3179 } 3180 3181 var m = s.anchorNode.data.match(HTMLArea.RE_url); 3182 if(m && a.href.match(s.anchorNode.data.trim()) ) 3183 { 3184 var textNode = s.anchorNode; 3185 var fn = function() 3186 { 3187 var m = textNode.data.match(HTMLArea.RE_url); 3188 a.href = (m[1] ? m[1] : 'http://') + m[2]; 3189 a._updateAnchTimeout = setTimeout(fn, 250); 3190 } 3191 a._updateAnchTimeout = setTimeout(fn, 250); 3192 } 3193 } 3194 } 3195 3196 } 3197 } 3198 break; 3199 } 3200 } 3201 2943 3202 // other keys here 2944 switch (ev.keyCode) { 3203 switch (ev.keyCode) 3204 { 2945 3205 case 13: // KEY enter 2946 if (HTMLArea.is_gecko && !ev.shiftKey) { 3206 if (HTMLArea.is_gecko && !ev.shiftKey && this.config.mozParaHandler == 'dirty' ) 3207 { 2947 3208 this.dom_checkInsertP(); 2948 3209 HTMLArea._stopEvent(ev); … … 3894 4155 popup += ".html"; 3895 4156 url = _editor_url + "plugins/" + plugin + "/popups/" + popup; 3896 } else 4157 } else if(file.match(/^\/.*?/)) 4158 url = file; 4159 else 3897 4160 url = _editor_url + this.config.popupURL + file; 3898 4161 return url; … … 4030 4293 if(req.status == 200) 4031 4294 { 4295 if(typeof handler == 'function') 4032 4296 handler(req.responseText, req); 4033 4297 }
Note: See TracChangeset
for help on using the changeset viewer.