diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt
index 05dc3b802..5693f4390 100644
--- a/docs/changelog/7.x.x.txt
+++ b/docs/changelog/7.x.x.txt
@@ -62,6 +62,7 @@
- fixed #10625: Map point no save button
- fixed #10639: Map: Can't edit or delete points
- fixed #10640: Map: points not working correctly
+ - fixed Codearea editor to work a lot better and be more compatible
7.7.17
- fixed #10697: Story: Image crowds text
diff --git a/lib/WebGUI/Form/Codearea.pm b/lib/WebGUI/Form/Codearea.pm
index 01fb4aeef..cff4b5674 100644
--- a/lib/WebGUI/Form/Codearea.pm
+++ b/lib/WebGUI/Form/Codearea.pm
@@ -16,6 +16,7 @@ package WebGUI::Form::Codearea;
use strict;
use base 'WebGUI::Form::Textarea';
+use HTML::Entities qw(encode_entities decode_entities);
use WebGUI::International;
=head1 NAME
@@ -114,6 +115,21 @@ sub getName {
#-------------------------------------------------------------------
+=head2 getValue ( [value] )
+
+Return the value, HTML decoded
+
+=cut
+
+sub getValue {
+ my ( $self, @args ) = @_;
+ my $value = $self->SUPER::getValue( @args );
+ $self->session->log->warn( $value );
+ return decode_entities( $value );
+}
+
+#-------------------------------------------------------------------
+
=head2 isDynamicCompatible ( )
A class method that returns a boolean indicating whether this control is compatible with the DynamicField control.
@@ -136,7 +152,7 @@ sub toHtml {
my $self = shift;
my ($style, $url, $stow) = $self->session->quick(qw(style url stow));
- my $value = $self->fixMacros($self->fixTags($self->fixSpecialCharacters(scalar $self->getOriginalValue)));
+ my $value = encode_entities( $self->fixMacros($self->fixTags($self->fixSpecialCharacters(scalar $self->getOriginalValue))) );
my $width = $self->get('width') || 400;
my $height = $self->get('height') || 150;
my $id = $self->get('id');
@@ -146,33 +162,31 @@ sub toHtml {
my $styleAttr = $self->get('style');
$style->setLink($url->extras("yui/build/resize/assets/skins/sam/resize.css"), {type=>"text/css", rel=>"stylesheet"});
- $style->setScript($url->extras("yui/build/utilities/utilities.js"), {type=>"text/javascript"});
- $style->setScript($url->extras("yui/build/resize/resize-min.js"), {type=>"text/javascript"});
- $style->setScript($url->extras('editarea/edit_area/edit_area_full.js'), {type=>"text/javascript"});
+ $style->setLink($url->extras("yui/build/assets/skins/sam/skin.css"), {type=>"text/css", rel=>"stylesheet"});
+ $style->setLink($url->extras('yui/build/logger/assets/skins/sam/logger.css'), {type=>"text/css", rel=>"stylesheet"});
+ $style->setScript($url->extras("yui/build/yahoo-dom-event/yahoo-dom-event.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/utilities/utilities.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/container/container_core-min.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/menu/menu-min.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/button/button-min.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/element/element-min.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/dragdrop/dragdrop-min.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/resize/resize-min.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/editor/editor-debug.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui/build/logger/logger.js"),{type=>"text/javascript"});
+ $style->setScript($url->extras("yui-webgui/build/code-editor/code-editor.js"),{type=>"text/javascript"});
+ my $codeCss = $url->extras("yui-webgui/build/code-editor/code.css");
my $out = <<"END_HTML";
-
-
-
+
END_HTML
return $out;
diff --git a/www/extras/yui-webgui/build/code-editor/code-editor.js b/www/extras/yui-webgui/build/code-editor/code-editor.js
new file mode 100755
index 000000000..2d1a82a73
--- /dev/null
+++ b/www/extras/yui-webgui/build/code-editor/code-editor.js
@@ -0,0 +1,294 @@
+(function() {
+ var Dom = YAHOO.util.Dom,
+ Event = YAHOO.util.Event,
+ Lang = YAHOO.lang
+ ;
+
+ YAHOO.widget.CodeEditor = function (id, cfg) {
+ // Disable Editor configs that don't apply
+ cfg["animate"] = false;
+ cfg["dompath"] = false;
+
+ // Default toolbar is different
+ cfg["toolbar"] = cfg["toolbar"] || {
+ titlebar : "Code Editor",
+ buttons : []
+ };
+
+ YAHOO.widget.CodeEditor.superclass.constructor.call(this, id, cfg);
+
+ // Allow us to have no buttons
+ // This will be fixed in a future version of YUI Editor
+ YAHOO.widget.Toolbar.prototype.disableAllButtons
+ = function () {
+ if (!this._buttonList) {
+ this._buttonList = [];
+ }
+ if (this.get('disabled')) {
+ return false;
+ }
+ var len = this._buttonList.length;
+ for (var i = 0; i < len; i++) {
+ this.disableButton(this._buttonList[i]);
+ }
+ };
+ // End allow us to have no buttons
+
+ this.on('editorContentLoaded', function() {
+ // Add the code stylesheet
+ var link = this._getDoc().createElement('link');
+ link.rel = "stylesheet";
+ link.type = "text/css";
+ link.href = this.get('css_url');
+ this._getDoc().getElementsByTagName('head')[0].appendChild(link);
+ // Highlight the initial value
+ if ( !this.browser.ie ) { // IE puts "!!CURSOR HERE!!" in the main doc, not the iframe...
+ this.highlight(false);
+ }
+ // Setup resize
+ if ( this.status ) {
+ this._writeStatus();
+ this._setupResize();
+ }
+ }, this, true);
+ this.on('editorKeyUp', function(ev) {
+
+ // Don't highlight arrows or modifiers
+ if ( ( ev.ev.keyCode > 36 && ev.ev.keyCode < 41 )
+ || ev.ev.keyCode == 16 || ev.ev.keyCode == 17
+ || ev.ev.keyCode == 18 || ev.ev.keyCode == 91 // Safari "command"
+ || ev.ev.keyCode == 224 // Firefox "command"
+ ) {
+ return;
+ }
+
+ // TODO: Don't re-highlight if there is a selection
+ // That is the problem we're trying to avoid with disabling
+ // highlighting for arrows and modifiers
+
+ // Highlight every keypress
+ Lang.later(10, this, this.highlight);
+ Lang.later(100, this, this._writeStatus);
+ }, this, true);
+
+ //Borrowed this from CodePress: http://codepress.sourceforge.net
+ this.cc = '\u2009'; // carret char
+ this.keywords = [
+ { code: /(<DOCTYPE.*?-->.)/g, tag: '$1' }, // comments
+ { code: /(<[^!]*?>)/g, tag: '$1' }, // all tags
+ { code: /(<!--.*?-->.)/g, tag: '$1' }, // comments
+ { code: /\b(YAHOO|widget|util|Dom|Event|lang)\b/g, tag: '$1' }, // reserved words
+ { code: /\b(break|continue|do|for|new|this|void|case|default|else|function|return|typeof|while|if|label|switch|var|with|catch|boolean|int|try|false|throws|null|true|goto)\b/g, tag: '$1' }, // reserved words
+ { code: /\"(.*?)(\"|
|<\/P>)/gi, tag: '"$1$2' }, // strings double quote
+ { code: /\'(.*?)(\'|
|<\/P>)/gi, tag: '\'$1$2' }, // strings single quote
+ { code: /\b(alert|isNaN|parent|Array|parseFloat|parseInt|blur|clearTimeout|prompt|prototype|close|confirm|length|Date|location|Math|document|element|name|self|elements|setTimeout|navigator|status|String|escape|Number|submit|eval|Object|event|onblur|focus|onerror|onfocus|onclick|top|onload|toString|onunload|unescape|open|valueOf|window|onmouseover|innerHTML)\b/g, tag: '$1' }, // special words
+ { code: /([^:]|^)\/\/(.*?)(
//$2$3' }, // comments //
+ { code: /\/\*(.*?)\*\//g, tag: '/*$1* /' } // comments / * */
+ ];
+ //End Borrowed Content
+
+ };
+ Lang.extend( YAHOO.widget.CodeEditor, YAHOO.widget.Editor, {
+ /**
+ * @property _defaultCSS
+ * @description The default CSS used in the config for 'css'. This way you can add to the config like this: { css: YAHOO.widget.SimpleEditor.prototype._defaultCSS + 'ADD MYY CSS HERE' }
+ * @type String
+ */
+ _defaultCSS: 'html { height: 95%; } body { background-color: #fff; font:13px/1.22 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small; } a, a:visited, a:hover { color: blue !important; text-decoration: underline !important; cursor: text !important; } .warning-localfile { border-bottom: 1px dashed red !important; } .yui-busy { cursor: wait !important; } img.selected { border: 2px dotted #808080; } img { cursor: pointer !important; border: none; } body.ptags.webkit div { margin: 11px 0; }'
+ });
+
+
+ YAHOO.widget.CodeEditor.prototype._cleanIncomingHTML = function(str) {
+ // before
for IE7 so lines show up correctly
+ str = str.replace(/\r?\n/g, "
");
+ return str;
+ };
+
+ /* Override to fix problem with the rest of what the normal _handleFormSubmit does
+ * ( it doesn't properly click the correct submit button )
+ */
+ YAHOO.widget.CodeEditor.prototype._handleFormSubmit = function () {
+ this.saveHTML();
+ return;
+ };
+ /* End override to fix problem */
+
+ YAHOO.widget.CodeEditor.prototype._writeStatus = function () {
+ if ( this.status ) {
+ var text = this.getEditorText();
+ this.status.innerHTML
+ = 'C: ' + text.length
+ + ' L: ' + text.split(/\r?\n/).length
+ ;
+ }
+ };
+
+ /**
+ * @private
+ * @method _setupResize
+ * @description Creates the Resize instance and binds its events.
+ */
+ YAHOO.widget.CodeEditor.prototype._setupResize
+ = function() {
+ if (!YAHOO.util.DD || !YAHOO.util.Resize) { return false; }
+ if (this.get('resize')) {
+ var config = {};
+ Lang.augmentObject(config, this._resizeConfig); //Break the config reference
+ this.resize = new YAHOO.util.Resize(this.get('element_cont').get('element'), config);
+ this.resize.on('resize', function(args) {
+ var anim = this.get('animate');
+ this.set('animate', false);
+ this.set('width', args.width + 'px');
+ var h = args.height,
+ th = (this.toolbar.get('element').clientHeight + 2),
+ dh = 0;
+ if (this.status) {
+ dh = (this.status.clientHeight + 1); //It has a 1px top border..
+ }
+ var newH = (h - th - dh);
+ this.set('height', newH + 'px');
+ this.get('element_cont').setStyle('height', '');
+ this.set('animate', anim);
+ }, this, true);
+ }
+ };
+
+ YAHOO.widget.CodeEditor.prototype.cleanHTML = function (html) {
+ if (!html) {
+ html = this.getEditorHTML();
+ }
+ html = html.replace(/ /g," ");
+ html = html.replace(/ ?
/gi,'\n');
+ html = html.replace(/<[^>]+>/g,'');
+ // Remove spaces at end of lines
+ html = html.replace(/ +\r?\n/g,"");
+ return html;
+ };
+
+ YAHOO.widget.CodeEditor.prototype.focusCaret = function() {
+ if (this.browser.gecko) {
+ if (this._getWindow().find(this.cc)) {
+ this._getSelection().getRangeAt(0).deleteContents();
+ }
+ } else if (this.browser.webkit || this.browser.ie || this.browser.opera) {
+ var cur = this._getDoc().getElementById('cur');
+ if ( cur ) {
+ cur.id = '';
+ cur.innerHTML = '';
+ this._selectNode(cur);
+ }
+ }
+ };
+
+ YAHOO.widget.CodeEditor.prototype.getEditorText
+ = function () {
+ return this.cleanHTML( this.getEditorHTML() );
+ };
+
+ YAHOO.widget.CodeEditor.prototype.highlight = function(focus) {
+
+ // Opera support is not working yet
+ if ( this.browser.opera ) {
+ return;
+ }
+ // Firefox < 3 support is not working yet
+ if ( this.browser.gecko && this.browser.gecko <= 1.8 ) {
+ return;
+ }
+
+ if (!focus) {
+ if (this.browser.gecko) {
+ this._getSelection().getRangeAt(0).insertNode(this._getDoc().createTextNode(this.cc));
+ } else if (this.browser.webkit || this.browser.ie || this.browser.opera) {
+ try {
+ this.execCommand('inserthtml', '!!CURSOR_HERE!!');
+ }
+ catch (e) {}
+ }
+ }
+ var html = '';
+ html = this._getDoc().body.innerHTML;
+ //if (this.browser.opera) {
+ // html = html.replace(/<(?!span|\/span|br).*?>/gi,'');
+ //} else
+ if (this.browser.webkit) {
+ //YAHOO.log('1: ' + html);
+ html = html.replace(/<\/div>/ig, '');
+ html = html.replace(/
/ig, '
');
+ html = html.replace(/
/ig, '
');
+ html = html.replace(/
/ig,'\n');
+ html = html.replace(/<.*?>/g,'');
+ html = html.replace(/\r?\n/g,'
');
+ //YAHOO.log('2: ' + html);
+ } else {
+ if (this.browser.ie) {
+ html = html.replace(/<\/SPAN>/ig, '');
+ }
+ YAHOO.log(html);
+ // before
for IE7
+ html = html.replace(/( |!!CURSOR_HERE!!)?
]*>/gi,'$1\n');
+ html = html.replace(/<[^>]*>/g,'');
+ html = html.replace(/\r?\n/g,'
');
+ // between
for IE6
+ html = html.replace(/
]*>(!!CURSOR_HERE!!)?
]*>/gi, '
$1
');
+ YAHOO.log(html);
+ }
+ for (var i = 0; i < this.keywords.length; i++) {
+ html = html.replace(this.keywords[i].code, this.keywords[i].tag);
+ }
+ YAHOO.log("AFTER HIGHLIGHT:" + html);
+ html = html.replace('!!CURSOR_HERE!!', '|');
+
+ this._getDoc().body.innerHTML = html;
+ if (!focus) {
+ this.focusCaret();
+ }
+ };
+
+ /**
+ * @method initAttributes
+ * @description Initializes all of the configuration attributes used to create
+ * the editor.
+ * @param {Object} attr Object literal specifying a set of
+ * configuration attributes used to create the editor.
+ */
+ YAHOO.widget.CodeEditor.prototype.initAttributes
+ = function(attr) {
+ YAHOO.widget.CodeEditor.superclass.initAttributes.call(this, attr);
+ var self = this;
+ /**
+ * @attribute status
+ * @description Toggle the display of a status line below the editor
+ * @default false
+ * @type Boolean
+ */
+ this.setAttributeConfig('status', {
+ value: attr.status || false,
+ method: function(status) {
+ if (status && !this.status) {
+ this.status = document.createElement('DIV');
+ this.status.id = this.get('id') + '_status';
+ Dom.addClass(this.status, 'dompath'); // Piggy-back on Editor's dompath
+ this.get('element_cont').get('firstChild').appendChild(this.status);
+ if (this.get('iframe')) {
+ this._writeStatus();
+ }
+ } else if (!status && this.status) {
+ this.status.parentNode.removeChild(this.status);
+ this.status = null;
+ }
+ }
+ });
+ /**
+ * @attribute css_url
+ * @description The URL to the CSS file for the inside of the code editor
+ * @default 'code.css'
+ * @type String
+ */
+ this.setAttributeConfig('css_url', {
+ value: attr.css_url || 'code.css'
+ } );
+ };
+
+})();
+
diff --git a/www/extras/yui-webgui/build/code-editor/code.css b/www/extras/yui-webgui/build/code-editor/code.css
new file mode 100755
index 000000000..783326044
--- /dev/null
+++ b/www/extras/yui-webgui/build/code-editor/code.css
@@ -0,0 +1,9 @@
+body { background:white url(line-numbers.png) repeat-y scroll 0pt -4px; font-family:monospace; font-size:13px; height:100%; line-height:16px; margin-left:32px; margin-top:8px; white-space:pre; }
+b, i, s, u, a, em, tt, ins, big, cite, strong, var, dfn {text-decoration:none;font-weight:normal;font-style:normal;font-size:13px;}
+b, cite {color:#7F0055;font-weight:bold;} /* reserved words */
+u {color:darkblue;font-weight:bold;} /* special words */
+i, i b, i s, i u {color:green;font-weight:normal;} /* comments */
+s, s b, s u {color:#2A00FF;font-weight:normal;} /* strings */
+ins, ins b, ins s, ins em {color:green;} /* comments */
+a {color:blue; text-decoration: underline; } /* links */
+body.ie { padding-left: 32px; margin-left: 0px; background-position: 0 -10px; margin-top: 0px;}
diff --git a/www/extras/yui-webgui/build/code-editor/line-numbers.png b/www/extras/yui-webgui/build/code-editor/line-numbers.png
new file mode 100755
index 000000000..ffea4e6aa
Binary files /dev/null and b/www/extras/yui-webgui/build/code-editor/line-numbers.png differ