Zend headScript() and appendFile not working as expected - javascript

I'm having an issue trying to append a javascript file using headScript()->appendFile('file name') with Zend. I have my layout setup like this:
<?= $this->headScript()
->prependScript( 'BASE_URL = "' . $this->baseUrl() . '";' )
->appendFile( $this->baseUrl('js/lib/jquery/jquery-1.4.2.min.js') )
->appendFile( $this->baseUrl('js/admin.js') );
?>
Then, in my controller I am trying to append an additional js file only for this page, like:
$this->view->headScript()->appendFile( 'another/js/file.js' );
This file needs to be appended to what is already setup in the layout. However, this file gets added before the other 'appendFile' files. I've also tried
$this->headScript()->offsetSetFile(999, '/js/myfuncs.js');
But this still adds the file before the other files. This is not how I would expect this to work, especially when using the offsetSetFile method. How can I add this file after the other files? Thanks.

The answer is to use headScript()->prependFile in layout.phtml and headScript()->appendFile in a view.

I know it's a late answer but!
If you do appendFile or appendScript is uses the next available index. Thus
$this->headScript()->offsetSetFile(50, 'file');
$this->headScript()->appendFile('file2');
is equivalent to
$this->headScript()->offsetSetFile(50, 'file');
$this->headScript()->offsetSetFile(51, 'file2');
Also it is key to note that the controller code get executed first before the view/layout code. Thus in your case your appends are actually using the id's 1000, and 1001. A quick fix to this is just to explicitly use offsetSetFile for all your appends. So your code in your layout would look like:
<?=
$this->headScript()
->prependScript( 'BASE_URL = "' . $this->baseUrl() . '";' )
->offsetSetFile(500, $this->baseUrl('js/lib/jquery/jquery-1.4.2.min.js') )
->offsetSetFile(501, $this->baseUrl('js/admin.js') );
?>
I hope this helps future googler's

I've noticed that if I 'prepend' all the files in the layout, I can then use appendFile in my controller and it will appear after them. Unfortunately, then I have to list all my JS files in reverse order in the layout (since they prepend to themselves). I'd really like to keep things in order and just be able to append to my layout stack.

If prepending in the layout file is not good enough, you can either include the files in your bootstrap when you set up your view or you could set up a controller plugin if you need to prepend based on what module is being loaded.
// in your bootstrap
protected function _initHeadScript()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$view->headScript()->appendFile('another/js/file.js');
}
// as a plugin
class My_Plugin_HeadScriptPlugin extends Zend_Controller_Plugin_Abstract
{
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$view = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->view;
if($request->getModuleName() == 'foo')
{
$view->headScript()->appendFile('another/js/file.js');
}
}
}

Actually, you don't need get the baseUrl 'cause ZF already does it for you. You just have to pay attention to your path. Do not use the first slash! otherwise ZF will return the remote address.
Just use '$this->_view->headLink()->appendStylesheet('css/main.css');'

http://zendframework.com/issues/browse/ZF-3282?focusedCommentId=23552&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-23552
the last comment gives an excellent solution, first include in the layout at top, then print when you need it, this way it will work

Related

How to deal with DOM elements?

I am learning about writing custom JavaScript for my Odoo 10 addons.
I've written the following piece of code:
odoo.define('ioio.io', function(require) {
'use strict'
const e = $('div.o_sub_menu_footer')
console.log('--testing--'.repeat(7))
console.log(e)
// the "Powered by Odoo" down the secondary menu
e.remove()
})
The code is well loaded and I can see my testing string in the console.
However when this code is being loaded before the target div, so e empty/not yet filled and thus its content is not removed.
Doing it manually from the console works.
My question is what is the right way to do that? And how to know exactly when the code gets executed?
You can
put your html code before the script tag in your file
use jQuery $(document).ready(...);
Place your script at the bottom of the <body> tag to make sure the DOM renders before trying to manipulate it.
This is an Odoo specific question, so you should use the Odoo standard way, which is via its base JS class. That class contains a ready() method which does exactly what you need.
In your case, to use that function, you need to require the class first. Then you can use ready().
Updating your code, it should look like this:
odoo.define('ioio.io', function(require) {
'use strict'
// require base class
var base = require('web_editor.base');
//use its ready method
base.ready().done(function () {
// put all the code you want to get loaded
// once the DOM is loaded within this block
const e = $('div.o_sub_menu_footer')
console.log('--testing--'.repeat(7))
console.log(e)
// the "Powered by Odoo" down the secondary menu
e.remove()
});
})
While your accepted answer leads to the same outcome, you might want to update it to this one since this is the Odoo way. It's generally advised to work within the Odoo framework as much as possible and customise only if really needed. (Though it can be tough to learn what features Odoo already provides because of its poor documentation.)

