Can't add js and css files to back office - javascript

I want to add JS and CSS files to back office in my module. But I get error: Attempted to call an undefined method named "registerStylesheet" of class "AdminModulesController".
I've seen other posts (like this Show my module JS at footer in prestashop) or here https://devdocs.prestashop.com/1.7/themes/getting-started/asset-management/
So I want to avoid addJS() function as this is depreciated. But when I try to use $this->context->controller->registerStylesheet() and $this->context->controller->registerJavascript() I get the above error.
This is my whole hook code:
public function hookActionAdminControllerSetMedia($params)
{
$this->context->controller->registerStylesheet(
'mb_pages_content',
'modules/'.$this->name.'/styles/admin.min.css'
);
$this->context->controller->registerJavascript(
'mb_pages_content',
'modules/'.$this->name.'/js/admin.js'
);
}
I've checked what kind of thing is my: $this->context->controller
but it doesn't indeed have registerStylesheet() and registerJavascript() methods. What am I missing? i do everything exactly as described everywhere in the internet, why do I get the error?

The explanation of which methods to use:
These are FrontController methods in PrestaShop 1.7: registerJavascript and registerStylesheet.
These are legacy (deprecated) FrontController methods in PrestaShop 1.7: addJS and addCSS.
These are AdminController methods in PrestaShop 1.7, 1.6, 1.5: addJS and addCSS.
So, the correct example to add a JS and a CSS files for a back-office (i.e. for AdminController) via a module class is:
public function hookActionAdminControllerSetMedia($params)
{
// Adds your's CSS file from a module's directory
$this->context->controller->addCSS($this->_path . 'views/css/example.css');
// Adds your's JavaScript file from a module's directory
$this->context->controller->addJS($this->_path . 'views/js/example.js');
}
For an additional information see my yet another answer how to register JavaScript in a back-office (in admin pages). I have updated it after this question.

Try with :
$this->addJs(
_PS_MODULE_DIR_ .'objet/views/js/feature.js',
'all'
);
$this->addCss(
_PS_MODULE_DIR_ .'objet/views/css/feature.css',
'all'
);
Regards

Related

Can only have one anonymous define call per script file

I'm creating monaco editor using loader.js but getting the error "Can only have one anonymous define call per script file" 2 times in console.
<script src="/monaco-editor/min/vs/loader.js"></script>
Code to create editor
require.config({ paths: { 'vs': '/monaco-editor/min/vs' }});
require(['vs/editor/editor.main'], function() {
monacoEditor= monaco.editor.create(document.getElementById('coding-editor'), {
value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'javascript'
});
});
I tried to search the issue and found below related answer:
Some piece of code that you are loading is invoking define with an anonymous module id. You could:
load that code through the AMD loader (i.e. manually require it) such that the AMD loader creates the <script> tag.
load that code before the AMD loader (i.e. define will not be available to that piece of code)
unset define for the duration of evaluation of that script (i.e. if you load it with a <script> tag, then unset define before and restore it afterwards)
try to unset define.jquery, AFAIK jquery might be checking for that on the define function
This page has lot of jquery already and I understand this because of jQuery. Please help some to make me understood by example. Thanks
I had the same issue this morning and I applied the second solution.
load that code before the AMD loader (i.e. define will not be available to that piece of code)
This works because define is being called from inside jQuery anonymously, as the error says. Explained further in the require.js website, which happens to use loader function (define, require) similar to loader.js.
In my case I simply made sure to include my loader after jQuery so the defines don't collide.
I had tried to create script by tags, but got aler:'Can only have one anonymous define'
So I just overwrite it :
this.temp_define = window['define'];
head.appendChild(loaders);
window['define'] = undefined;

How can I access a service in config function or access a provider inside a service

