Hi!!
How about posts #39 and #40??
Hi!!
How about posts #39 and #40??
Dynamically loading tinymce into jQuery UI/Dialog.
There is a problem with dynamic loading both "native" tinymce and lazy loading
with gzip compressor.
Saying "dynamic loading" I mean complete dynamic loading when tiny_mce.js or
tiny_mce_gzip.js also loaded into the page dynamically.
Here is my use case:
I have GUI builder which creates dynamically tabled views (for example, news
list) and edit forms where none or one or more textareas with tinyMCE can be used.
Forms are added to the page dynamically into jQuery / UI Dialog.
Forms is generated as a set of widget and I have a widget for tinyMCE.
Since this GUI builder is generic I do not want to include tinymce core script
to all pages, but load it dynamically when appropriate widget is rendered on the
form.
Now I get to work both loading tiny_mce.js or tiny_mce_gzip.js dynamically and
had to solve some problems.
We have here two major issues: first - tinyMCE._init fails to set correct baseURL so other scripts not
loaded and second - scriptLoader.loadScripts by default
loads scripts with document.write and this breaks the page (all page content is gone).
Both problems where solved with following approach:
if (!window.tinymce) {
//set base URL for tinymce
window.tinyMCEPreInit = {base : '$assets/tinymce', suffix : '', query : ''};
//load tinymce
jQuery.ajax({
type : 'GET',
url : '$assets/tinymce/tiny_mce.js',
async : false,
success : function(co) {
var w = window;
// Evaluate script
if (!w.execScript) {
try {
eval.call(w, co);
} catch (ex) {
eval(co, w); // Firefox 3.0a8
}
} else {
w.execScript(co); // IE
}
//load scripts with dom manipulation instead of document.write
w.tinymce.dom.Event.domLoaded = true;
}
});
}
// Init textarea with jquery plugin
jQuery("#{$id}").tinyMCE({$tinyOptions}, '{$jsMode}', {$jsUseCookies});
I add js code to the page to load core tinymce script dynamically and create
window.tinyMCEPreInit object before script is loaded to set correct baseURL to solve first problem
and set tinymce.dom.Event.domLoaded = true after script is loaded to solve second.
Full text of modified ETinyMCE::init() method:
[spoiler]
public function init()
{
list($name, $id) = $this->resolveNameID();
if ($this->useCookies) {
if (isset($_COOKIE[$id.self::COOKIE_SUFFIX]) && in_array($_COOKIE[$id.self::COOKIE_SUFFIX], array('text', 'html'))) {
$this->setMode($_COOKIE[$id.self::COOKIE_SUFFIX]);
}
}
$baseDir = dirname(__FILE__);
$assets = Yii::app()->getAssetManager()->publish($baseDir.DIRECTORY_SEPARATOR.'assets');
$tinyOptions = $this->makeOptions();
$jsUseCookies = ($this->useCookies) ? 'true' : 'false';
$jsMode = strval($this->mode);
$jsToggleLabels = CJavaScript::encode($this->switchLabels);
$cs = Yii::app()->getClientScript();
$cs->registerCoreScript('jquery');
$this->htmlOptions['id'] = $id;
if (!array_key_exists('style', $this->htmlOptions)) {
$this->htmlOptions['style'] = "width:{$this->width};height:{$this->height};";
}
if (!array_key_exists('cols', $this->htmlOptions)) {
$this->htmlOptions['cols'] = self::COLS;
}
if (!array_key_exists('rows', $this->htmlOptions)) {
$this->htmlOptions['rows'] = self::ROWS;
}
$baseDir = dirname(__FILE__);
$assets = Yii::app()->getAssetManager()->publish($baseDir.DIRECTORY_SEPARATOR.'assets');
$bu = Yii::app()->getRequest()->getBaseUrl();
$js =<<<EOP
function fileBrowserCallback(field_name, url, type, win) {
var connector = '$assets/tinymce/filemanager/browser.html?Connector=$bu/tinymce/connector';
var enableAutoTypeSelection = true;
var cType;
tinyfck_field = field_name;
tinyfck = win;
switch (type) {
case 'image':
cType = 'Image';
break;
case 'flash':
cType = 'Flash';
break;
case 'file':
cType = 'File';
break;
}
if (enableAutoTypeSelection && cType) {
connector += '&Type=' + cType;
}
window.open(connector, 'tinyfck', 'modal,width=600,height=400');
};
EOP;
$cs->registerScript('Yii.'.get_class($this).'initTinyCallbacks', $js, CClientScript::POS_HEAD);
$cs->registerScriptFile($assets.'/jquery/jquery.tinymce.js');
$cs->registerScriptFile($assets.'/embedmedia/embed.js');
if ($this->useCompression) {
$cs->registerScriptFile($assets.'/tinymce/tiny_mce_gzip.js');
$gzOptions = $this->makeCompressor();
$js =<<<EOP
function initTinyGZ_$id() {
jQuery("#{$id}").tinyMCE({$tinyOptions}, '{$jsMode}', {$jsUseCookies});
}
window.tinyMCEPreInit = {base : '$assets/tinymce', suffix : '', query : ''};
tinyMCE_GZ.init({$gzOptions}, function() { initTinyGZ_$id(); });
EOP;
$cs->registerScript('Yii.'.get_class($this).'#'.$id, $js, CClientScript::POS_LOAD);
} else {
// Load tinymce script manually to be shure tinyMCEPreInit object is created
// before tinyMCE is initialized
$js =<<<EOP
if (!window.tinymce) {
//set base URL for tinymce
window.tinyMCEPreInit = {base : '$assets/tinymce', suffix : '', query : ''};
//load tinymce
jQuery.ajax({
type : 'GET',
url : '$assets/tinymce/tiny_mce.js',
async : false,
success : function(co) {
var w = window;
// Evaluate script
if (!w.execScript) {
try {
eval.call(w, co);
} catch (ex) {
eval(co, w); // Firefox 3.0a8
}
} else {
w.execScript(co); // IE
}
//load scripts with dom manipulation instead of document.write
w.tinymce.dom.Event.domLoaded = true;
}
});
}
jQuery("#{$id}").tinyMCE({$tinyOptions}, '{$jsMode}', {$jsUseCookies});
EOP;
$cs->registerScript('Yii.'.get_class($this).'#'.$id, $js, CClientScript::POS_LOAD);
}
if($this->hasModel()) {
$textarea = CHtml::activeTextArea($this->model, $this->attribute, $this->htmlOptions);
} else {
$textarea = CHtml::textArea($name, $this->value, $this->htmlOptions);
}
$html = '';
if ($this->useSwitch && !$this->readOnly) {
$label = $this->switchLabels[($this->mode=='html'?0:1)];
$css = ($this->labelClass !== '') ? array('class'=>$this->labelClass) : array('style'=>$this->labelStyle);
$switchOptions = array_merge(array('id'=>$id.self::SWITCH_SUFFIX), $css);
$uri = rawurlencode('$("#'.$id.'").toggleModeTinyMCE('.$jsToggleLabels.')');
$link = CHtml::link($label, 'javascript:'.$uri, $switchOptions);
$switch = CHtml::tag('div', array(), CHtml::tag('span', array(), $link));
$html = CHtml::tag('div', array(), $textarea.$switch);
} else {
$html = $textarea;
}
echo $html;
}
[/spoiler]
Here also two problems exist: first with base URL mentionad above and second -
with sequential calls of tinyMCE_GZ.init for more then one textareas.
I need to call tinyMCE_GZ.init more then once becuse when dialog with form is generated I
could not know how many tinymce widgets exists and each widget initializes
itself with such code:
function initTinyGZ_$id() {
// Init textarea with jquery plugin
jQuery("#{$id}").tinyMCE({$tinyOptions}, '{$jsMode}', {$jsUseCookies});
}
// this is for tinymce core when it will be loaded by tiny_mce_gzip.js
window.tinyMCEPreInit = {base : '$assets/tinymce', suffix : '', query : ''};
// init compressor and pass textarea initialization as callback
tinyMCE_GZ.init({$gzOptions}, function() { initTinyGZ_$id(); });
To solve problems I have with tiny_mce_gzip.js I had to modify its code.
To fix problem with base URL I added special setting to provide external base
URL through options and changed init() method to take that parameter.
To solve problem with sequential init() calls I changed init() function to
invoke callback even if core scripts are already loaded:
if (!t.coreLoaded)
t.loadScripts(1, s.themes, s.plugins, s.languages, cb, sc);
else
// SEB - scripts are loaded only once (loadScripts method sets t.coreLoaded to true)
// if we have two textareas on the page and provide tiniymce initialization in the
// callback function then second callback was never called
cb.call(sc || t, null);
and changed loadScripts to load core synchronously so second init() call will be
performed when scripts are actually loaded into the page:
//SEB - make syncronous call
x.open('GET', t.baseURL + '/' + s.page_name + '?' + q, false);
//x.setRequestHeader('Content-Type', 'text/javascript');
x.send('');
if (co)
t.coreLoaded = 1;
// SEB - Handle syncronous loading
if (cb && x.status == 200) {
t.loaded = 1;
t.eval(x.responseText);
tinymce.dom.Event.domLoaded = true;
cb.call(sc || t, x);
} else {
t.eval(x.responseText);
}
Modified text of tiny_mce_gzip.js:
[spoiler]
var tinyMCE_GZ = {
settings : {
themes : '',
plugins : '',
languages : '',
disk_cache : true,
page_name : 'tiny_mce_gzip.php',
debug : false,
suffix : '',
// SEB - exteral base url
baseURL : '',
},
init : function(s, cb, sc) {
var t = this, n, i, nl = document.getElementsByTagName('script');
for (n in s)
t.settings[n] = s[n];
s = t.settings;
if (t.settings.baseURL == '') {
for (i=0; i<nl.length; i++) {
n = nl[i];
if (n.src && n.src.indexOf('tiny_mce') != -1)
t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
}
} else {
// SEB - if script is loaded into the page dynamically it can not be found in the scripts array
// in this case we can specify external base url where tiny mce scripts are located
t.baseURL = t.settings.baseURL;
}
if (!t.coreLoaded)
t.loadScripts(1, s.themes, s.plugins, s.languages, cb, sc);
else
// SEB - scripts are loaded only once (loadScripts method sets t.coreLoaded to true)
// if we have two textareas on the page and provide tiniymce initialization in the
// callback function then second callback was never called
cb.call(sc || t, null);
},
loadScripts : function(co, th, pl, la, cb, sc) {
var t = this, x, w = window, q, c = 0, ti, s = t.settings;
function get(s) {
x = 0;
try {
x = new ActiveXObject(s);
} catch (s) {
}
return x;
};
// Build query string
q = 'js=true&diskcache=' + (s.disk_cache ? 'true' : 'false') + '&core=' + (co ? 'true' : 'false') + '&suffix=' + escape(s.suffix) + '&themes=' + escape(th) + '&plugins=' + escape(pl) + '&languages=' + escape(la);
// SEB - Here also was a problem withis.two or more textareas on the page
// request was asyncronous and "t.coreLoaded = 1" was set before request is even started.
// When tinyMCE_GZ.init was invoked for the second area we have "t.coreLoaded = 1" and
// scripts are not loaded yet. So second area initialization was failed.
// Now request for script is sent syncronously and problem is gone.
// Send request
x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Msxml2.XMLHTTP') || get('Microsoft.XMLHTTP');
x.overrideMimeType && x.overrideMimeType('text/javascript');
//x.open('GET', t.baseURL + '/' + s.page_name + '?' + q, !!cb);
//SEB - make syncronous call
x.open('GET', t.baseURL + '/' + s.page_name + '?' + q, false);
// x.setRequestHeader('Content-Type', 'text/javascript');
x.send('');
if (co)
t.coreLoaded = 1;
// SEB - Handle syncronous loading
if (cb && x.status == 200) {
t.loaded = 1;
t.eval(x.responseText);
tinymce.dom.Event.domLoaded = true;
cb.call(sc || t, x);
} else {
t.eval(x.responseText);
}
/*
// Handle asyncronous loading
if (cb) {
// Wait for response
ti = w.setInterval(function() {
if (x.readyState == 4 || c++ > 10000) {
w.clearInterval(ti);
if (c < 10000 && x.status == 200) {
t.loaded = 1;
t.eval(x.responseText);
tinymce.dom.Event.domLoaded = true;
cb.call(sc || t, x);
}
ti = x = null;
}
}, 10);
} else
t.eval(x.responseText);*/
},
...
[/spoiler]
Thanks for posting your modifications. I’ll try to update the extension soon. It’s been a difficult second part of the year, and I was dedicated mostly to system administration, so I stopped the development a bit
Hi I have the same problem with the image manager, did you ever get this to work? If so I would greatly appreciate some advice…
Hi all,
How do you set "document_base_url" with this extension ?
Thanks!
Anyone have any idea why the tiny_mce_###.gz file is not being created in assets?
I have my own server with a site running this extension fine. I use the same exact code on a web host I don’t own and I can’t get this extension to load. The one thing I’m noticing is that on the one that doesn’t work the compressed file doesn’t get created in the assets directory (under the tiny_mce folder). Anyone have any ideas why or what I can do to debug it? I don’t get any errors on the page, it just loads a text box with no TinyMCE.
I don’t understand why for me this solution don’t work. I open dialog so:
$('.update').live('click',(function(){
var id=$(this).attr('id');
$.ajax({
url: '".Yii::app()->createUrl("admin/offerte/update")."&id='+id,
success: function(data) {
$('#dialog').html(data);
var buttons = $( '#dialog' ).dialog( 'option', 'buttons' );
$('#dialog').dialog('open');
return false;
}});
}));
Same here, why it wasn’t solved yet?
What is the purpose of $tinymce variable?
1 - I don’t want to change the core.
2 - I don’t want do disable warning.
What is the best approach?
Thanks
When I try to change the list of plugins:
$this->widget('application.extensions.tinymce.ETinyMce',
array(
'name'=>'html',
'editorTemplate' => 'full',
'options' => array('plugins' => 'test1,test2'),
)
);
Then the list of plug-ins for tinyMCE_GZ remains not changed in page script:
tinyMCE_GZ.init({'plugins':'safari,pagebreak,style,...);
But:
window.onload=function() {
jQuery("#html").tinyMCE({...,'plugins':'test1,test2'}, 'html', true);
};
Is it correct?
It appears the $tinymce variable should be the $assets variable as it is used by makeFullEditor(). I’ve changed this and it appears to be working correctly.
Hello mates,
I have integrated this extension and it works great.
I have a little problem with generated xhtml code. It is written in db as it should be but when I generate view to show the entered elements I see the tags and they are not interpreted by the browser (i see html code on my page, I mean tags).
What could be wrong ?
I’m not sure if anyone has figured this out yet but the extension bailed in Windows Vista running wampp after using it successfully on a linux box and a linux server.
I see some others have found the anomololy but I didn’t read all posts to see if it was solved. This worked for me
// $tinyOptions = $this->makeOptions($tinymce); // broken in Wampp on Vista but works on Linux box ??
$tinyOptions = $this->makeOptions(); // this works on both
It seems that $tinymce just evaluates to null on the linux box, wampp croaks.
dunno why!!
doodle
Could you post your changes? Probably better than my approach
I believe this is what he did, but I’ve made several other modifications so I’m not 100% sure that this fixed it completely.
In protected/extensions/tinymce/ETinyMce.php, line 842:
find:
$tinyOptions = $this->makeOptions($tinymce);
change to:
$tinyOptions = $this->makeOptions($assets);
hi everyone, had just founded out a problem maybe it is described already in a topic list just have no time to read them all), i integrated tinymcy into my system and need to remove status/path bar from it, puted
“theme_advanced_path”=> false, removed “theme_advanced_statusbar_location” from list, but it steal showes me path bar, hm thats the problem i decided to dig a source ETinyMce.php and founded out that developers defined it for the user $options[‘theme_advanced_path_location’] = ‘bottom’; twice at line 691 and 698, and other parameter that must be removed $options[‘theme_advanced_path_location’] at line 701 plugin version 1.1 no problems for developer greate thx for him o her just make a remark
I’ve made some fixes and improvements to the extension :
. Fixed $tinymce variable issue (replaced with $assets)
. Upgraded to latest version of tinymce, 3.3.9.2
. Fixed certain plugins from autoloading, due to the $this->plugins being hardcoded. Now looks to see if the plugins array is empty before applying default plugins.
I’d like to share these with the community, how should I go about doing that ?
Thanks
It looks like the author abandoned the project some time ago?
I can see that the extension hasn’t been updated since Aug 18, 2009.
And that means that the author wrote the extension, uploaded the initial version, and then made an update to it two months later.
And then left it behind.
I would create a new extension (page) and put the code up on a public repository.
Google code, Github, Bitbucket?
IMO, that’s the best approach.
<edit>
Of course, you could ask ‘someone’ (moderator/team?) to allow you to take over the extension…
</edit>
Can you or did you publish your changes somewhere?
Hello,
I used this extension and it works perfect on localhost, but when I upload it to my web server, it stops working.
After looking I found out that it’s caused because the file tiny_mce_gzip.php could not be accessed because of its containing folder having permission of 777. If I change the permission of the whole folder (/assets/tiny_mce) to 755, then it works.
Why is this happening?
Thanks
Today I was bit by Bug #48885 hxxp://bugs.php.net/48885. (This is my first post and I cannot embed links yet so replace hxxp with http.) After spending hours trying to find out what’s wrong I came up with this patch that fixes the problem. I hope that it will be put into the extension soon so others can use it.
1723