How to resolve 404 error using CodeIgniter?

CSS and jquery does not applied in codeigniter. And it give
error 404 not found
I have tried to load all the class of bootstrap. I used css property.
I strongly suggest building yourself a helper for including your assets so you don't need to keep referring back by direct path with each asset.
You are calling within the controller not outside of it, when I call this stuff I tend to use site_url() and call directly to the public assets folder from this, eg:
siteurl('assets/css/style.php')
This would find, for example: http://localhost/assets/css/style.php
an example of using this in a helper would be a function like:
function assets($var)
{
$CI =& get_instance();
$CI->load->helper('url');
return site_url('assets') . '/' . $var;
}
With this and the helper autoloaded, you could then just call assets('path/inside/assets/folder/')
Use ../../../img/your_imgName in your CSS file

Grunt-injector - Inject parent directories first

I'm using grunt-injector and I have a list of files being injected using 'app/**/*.js but I don't want to inject the files alphabetically as it is causing dependency errors. I want to systematically inject the files in the parent directory, then move to the next level and inject those files and so on. This way I will inject all the parent files first and remove any dependency issues.
Can anyone help to do this? I've tried looking at grunt-include-source as it includes a top-down file sort which is what I want but I was unable to get that working and I'd rather stick with injector as its used heavily at the moment.
I had the same problem, so I had to do changes in the injector.js script (node_modules/grunt-injector/tasks/injector.js).
You have to do:
1.- looking for the comment "Sort files if needed" and add an else case:
else {
//parent dir's files go first.
if (options.parentDirFirst) {
sources.sort(function (a, b) {
return a.file.split("/").length - b.file.split("/").length;
});
}
}
2.- in your gruntfile.js you have to set the option parentDirFirst to true:
injector: {
options: {
parentDirFirst: true,
.
.
.
},
.
.
.
}
these changes could be sent to Joakim Bengtson. He needs contributors to maintain the plugin, he's looking for people who want to help out and be contributors, but I don't have enough time.

Adding a variable into a page - wordpress

When I create pages within Wordpress, the call to action links on those pages always have the same URL. I want to be able to globalize this variable but am struggling to find a good way to do it.
If I were making simple PHP pages I could simply include e.g.
$URLpath = "http://example.com/my/page";
Then call this in the html:
Call to action
Obviously I can't do this within the Wordpress CMS as it renders as <?=$URLpath?>
I could add, say, Call to action and replace after the page loads using javascript replace over the whole block of html, but it doesn't feel efficient to do this.
Is there a better way? I'm pretty new to Wordpress.
You can add a shortcode in your functions.php file that prints your cta, or better create a plugin with some parameter that manages this link.
For example in functions.php you could add
function cta_func( $atts ){
$URLpath = "http://example.com/my/page";
return 'Call to action';
}
add_shortcode( 'cta', 'cta_func' );
inside your pages/post you can write simply this shortcode.
...
[cta]
...
Further infos about shortcodes are in the reference of codex
https://codex.wordpress.org/Shortcode_API
A good way to do this within WordPress is to use their wp_localize_script()
In your functions.php file you could use as:
// For sake of example I will put your data inside an array,
// but you can set a single value.
$dataForJS = array(
$URLPath => "http://example.com/my/page"
);
// wp_localize_script() takes 3 parameters:
// 1. Name of the registered script, this is the name you used in wp_register_script()
// here I am naming it "main" but it can be anything.
// 2. Name of the variable.
// This name is then available in your JS and will contain your data.
// 3. The data you want to pass, it can be a single value or array
wp_localize_script( 'main', 'd', $dataForJS );
In your JavaScript, you will be able to access this data by just calling the variable d.
What this does is that if the page requests the "main" script, WordPress will add a script tag with your data inside it and makes sure it is placed before your "main" script runs.

