TLDR: How can I identify what's being added by the call to <jdoc:include type="head" />?
In an attempt to avoid doing yet another site for friends/family, this time I set up a copy of Joomla 3 on AWS, handed over the creds and thought "Job well done"... More fool me.
Somehow Joomla has been configured in a way that's throwing a JS Exception. Specifically, something's attempting to call jQuery and getting an undefined error. Note that there's a call to jQuery.noConflict(); after the line with the error.
Needless to say, the person in question doesn't really know what they've done because they were following a guide to add a contact form that they can no longer find.
Words have been had. Emphatically.
How can I track down which plugin/extension/template added a particular line in the output?
The offending script is being dumped directly into the main page, not linked and is semi-minified.
I'm hoping that the fact that it comes after the external script files, just before what looks like a session keep-alive Ajax request will be a good enough pointer.
The beautified version of the script looks something like this...
jQuery(window).on('load', function() {
new JCaption('img.caption');
});
jQuery(document).ready(function() {
jQuery('.hasTooltip').tooltip({
"html": true,
"container": "body"
});
});
jQuery(document).ready(function() {
jQuery('.hasPopover').popover({
"html": true,
"trigger": "hover focus",
"container": "body"
});
});
jQuery.noConflict();
$(document).ready(function() {
$("#contact-form").validate({
rules: {
/* Lots of validation rules */
},
highlight: function(label) {
$(label).closest(".control-group").addClass("error");
},
success: function(label) {
label.addClass("valid").closest(".control-group").addClass("success");
}
});
});
window.setInterval(function() {
var r;
try {
r = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP")
} catch (e) {}
if (r) {
r.open("GET", "./", true);
r.send(null)
}
}, 840000);
It looks like it's trying to validate a contact form so is a likely culprit but there isn't one on the site (at least, not one that's working/visible).
Just after that block is a non-jQuery Ajax request to the home page (every 14 minutes?) I assume this is some form of session keep-alive. Ironically this doesn't rely on jQuery.
I've looked at the template's component.php and that whole section seems to be added via a <jdoc:include type="head" />
What's the next link in the chain? I can't see any files or xml blocks that specify what the head include relates to.
About the error:
You can read the reason why the javascript is not working here.
So in there you'll find the fix.
About how to find the file:
Just search for $("#contact-form") in the following folders:
components/
modules/
templates
There is hight canches the it's a module so maybe it could be useful for your investigation that you track if this error is in each page or just in some pages.
If it's in all the pages probably the file is in the templates or component folder otherwise it's a module.
If it's a module you just have to go in the backend and check the module enabled in the page broken.
I hope it's gonna be useful.
Related
I have set a razor page as the landing page for my application:
options.Conventions.AddAreaPageRoute("Home","/Home/Index", "");
My pages are all contained in areas, so in order to access them by url more easily I wanted to avoid writing the additional area name, so from Home/Home/page to Home/Index:
options.Conventions.AddAreaPageRouteModelConvention("Home", "/Home/Index", model =>
{
foreach (var selector in model.Selectors)
{
selector.AttributeRouteModel = new AttributeRouteModel
{
Template = new string(selector.AttributeRouteModel.Template.SkipWhile(c => c != '/').Skip(1).ToArray()),
};
}
});
I also modified my app settings:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "Default",
template: "{area=Home}/{page=Index}");
});
I removed all the other mapRoutes, including controller routing, etc.
After I added this snippet I tried accessing the pages by /Home/Index, and it worked, however my js scripts are not loading and thus not functioning. Then I removed the aforementioned option and attempted to access the page by Home/Home/Index and my scripts were still not loading. They do load property if I use the anchors I have set up:
<a class="nav-bar-brand" asp-area="Home" asp-page="/Home/Index">...</a>
The script file is included in the Layout:
<script src="js/site.js" type="text/javascript"></script>
The problem appears to be that the browser is looking for the file in the wrong place, this is the Request URL that the General header contains "https://localhost/Home/Home/js/site.js", while in reality the proper address is "https://localhost/js/site.js", why is this happening and how do I fix it?
<script src="**~/**js/site.js" type="text/javascript"></script>
You must update your code thats. (
/
or
~/
get starting on domain root folder)
I'm using CakePHP 2.4.7 and the TinyMCE plugin from CakeDC.
I set up my CakePHP core along with the plugin in a shared location on my server so that multiple applications can access it. This keeps me from having to update multiple copies of TinyMCE. Everything was working well until I migrated to a new server and updated software.
The new server is running Apache 2.4 instead of 2.2 and using mod_ruid2 instead of suexec.
I now get this error when trying to load the editor:
Fatal Error (4): syntax error, unexpected T_CONSTANT_ENCAPSED_STRING in [/xyz/Plugin/TinyMCE/webroot/js/tiny_mce/tiny_mce.js, line 1]
How should I start debugging this?
Workaround Attempt
I tried adding a symlink from an application's webroot to TinyMCE's plugin webroot. This works in that it loads the js file and the editor, but then TinyMCE plugins are working on the wrong current directory and file management would not be separated.
The problem is the AssetDispatcher filter, it includes css and js files using PHPs include() statement, causing the files to be sent through the PHP parser, where it will stumble over the occurrences of <? in the TinyMCE script.
See https://github.com/.../2.4.7/lib/Cake/Routing/Filter/AssetDispatcher.php#L159-L160
A very annoying, and, since it's undocumented and non-optional, dangerous behavior if you ask me.
Custom asset dispatcher
In case you want to continue to use a plugin asset dispatcher, extend the built in one, and reimplement the AssetDispatcher::_deliverAsset() method with the include functionality removed. Of course this is kinda annoying, maintenance wise, but it's a pretty quick fix.
Something like:
// app/Routing/Filter/MyAssetDispatcher.php
App::uses('AssetDispatcher', 'Routing/Filter');
class MyAssetDispatcher extends AssetDispatcher {
protected function _deliverAsset(CakeResponse $response, $assetFile, $ext) {
// see the source of your CakePHP core for the
// actual code that you'd need to reimpelment
ob_start();
$compressionEnabled = Configure::read('Asset.compress') && $response->compress();
if ($response->type($ext) == $ext) {
$contentType = 'application/octet-stream';
$agent = env('HTTP_USER_AGENT');
if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) {
$contentType = 'application/octetstream';
}
$response->type($contentType);
}
if (!$compressionEnabled) {
$response->header('Content-Length', filesize($assetFile));
}
$response->cache(filemtime($assetFile));
$response->send();
ob_clean();
// instead of the possible `include()` in the original
// methods source, use `readfile()` only
readfile($assetFile);
if ($compressionEnabled) {
ob_end_flush();
}
}
}
// app/Config/bootstrap.php
Configure::write('Dispatcher.filters', array(
'MyAssetDispatcher', // instead of AssetDispatcher
// ...
));
See also http://book.cakephp.org/2.0/en/development/dispatch-filters.html
Don't just disable short open tags
I'm just guessig here, but the reason why it was working on your other server probably is that short open tags (ie <?) where disabled. However even if that is the problem on your new server, this isn't something you should rely on, the assets are still being served using include(), and you most probably don't want to check all your third party CSS/JS for possible PHP code injections on every update.
I am looking for an equivalent to jquery's load() method that will work offline. I know from jquery's documentation that it only works on a server. I have some files from which I need to call the html found inside a particular <div> in those files. I simply want to take the entire site and put it on a computer without an internet connection, and have that portion of the site (the load() portion) function just as if it was connected to the internet. Thanks.
Edit: BTW, it doesn't have to be js; it can be any language that will work.
Edit2:
My sample code (just in case there are syntax errors I am missing; this is for the files in the same directory):
function clickMe() {
var book = document.getElementById("book").value;
var chapter = document.getElementById("chapter").value;
var myFile = "'" + book + chapter + ".html'";
$('#text').load(myFile + '#source')
}
You can't achieve load() over the file protocol, no other ajax request is going to work for html files. I have tried even with the crossDomain and isLocale option on without anything success, even if precising the protocol.
The problem is that even if jQuery is trying the browser will stop the request for security issues (well most browsers as the snippet below works in FF) as it allows you to load locale file so you could get access to a lot of things.
The one thing you could load locally is javascript files, but that probably means changing a lot of the application/website architecture.
Only works in FF
$.ajax({
url: 'test.html',
type: 'GET',
dataType: 'text',
isLocale: true,
success: function(data) {
document.body.innerHTML = data;
}
});
What FF does well is that it detect that the file requesting local files is on the file protocol too when other don't. I am not sure if it has restriction over the type of files you can request.
You can still use the JQuery load function in this context:
You would could add an OfflineContent div on your page:
<div id="OfflineContent">
</div>
And then click a button which calls:
$('#OfflineContent').load('OfflinePage.html #contentToLoad');
Button code:
$("#btnLoadContent").click(function() {
$('#OfflineContent').load('OfflinePage.html #contentToLoad');
});
In the OfflinePage.html you could have to have another section called contentToLoad which would display on the initial page.
Is there any way to force an <a href> to do a delete request when clicked instead of a regular GET?
The "Rails" way is to dynamically generate a <form> tag that adds the appropriate params so that it gets routed to the right place, however I'm not too fond of that much DOM manipulation for such a simple task.
I thought about going the route of something like:
$("a.delete").click(function(){
var do_refresh = false;
$.ajax({
type: "DELETE",
url: "my/path/to/delete",
success: function(){
do_refresh = true;
},
failure: function(){
alert("There is an error");
}
});
return do_refresh; //If this is false, no refresh would happen. If it
//is true, it will do a page refresh.
});
I'm not sure if the above AJAX stuff will work, as it's just theoretical. Is there any way to go about this?
Note:
Please don't recommend that I use the rails :method => :delete on link_to, as I'm trying to get away from using the rails helpers in many senses as they pollute your DOM with obtrusive javascript. I'd like this solution to be put in an external JS file and be included as needed.
According to the docs:
http://api.jquery.com/jQuery.ajax/
the DELETE method is allowed but not supported on all browsers, so you should take a look here:
Are the PUT, DELETE, HEAD, etc methods available in most web browsers?
This is what i do:
$("a.delete").live('click', function() {
$.post(this.href, "_method=delete", function(data) {
//do refresh
});
return false;
})
But i don't really know which all browsers support it and which don't. I tested it on mac with Firefox 2 and 3.6, safari 3 and chrome beta 5.0.375.70 and it works.
You can use RESTInTag plugin, it will do the ajax requests for you all you have to do is add a couple of extra attributes to your HTML tag
Example:
HTML
<button class="delete" data-target="my/path/to/delete" data-method="DELETE" data-disabled="true">Delete Article</button>
JavaScript
$(".delete").restintag(optionsObj, function() {
do_refresh = true
},
function() {
alert("some error happened");
});
I use this plugin: jQuery.i18n.properties
I put this code:
/* Do stuff when the DOM is ready */
jQuery(document).ready(loadMessage);
/*
* Add elements behaviours.
*/
function loadMessage() {
jQuery("#customMessage").html("test");
jQuery.i18n.properties({
name:'up_mail_messages',
path:'https://static.unifiedpost.com/apps/myup/customer/upmail/upmail_messages/',
mode:'both',
language:'en',
callback: function() {
var messageKey = 'up.mail.test';
//alert(eval(messageKey));
jQuery('#customMessage').html(jQuery.i18n.prop(messageKey));
}
});
}
I do not understand why, in the customeMessage div it prints out:
[up.mail.test]
instead of the value of it:
up.mail.test=messages loaded from en
Can anybody show me where i am wrong? I;ve spent about two hours on it without finding any clue...
Many Thanks.
Ps: here is the message file: https://static.unifiedpost.com/apps/myup/customer/upmail/upmail_messages/up_mail_messages_en.properties
EDIT: After testing locally, all works good. But if the messages files are located to another host (like in the above example) it seems that it fails...It would be nice if anyone can confirm this...
EDIT 1: It does not work because inside the js script there is an ajax call to read the messages files. Well, as you probably know, Cross-Domain XMLHttpRequest Calls are forbidden in ajax due to the browsers restrictions.
Could I trouble you and test a suspicion of mine?
Replace your first line with:
$(document).ready(function() {loadMessage()});
Also, I note that https://static.unifiedpost.com/apps/myup/customer/upmail/upmail_messages/up_mail_messages.properties returns a 404 error, while the en version works well. Is this intentional?
i don't know what is you server return, so in php i just echo something like this :
$arg = 'up.mail.test=messages loaded from en';
exit($arg);
then the js :
.......
callback: function() {
var messageKey = up.mail.test;
//alert(eval(messageKey));
jQuery('#customMessage').html(jQuery.i18n.prop(messageKey));
}
i got this : [messages loaded from en] . is this what you want ?