i'm adding onchange handler to all cck fields by following manner.
function bday_form_event_node_form_alter(&$form, &$form_state) {
$form['title']['#attributes'] = array('onchange' => "titleval()");
$form['#after_build'][] = 'bday_form_event_node_form_cck_alter';
}
function bday_form_event_node_form_cck_alter($form, &$form_state) {
$form['field_date1'][0]['value']['#attributes'] = array('onchange' => "dateval()"); //Text Field
$form['field_city']['#attributes'] = array('onchange' => "cityval()"); //Select Field
}
But Onchange handler for Select is not added to the dom .
Building a little on what googletorp said.
This is not the way to add behaviours to forms in drupal.
There is a very nice JS api that comes with drupal which can aid you in doing this.
Roughly what you would want is something like this.
Drupal.behaviors.myModuleBehavior = function(context) {
$('.title').change(function() {titleval() }) ;
$('.field_date1').change(function() {dateval()});
$('.field_city').change(function() {cityval()});
}
Related
I use FullCalendar in a site of mine:
I'd like to restrict the content of 'Select Language' dropdown list to specific entries (let's say English, French and Finnish).
I couldn't find how to do that.
Any help?
As I said to #ADyson, I use FullCalendar implemented by a Drupal module.
Finally, I updated this piece of code in fullcalendar_view.js
adding if (localeCode=="en" || localeCode=="fi" || localeCode=="fr") {
if (drupalSettings.languageSelector) {
// Build the locale selector's options.
$.each($.fullCalendar.locales, function (localeCode) {
if (localeCode=="en" || localeCode=="fi" || localeCode=="fr") {
$('#locale-selector').append(
$('<option/>')
.attr('value', localeCode)
.prop('selected', localeCode == drupalSettings.defaultLang)
.text(localeCode)
);
}
});
// When the selected option changes, dynamically change the calendar option.
$('#locale-selector').on('change', function () {
if (this.value) {
$('#calendar').fullCalendar('option', 'locale', this.value);
}
});
}
and it works!
I have a grid that shows a list of financial arrears grouped by the type of debt, known as Cash Type. These Cash Types can be categorised in a number of ways, or not, which is "Normal". When they are categorised I'm adding a lovely badge in the ClientGroupHeaderTemplate so it stands out to the user. All good so far.
#(Html.Kendo().Grid(Model.Arrears)
.Name("arrearsGrid-" + Model.LeaseId.ToString())
.HtmlAttributes(new { #class = "smallergrid" })
.Columns(columns =>
{
columns.Bound(p => p.InvoiceNumber)
.ClientTemplate("<a class=\"text-primary\" href=\"" + Url.Action("Invoice", "Arrear") + $"/#=InvoiceNumber#?buildingid=#=BuildingId#&leaseid={Model.LeaseId}\" target=\"_blank\">#=InvoiceNumber#</a>");
columns.Bound(p => p.InvoiceDescription);
columns.Bound(p => p.CashType)
.ClientGroupHeaderTemplate("Cash Type: #= getCashTypeName(data.value) # (#= getDebtCategoryName(data.items[0].DebtCategory) #)");
columns.Bound(p => p.InvoiceDate);
columns.Bound(p => p.TransactionDate);
columns.Bound(p => p.DaysOverdue);
columns.Bound(p => p.InvoiceGross)
.HtmlAttributes(new { #class = "text-right" });
columns.Bound(p => p.OutstandingGross)
.HtmlAttributes(new { #class = "text-right" });
})
.Sortable()
.Excel(excel => excel
.FileName("Kendo UI Grid Export.xlsx")
.Filterable(true)
.AllPages(true)
)
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Group(g => g.Add(p => p.CashType))
)
.NoRecords(x => x.Template("<div class='empty-grid'></div>"))
)
The problem is the Export to Excel function does no processing on the ClientGroupHeaderTemplate, and shows<span>Cash Type: Rent <span class="d-print-none badge debt-category-1 ml-2">In Query</span></span> in the spreadsheet.
Here's the options I see are available, and some I've discounted. Are these really the best options I have?
CSS (rejected)
As you can see, using the Bootstrap d-print-none does nothing. From all the posts on Export and hidding columns, it seems that Kendo is in no way using a print view of the page, so #media options aren't going to help.
excelExport event
Use the Kendo excelExport event to customise the generated Excel workbook, however, this example is document creation. If I'm going this route I suspect it might be easier to write one from scratch, rather than workaround Kendo limitations. Either way it's a lot of work to remove 1 line of HTML markup.
Use the ProxyURL
Under a Grids Excel object, you can set an endpoint to call when the Excel spreadsheet is created. This might give the chance to tweak a ready-to-save spreadsheet before it is saved. There's a demo of it here. The demo is wrong (the Controller name is not Grid, it's Excel_Export) and it doesn't work for me even when corrected and the standard .ToolBar(tools => tools.Excel()) back in. Maybe it's because I'm not AJAXing my data in, or maybe it's just as broken as the demo. Changing my grid to AJAX will is not beyond the realms of possibility, but it's not a small job either.
Edit: I got this to hit the event by also adding .ForceProxy(true) to the Excel definition. This isn't mentioned in the demo, and the statement that you need to add .ToolBar(tools => tools.Excel()) is also incorrect; you can fire the event from your own buttons that trigger the Excel export.
Give up and go simple
The last option I have is to give up on the badges and just have text. It's the quickest and surest option, but it's solving the problem by ignoring the problem.
So I managed this in yet another way. I'm sure there must be an MVC answer to this problem though.
I added an event to my Grid
#(Html.Kendo().Grid(Model)
...
.Events(e =>
{
e.ExcelExport("exportExcel");
}
...
)
and created a JavaScript middleware function to alter the Excel file before it is saved. Of course you can then do whatever JS allows you to do at this point.
In the code below are examples of setting a column width (4), removing HTML span markup, and converting a string to a number and adding a currency format to that number (7). The method of obtaining the currency symbol is not pretty, but it's a string inside some HTML markup, I don't think it can be pretty.
function exportExcel(e) {
var sheet = e.workbook.sheets[0];
var lastRow = sheet.rows[sheet.rows.length - 1];
var lastCell = lastRow.cells[lastRow.cells.length - 1];
var lastCellValue = lastCell.value.toString().replace(/<[^>]*>/, "").replace("</span>", "");
var currency = lastCellValue.substring(0, 1);
currency += "#,###,##0.00";
sheet.columns[4].autoWidth = false;
sheet.columns[4].width = 125;
$.each(sheet.rows, function (index, row) {
if (index > 0) {
if (row.cells[0] != undefined) {
if (row.cells[0].value != undefined) {
row.cells[0].value = row.cells[0].value.replace(/<[^>]*>/, "(").replace("</span>", ")");
}
}
if (row.cells[7] != undefined) {
if (row.cells[7].value != undefined) {
row.cells[7].value = row.cells[7].value.toString().replace(/<[^>]*>/, "").replace("</span>", "");
row.cells[7].value = Number(row.cells[7].value.toString().replace(/[^0-9\.-]+/g, ""));
row.cells[7].format = currency; // Why this prepends a backslash to the format I do not know
}
}
}
});
};
Im a Drupal themer and im struggling to modify a module in the way that I need. When something happens I need to run a very simple bit of JavaScript. Ive found the part of the module responsable and the following works:
if (something = something else) {
return array(
'#commands' => array(
// Hacky by works
ajax_command_append('body',
'<script>
alert("Custom Js");
</script>'),
),
);
}
else {
// Do something else
}
However it would be better to call a function that was somewhere else as other modules will want to call it. How can I call a function from another module from within this statement?
You can do it inline, like this
Edit
In my first answer I forgot to wrap the javascript in jQuery(document).ready(function() {})
module
if (something = something else) {
// Inline fixed
drupal_add_js("jQuery(document).ready(function() { alert('Script inline!'); });", "type" => "inline");
// From file
drupal_add_js("myscript.js", "file");
return array(
'#commands' => array(
),
);
}
else {
// Do something else
}
myscript.js
(function() {
alert('Script from file!');
});
// or with jQuery
(function($) {
// Do something with $
})(jQuery);
If you want the javascript code to be in on its own file, do it like that (taken from the examples)
Check out the examples in the documentation
More information on adding javascript to your modules/themes
Adding Javascript to your theme or module
Managing JavaScript in Drupal 7
Edit 2
You can call a javascript function from a module. I would do it like this :
Create a new module that just inject a javascript code. This module should have a lesser weight than any other module so it executes before any of them.
Then call it from any module using Drupal.settings.
Assuming that you created the module, you should save your javascript function into Drupal.settings
(function ($) {
Drupal.settings.exampleModule = {
myFunction : function () {
alert('My example function!');
}
};
}(jQuery));
This will inject that code into settings and will be available to any module which needs to access it.
Your module
if (something = something else) {
// Inline fixed
drupal_add_js("(function($) { Drupal.settings.exampleModule.myFunction(); })(jQuery);", "type" => "inline");
}
else {
// Do something else
}
That's how I would do it. Now, if you need to use the ajax framework you should do something like this (try it, I've never used this framework before, so I'm guessing)
return array(
'#commands' => array(
// Hacky by works
ajax_command_append('body', "(function($) { Drupal.settings.exampleModule.myFunction(); })(jQuery);"),
),
);
For images uploaded using WordPress' media uploader, there is an "Insert Into Post" button that sends a shortcode to the editor for that image.
I have a text input that, when focused, I'd like the media uploader to appear so that the user can select an image and send the file URL to the text input.
The main issue I'm having is creating the additional "Insert Into Post" button that sends the file URL to the appropriate text field.
Which hook do I use for that and how can I get the file URL data returned to the input field?
Your guidance is appreciated!
What you've described is the older Wordpress way of doing it... If you want to use the new uploader in Wordpress 3.5+, you can create a wp.media object to upload it, similar to the code in wp-admin/js/custom-background.js:
// Create the media frame.
frame = wp.media.frames.customBackground = wp.media({
// Set the title of the modal.
title: $el.data('choose'),
// Tell the modal to show only images.
library: {
type: 'image'
},
// Customize the submit button.
button: {
// Set the text of the button.
text: $el.data('update'),
// Tell the button not to close the modal, since we're
// going to refresh the page when the image is selected.
close: false
}
});
// When an image is selected, run a callback.
frame.on( 'select', function() {
// Grab the selected attachment.
var attachment = frame.state().get('selection').first();
// Run an AJAX request to set the background image.
$.post( ajaxurl, {
action: 'set-background-image',
attachment_id: attachment.id,
size: 'full'
}).done( function() {
// When the request completes, reload the window.
window.location.reload();
});
});
// Finally, open the modal.
frame.open();
the frame.on('select' function(){ code is run when a file is chosen.
A litter further searching and I was able to find some good sources explaining how to do this. I went for a JavaScript, PHP mix:
JavaScript
$j('input').live('focusin',function(){
var target = '#'+$j(this).attr('id');
tb_show('','media-upload.php?post_id=[post_id]&tab=gallery&context=choose&TB_iframe=1');
window.send_to_editor = function(html) {
fileurl = $j(html).attr('href');
$j(target).val(fileurl);
tb_remove();
};
});
source: http://jaspreetchahal.org/wordpress-using-media-uploader-in-your-plugin/
PHP
/* Customize button */
function media_uploader_btn($form_fields, $post) {
$send = "<input type='submit' class='button' name='send[$post->ID]' value='" . esc_attr__( 'Choose This File' ) . "' />";
$form_fields['buttons'] = array('tr' => "\t\t<tr class='submit'><td></td><td class='savesend'>$send</td></tr>\n");
$form_fields['context'] = array( 'input' => 'hidden', 'value' => 'choose' );
return $form_fields;
}
/* Check for button context */
function check_upload_image_context($context){
if(isset($_REQUEST['context']) && $_REQUEST['context'] == $context){
return true;
} elseif(isset($_POST['attachments']) && is_array($_POST['attachments'])){
/* check for context in attachment objects */
$image_data = current($_POST['attachments']);
if (isset($image_data['context']) && $image_data['context'] == $context ){
return true;
}
}
return false;
}
if(check_upload_image_context('choose')){
add_filter('attachment_fields_to_edit', 'media_uploader_btn', 20, 2);
}
source: http://shibashake.com/wordpress-theme/how-to-hook-into-the-media-upload-popup-interface
I am using #ajax in submit button of a form created using FAPI. Now when user submits the form, I want to run some jQuery validation before the form is submitted through ajax. As #ajax prevents events related to submit button such as submit, click, mousedown, keypress etc. I am not able to catch submit event using jQuery.
For now as a workaround, I have added custom code in ajax.js (misc/ajax.js) :
Drupal.ajax = function (base, element, element_settings) {
...
beforeSubmit: function (form_values, element_settings, options) {
//my custom code
alert(1);
...
This is against drupal best practices as I am hacking the core. Please any one can help me to do the same from my custom js file or any other approach to validate the content before ajax submit.
I think the accepted answer on the following post answers your question: How to extend or "hook" Drupal Form AJAX?
(function($) {
Drupal.behaviors.MyModule = {
attach: function (context, settings) {
// Overwrite beforeSubmit
Drupal.ajax['some_element'].options.beforeSubmit = function (form_values, element, options) {
// ... Some staff added to form_values
}
//Or you can overwrite beforeSubmit
Drupal.ajax['some_element'].options.beforeSerialize = function (element, options) {
// ... Some staff added to options.data
// Also call parent function
Drupal.ajax.prototype.beforeSerialize(element, options);
}
//...
i put this in the attach function
for (var base in settings.ajax) {
Drupal.ajax[base].options.beforeSubmit = function(form_values, element, options){
console.log('call your func');
}
}
it works!