Drupal 7 override jquery js file in custom theme

Is it possible to rewrite/override a default Drupal 7.26 jquery used in custom template scripts variable ?
I mean one of the js files:
<script type="text/javascript" src="http://drupal.dev/misc/jquery.js?v=1.4.4"></script>
by one which comes by custom theme ?
I tried this in sites/all/MYTPL/template.php but it doesn't work:
$scripts['misc/jquery.js']['data'] = $base_theme . '/js/packages/jquery-2.1.0.min.js';
I would like to know if someone managed it without using any modules such as jQuery Update ?
=== UPDATED ===
Actually I solved it by help of accepted answer with some modifications based on #cojomojo 's answer:
function THEMEname_js_alter(&$javascript) {
// Swap out jQuery to use an updated version of the library.
$javascript['misc/jquery.js']['data'] = drupal_get_path('theme', 'THEMEname') . '/js/packages/jquery-2.1.0.min.js';
}
Use this code inside your theme's template.php file, in hook_js_alter.
function [YOUR_THEME]_js_alter(&$js)
{
$jqKey = "my-new-jquery"; // a key for new jquery file entry
$js[$jqKey] = $js['misc/jquery.js']; // copy the default jquery settings, so you don't have to re-type them.
$js[$jqKey]['data'] = "https://code.jquery.com/jquery-2.1.0.min.js"; // the path for new jquery file.
$js[$jqKey]['version'] = '2.1.0'; // your jquery version.
unset($js['misc/jquery.js']); // delete drupal's default jquery file.
}
So you have a few options to do this. Here they are:
You can use hook_js_alter like so:
<?php
function hook_js_alter(&$javascript) {
// Swap out jQuery to use an updated version of the library.
$javascript['misc/jquery.js']['data'] = drupal_get_path('module', 'jquery_update') . '/jquery.js';
}
?>
Or in order to avoid breakage like 2pha mentioned you can run two versions of jquery side by side. jQuery already has the functionality to run along side a different version of jQuery (or, really, along side any other JavaScript library that uses the $ symbol as a function or variable). This is the noConflict() function. You can view the API page here: http://api.jquery.com/jQuery.noConflict/
To use this functionality within your project, simply tell the browser about your new jQuery library and that you'll be referencing it via your custom noConflict identifier. Here is an example of how you would implement this in a custom theme.
MyTheme/page.tpl.php
<head>
<title><?php print $head_title; ?></title>
<?php print $head; ?>
<?php print $styles; ?>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
var $jq = jQuery.noConflict();
</script>
<?php print $scripts; ?>
</head>
Another possible method is to swap jQuery with the preprocess page like so:
<?php
function yourModuleOrThemeName_preprocess_page(&$variables) {
// exclude backend pages to avoid core js not working anymore
// you could also just use a backend theme to avoid this
if (arg(0) != 'admin' || !(arg(1) == 'add' && arg(2) == 'edit') || arg(0) != 'panels' || arg(0) != 'ctools') {
$scripts = drupal_add_js();
$new_jquery = array(drupal_get_path('theme', 'YOURTHEME') . '/js/jquery-1.7.1.min.js' => $scripts['core']['misc/jquery.js']);
$scripts['core'] = array_merge($new_jquery, $scripts['core']);
unset($scripts['core']['misc/jquery.js']);
$variables['scripts'] = drupal_get_js('header', $scripts);
}
}
?>
To me the best method would be to either run two version of jQuery side by side (the version that Drupal 7 uses by default and whatever your theme requires) or swapping jQuery with the preprocess page. The hook_js_alter has potential for breaking anything that requires the different version of jQuery. All the potential ways to do what you ask are here: https://drupal.org/node/1058168
Maybe use the hook hook_js_alter.
Keep in mind though that other modules will depend on jQuery and if they use something that has changed between versions, you may encounter problems.

Categories

Resources