I need to configure angular bootstrap tooltip (uibTooltip) to be disabled for mobile devices when using angular-bowser for device detection.
This could be done simply by:
isMobile = _bowser.mobile
$uibTooltipProvider.options = { trigger: isMobile ? "none" : "mouseenter" }
Problem: $uibTooltipProvider is a provider and bowser is a service.
I have to use $uibTooltipProvider in a config function while I can't use bowser service in a config function. And neither I can use $uibTooltipProvider in a run function where I can use bowser
I have already tried overriding the $get function as they suggest here but the "ontouchstart" event in $window does not apply for tablets where I want to keep tooltips enabled.
Is there any way I can get a workaround this?
I finally decided to inject a small css modification in run time. I had the three following options:
1. Use that hack on GitHub: I did not like the fact that in order to make it work I had to empirically (by placing a breaking point) find out which were the actual services injected in the $get function of the uibTooltipProvider. (see there is a difference between the services injected in the github thread and the ones I had to inject (see code snippet)
2. Add the bowser library and use it statically: I did not like this option because we are already using angular-bowser as a dependency for our DeviceDetector service, so we would be using the same library twice: one statically to configure the tooltip options and one in runtime for everything else.
3. Inject a small css modification (the option I chose):
public disableTooltipsForTouchScreen(): void {
if ( this._deviceDetector.isMobile() || this._deviceDetector.isTablet() ) {
let styleSheet = document.createElement("style");
styleSheet["innerHTML"] = ".tooltip { display: none; }";
document.body.appendChild(styleSheet);
}
}
And if we ever need to have a finest control over the bootstrap-tooltip configuration then I will consider option 2.

Autoloading Javascript

I have a interesting concept I was working on and looking over, through various stack questions on auto loading JavaScript. I dint want to use a third party tool, aside form jquery, so I thought I would role my own. The concept I have is:
var scripts = {
'name' : 'path/to/script_dir/' // Load all scripts in this file.
}
requireScripts(scripts); // Requires all scripts
// Call your classes, methods, objects and so on ....
The requireScript() function would work something like:
function requireScript(hash){
$.each(hash, function(key, value)){
$.ajax({
url: value,
dataType: "script",
async: false,
error: function () {
throw new Error("Could not load script " + script);
}
});
});
}
Note: The above is just a concept, I don't think it will work.
The above would let you load SPECIFIC scripts. so in essence your hash key value would be 'name' : 'path/to/specific/script'. The issue this posses is that your hash would get rather large ....
The other issue I ran into is what if I simplified this to "php pear naming standard" so, as the trend seems to be - we would create a class, and it would be named after its location:
var some_folder_name_class = function(){}
Would be translated by the autoloader as: some/folder/name/class.js and then loaded that way.
To wrap up and get to my point there are two ways of loading javascript file I am looking at, via rolling my own "require" method. One is loading a directory of javascript files via the hash idea implemented above. (the provided code sample of how this hash would be walked through would have to be changed and fixed....I dont think it works to even load a single file)
OR
to have you just do:
new some_class_name() and have a global function listen for the new word, go find the file your trying to call based on the name of the class and load it, this you never have to worry - as long as you follow "pear naming standards" in both class and folder structure your js file will be loaded.
Can either approach be done? or am I dreaming to big?
I see a lot of frameworks do a bunch of require('/path/to/script') and if I could role my own autoloader to just allow me to either load a directory of js files or even have it where it listens for new before a class instantiation then I could make my life SO MUCH easier.
Have you consider using requirejs and probably Lazy loading.
http://www.joezimjs.com/javascript/lazy-loading-javascript-with-requirejs/
Here is sample version:
You can download here.
The sample is based on this folder structure :
public
index.html
scripts
app.js
lib
** jquery-1.10.2.js
** require.js
3 . From Code:
html
`<!DOCTYPE html><html>
<head><title>Sample Test</title>`
<script src="scripts/lib/require.js"></script> <!-- downloaded from link provide above-->
<script src="scripts/app.js"></script></head>
`<body><h1>My Sample Project</h1><div id="someDiv"></div></body></html>`
application configuration app.js
requirejs.config({
baseUrl: 'scripts',
paths: {
app: 'app',
jquery: 'lib/jquery-1.10.2' //your libraries/modules definitions
}
});
// Start the main app logic. loading jquery module
require(['jquery'], function ($) {
$(document).on('ready',function(){
$('#someDiv').html('Hello World');
});
});
jQuery-only option
If you are looking for a jQuery-only solution, have a look at jQuery.getScript(). It would be a great candidate for handling the script loading portion of your problem. You could then write a very small wrapper around it to load all the scripts—something like you wrote above:
var loadScripts = function(scripts) {
$.each(scripts, function(name, path) {
jQuery.getScript("/root/path/" + path + ".js");
})
}
If you are interested in more information on this approach, read this article by David Walsh.
Other great libraries
I strongly recommend taking a look at the current batch of script-loading libraries. I think that you will pleasantly surprised by what is out there. Plus, they come with the benefit of great community support and documentation. RequireJS seems to be the front runner but David Walsh has great articles on curl.js and LABjs.

Make RequireJS place class on script tags it creates?

I've noticed that RequireJS creates script tags in the tag as it loads modules.
Is there anyway to configure RequireJS to "tag" those elements w/ a class or an attribute of some kind that I could later target w/ jQuery later on?
e.g.:
var $requireJsScripts = $('script.require-script');
--UPDATE--
Ok.. I think I can get by on this little workaround for now. Thanks to this answer for the breadcrumb on require.s.contexts._.defined. I'd still like to hear if anyone knows of a way to configure RequireJS to do something similar to what was laid out in the original question...
var loadedRjsModules = Object.keys(require.s.contexts._.defined);
var $scripts = $('script');
$scripts.each(function () {
if ($(this).data('requiremodule') && $.inArray($(this).data('requiremodule'), loadedRjsModules)) {
console.log(this);
}
});
Looking at the source code, I don't see how RequireJS would allow adding anything custom to the script nodes at creation. The routine that creates them has no provision for it. The code that fleshes them out upon creation does not support it either.
There's an onResourceLoad hook considered part of the internal API. It could be used with the code you've put in your question instead of relying on require.s.contexts._.defined, which as far as I know is fully private and subject to change without notice.

TypeScript Intellisense and jQuery problems

I am using VS 2012 and TypeScript with jquery. I am converting an existing JS app into TS and I have the following problem :
$(window).load(function () {
//stuff
});
$(window).load got underlined and error is 'supplied parameters do not match any signature of call target'.
I am using jquery 1.7.2 with this jquery.d.ts jquery ts annotations.
I added the reference link on top of the file.
What am I doing wrong ?
Edit :
I have got typescript installed in VS of course, and it doesn't change anything to edit the argument, it can be "window" or anything else, it keeps making the error.
The definition of load() it expects is (url:string, data: any, complete: any) while in jQuery doc it's just a function..
The Typescript definition only contains the definition for 1 particular version of the load function, the one that loads html from a url http://api.jquery.com/load/. Typescript is still in alpha don't forget.
This shouldn't affect your use of Typescript, except you will continue to receive the warning.
As an alternative you could change your code to something like the following:
$(window).on("load", function() {
/// so stuff
});

Categories