I have two custom fields that use wp_editor() on a WordPress custom post type, which basically embeds an iframe where the content is. I'm trying to capture when someone tries to change one of the values, which I'm learning requires the addEventListener function with the keydown approach.
My problem is that I keep getting an error saying the iframe is null or tinyMCE is undefined. My script works fine in the console, but if I add it from my plugin it won't work. I'm assuming it's a loading issue? But how do I force the JavaScript to not load until after the iframe content or tinymce?
// Fields from metabox:
$pf = 'eri_post_field_';
$meta_keys = [ $pf.'part_email_msg_pre', $pf.'part_email_msg_post' ];
foreach ($meta_keys as $meta_key) {
$meta_value = get_post_meta( $post_id, $meta_key, true );
$settings = array( 'media_buttons' => false, 'textarea_rows' => 10, 'textarea_name' => $meta_key );
wp_editor( $meta_value, $meta_key, $settings );
}
// JavaScript underneath the fields
echo '<script>
var saveNotice = document.getElementById("part_email_save_notice");
var saveNoticeHide = document.getElementById("part_email_save_notice_hide");
var emailMessageFields = [
"part_email_msg_pre",
"part_email_msg_post"
];
emailMessageFields.forEach(function callback(value, index) {
var iframeId = "'.$pf.'" + value + "_ifr";
var iframe = document.getElementById(iframeId);
console.log(iframe); // <-- NULL
// ERROR: Cannot read properties of null (reading "contentWindow")
// var editor = iframe.contentWindow.document.getElementById("tinymce");
// editor.addEventListener("keydown", function (e) {
// saveNotice.style.display = "block";
// saveNoticeHide.style.display = "none";
// console.log("Run: " + value);
// }, { once: true });
// ERROR: Uncaught TypeError: Cannot set properties of null (setting "onload")
document.getElementById(iframeId).onload = function() {
var editor = iframe.contentWindow.document.getElementById("tinymce");
editor.addEventListener("keydown", function (e) {
saveNotice.style.display = "block";
saveNoticeHide.style.display = "none";
console.log("Run: " + value);
}, { once: true });
};
// ERROR: Uncaught ReferenceError: tinymce is not defined
// tinymce.init(...);
});
</script>';
I also tried to insert the JavaScript from add_action('admin_footer'...), but that didn't make a difference. Tried admin_enqueue_scripts as well. Any suggestions?
Related
I am upgrading my site. I upgraded to AngularJS v1.7.6 and JQuery v1.12.1
I get this error message in my console log.
TypeError: Cannot read property 'CustomerId' of undefined
All I did was change .success to .then as .success was depreciated.
Here is the code where I made the change. So I believe data[0] is null so there is no property CustomerId. This function would work with my older version of jquery and angular with the method of .success instead of .then
I am not sure what to do to fix this...(going in circles here)
$scope.sessionDetails = function () {
urlService.dataProvider(sessionMethod, "POST", '').then(function (data) {
$scope.sesCustomerId = data[0].CustomerId;
$scope.sesToken = data[0].Token;
$scope.sesCustomerName = data[0].CustomerName;
$scope.sesUserIsMember = data[0].IsMember;
$scope.userEmail = data[0].Email;
var indexFavUrl = wLArray.indexOf("Favourites");
if (wLArray[indexFavUrl] == "Favourites") {
if ($scope.sesCustomerId != '') {
//Getting User Favourite Items with customer Id
$scope.GetFavouriteItems($scope.sesCustomerId);
}
}
/* To Open Popup after login */
if (sessionStorage.getItem("CustomPro") == "fromCompse") {
if (!sessionStorage.getItem("UMBID")) {
var cprt = window.location.search.split("=")[1];
var isprodmemonly = window.location.search.split("=")[2];
}
else {
var cprt = sessionStorage.getItem("UMBID");
var isprodmemonly = sessionStorage.getItem("UMBID_IsMem") == "true" ? true : false;
}
show();
if ($scope.sesUserIsMember != "1" && isprodmemonly) {
jAlert('This Product is only for members.');
sessionStorage.removeItem("CustomPro");
return false
} else {
$scope.ProductCompose(cprt, '', cprt, isprodmemonly);
}
}
});
}
$scope.sessionDetails();
for jQuery you need to replace .success() with .done() and not .then()
I have a custom posttype with a metabox that can add posts with editors to the post. whenever I add a new post with an editor I want to save the content of that editor. It has worked fine previously but has now stopped working. I can see that there are some changes in the wordpress update 4.8 to the editor api, but I can't see how the changes affect my code.
Making the editor:
<?php
public function wldk_elearn_add_elements_to_metabox($subpage_id){
$parent_id = $subpage_id;
echo '<div id="element_data_input_text">';
<?php
$settings = array( 'textarea_name' => 'mycustomeditor_'.$parent_id );
$editor_id = 'mycustomeditor_'.$parent_id;
wp_editor( "", $editor_id, $settings );
echo '</div>';
}
Javascript
function handleAddElementAction() {
$('.wldk-elearn-add-element').click(function (event) {
event.preventDefault();
var $wrapper = $(this).parents('#wldk-elearn-new-element');
var $subpage = $wrapper.find('input[name=subpage_id]');
var $type = $wrapper.find('input:radio[name=element_type]:checked');
var subpage = $subpage.val();
var content = '';
var whichmceditor = 'mycustomeditor_'+subpage;
console.log(whichmceditor);
if($type.val()=='tx'){
content = tinyMCE.editors[whichmceditor].getContent();
}
});
}
Uncaught TypeError: Cannot read property 'getContent' of undefined
i have also tried
content = tinyMCE.get(whichmceditor).getContent();
Which just gives me
Uncaught TypeError: Cannot read property 'getContent' of null
Its like tinyMCE methods don't exist anymore or something. I am not very good at this so any help or clue would be apreciated greatly.
So i figured it out! It was simply that the editor must be in visual mode in order to get the editor. A simple conditional fixes the issue:
function handleAddElementAction() {
$('.wldk-elearn-add-element').click(function (event) {
event.preventDefault();
var $wrapper = $(this).parents('#wldk-elearn-new-element');
var $subpage = $wrapper.find('input[name=subpage_id]');
var $type = $wrapper.find('input:radio[name=element_type]:checked');
var subpage = $subpage.val();
var content = '';
var whichmceditor = 'mycustomeditor_'+subpage;
console.log(whichmceditor);
if($type.val()=='tx'){
if($wrapper.find('#'+whichmceditor).is(':visible')){
content = $wrapper.find('#'+whichmceditor).val();
}else{
content = tinyMCE.editors[whichmceditor].getContent();
}
}
});
}
That's 3 hours of my life wasted, Maybe the documentation could be clearer, maybe it's me, maybe it's maybeline.
I have two fields in my module called: rules_name_c which is a text field and rules_author_c which is a relate field.
These fields are not mandatory fields however when i enter data into the rules_name_c field I would like to make it so the rules_author_c must be filled in to complete the record.
I have tried the following:
<?php
$dependencies['conn_connection']['required_author'] = array(
'hooks' => array("edit"),
'trigger' => 'true', //Optional, the trigger for the dependency. Defaults to 'true'.
'triggerFields' => array('rules_name_c'),
'onload' => true,
//Actions is a list of actions to fire when the trigger is true
'actions' => array(
array(
'name' => 'SetRequired',
//The parameters passed in will depend on the action type set in 'name'
'params' => array(
'target' => 'rules_author_c',
'label' => 'rules_author_c_label',
'value' => 'not(equal($rules_name_c, ""))',
),
),
),
);
?>
I believe this solution will not work as this only functions when editing a record. Is that correct?
I have also tried using:
<?php
require_once('include/MVC/View/views/view.edit.php');
/*
* replace UT_Blogs with the module your are dealing with
*/
class conn_connectionViewEdit extends ViewEdit {
public function __construct() {
parent::ViewEdit();
$this->useForSubpanel = true; // this variable specifies that these changes should work for subpanel
$this->useModuleQuickCreateTemplate = true; // quick create template too
}
function display() {
global $mod_strings;
//JS to make field mendatory
$jsscript = <<<EOQ
<script>
// Change rules_author_c to the field of your module
$('#rules_name_c').change(function() {
makerequired(); // onchange call function to mark the field required
});
function makerequired()
{
var status = $('#rules_name_c').val(); // get current value of the field
if(status != ''){ // check if it matches the condition: if true,
addToValidate('EditView','rules_author_c','varchar',true,'{$mod_strings['LBL_RULES_AUTHOR']}'); // mark rules_author_c field required
$('#description_label').html('{$mod_strings['LBL_RULES_AUTHOR']}: <font color="red">*</font>'); // with red * sign next to label
}
else{
removeFromValidate('EditView','rules_author_c'); // else remove the validtion applied
$('#rules_author_c_label').html('{$mod_strings['LBL_RULES_AUTHOR']}: '); // and give the normal label back
}
}
makerequired(); //Call at onload while editing a Published blog record
</script>
EOQ;
parent::display();
echo $jsscript; //echo the script
}
}
I wrote this javascript function and later on I use it with jQuery:
function lxValidateCRMfield(form_name, field_name, label, validate, fnCallerName = "") {
fnCallerName = (fnCallerName != "") ? "(Function " + fnCallerName + ")" : "";
if (validate) {
console.log("lxValidateCRMfield adding validation on form " + form_name + " to field " + field_name, fnCallerName);
//addToValidate is defined somewhere on suitecrm
addToValidate(form_name, field_name, 'varchar', true, "Falta campo requerido: " + label);
$('#' + field_name + '_label').html(label + ': <font color="red">*</font>');
} else {
console.log("lxValidateCRMfield removing validation on form " + form_name + " to field " + field_name, fnCallerName);
//removeFromValidate is defined somewhere on suitecrm
removeFromValidate(form_name, field_name);
$('#' + field_name + '_label').html(label + ': ');
}
}
Then you call it on the form you need to (using your fields it could look like this):
// List all forms available
console.log(document.forms);
// select one you need
var form_name = 'EditView'; eg: EditView, DetailView, search_form
var module = 'YourModule'; // eg: Opportunities
var crmEditView = document.forms[form_name];
if (crmEditView.module.value == module) {
if ($('#rules_name_c').val() != '') {
lxValidateCRMfield(form_name, 'rules_author_c', 'Author', true, 'optionalNameOfFunctionYourCallingThis');
} else {
lxValidateCRMfield(form_name, 'rules_author_c', 'Author', false, 'optionalNameOfFunctionYourCallingThis');
}
}
I hope it helps
Regards
Uncaught ReferenceError: safetxt is not defined
I am trying to build a video and text chat web app using pubnub with their webrtc sdk I would like to know where I went wrong in this code; the video chat works fine - it is when I tried to text that I have the error.
<script src="https://cdn.pubnub.com/pubnub.min.js"></script>
<script src="http://stephenlb.github.io/webrtc-sdk/js/webrtc.js"></script>
<div><script>(function(){
// ~Warning~ You must get your own API Keys for non-demo purposes.
// ~Warning~ Get your PubNub API Keys: http://www.pubnub.com/get-started/
// The phone *number* can by any string value
var phone = PHONE({
number : '7898',
publish_key : 'demo',
subscribe_key : 'demo',
ssl : true
});
// As soon as the phone is ready we can make calls
phone.ready(function(){
// Dial a Number and get the Call Session
// For simplicity the phone number is the same for both caller/receiver.
// you should use different phone numbers for each user.
var session = phone.dial('9365');
});
// When Call Comes In or is to be Connected
phone.receive(function(session){
// Display Your Friend's Live Video
session.connected(function(session){
PUBNUB.$('video-out').appendChild(session.video);
});
});
var chat_in = PUBNUB.$('pubnub-chat-input');
var chat_out = PUBNUB.$('pubnub-chat-output');
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// Send Chat MSG and update UI for Sending Messages
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
PUBNUB.bind( 'keydown', chat_in, function(e) {
if ((e.keyCode || e.charCode) !== 13) return true;
if (!chat_in.value.replace( /\s+/g, '' )) return true;
phone.send({ text : chat_in.value });
add_chat( '7898' + " (Me)", chat_in.value );
chat_in.value = '';
} )
function add_chat( number, text ) {
if (!text.replace( /\s+/g, '' )) return true;
var newchat = document.createElement('div');
newchat.innerHTML = PUBNUB.supplant(
'<strong>{number}: </strong> {message}', {
message : safetxt(text),
number : safetxt(number)
} );
chat_out.insertBefore( newchat, chat_out.firstChild );
}
function message( session, message ) {
add_chat( session.number, message.text );}
})();</script>
safetext() Method
You can find the source listed in the demonstration: https://github.com/stephenlb/webrtc-sdk/blob/gh-pages/index.html#L326-L331
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// XSS Prevention
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
function safetxt(text) {
return (''+text).replace( /[<>]/g, '' );
}
i'm getting the error : Uncaught ReferenceError: errorHandler is not defined at file:
what am i doing wrong? source code: http://pastebin.com/3203ynUB
i iniate the first piece with onclick="startBackup()"
it seems to go wrong somewhere in retrieving data from the database, but i cant figure out how and where.
the database is as following
DBName: SmartPassDB
Table name: SmartPass
rows: id , name , nickName , passID , Website
// change to your database
var db = window.openDatabase("Database", "1.0", "SmartPassDB", 5*1024); // 5*1024 is size in bytes
// file fail function
function failFile(error) {
console.log("PhoneGap Plugin: FileSystem: Message: file does not exists, isn't writeable or isn't readable. Error code: " + error.code);
alert('No backup is found, or backup is corrupt.');
}
// start backup (trigger this function with a button or a page load or something)
function startBackup() {
navigator.notification.confirm('Do you want to start the backup? This will wipe your current backup. This action cannot be undone.', onConfirmBackup, 'Backup', 'Start,Cancel');
}
// backup confirmed
function onConfirmBackup(button) {
if(button==1) {
backupContent();
}
}
// backup content
function backupContent() {
db.transaction(
function(transaction) {
transaction.executeSql(
// change this according to your table name
'SELECT * FROM SmartPass;', null,
function (transaction, result) {
if (result.rows.length > 0) {
var tag = '{"items":[';
for (var i=0; i < result.rows.length; i++) {
var row = result.rows.item(i);
// expand and change this according to your table attributes
tag = tag + '{"id":"' + row.attribute1 + '","name":"' + row.attribute2 + '","nickName":"' + row.attribute3 + '","passId":"' + row.attribute4 + '","website":"' + row.attribute5 + '"}';
if (i+1 < result.rows.length) {
tag = tag + ',';
}
}
tag = tag + ']}';
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
// Change the place where your backup will be written
fileSystem.root.getFile("backup.txt", {create: true, exclusive: false}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.write(tag);
}, failFile);
}, failFile);
}, failFile);
alert("Backup done.");
} else {
alert("No content to backup.");
}
},
errorHandler
);
}
);
}
// start restore (trigger this function with a button or a page load or something)
function startRestore() {
navigator.notification.confirm('Do you want to start the restore? This will wipe your current data. This action cannot be undone.', onConfirmRestore, 'Restore', 'Start,Cancel');
}
// restore confirmed
function onConfirmRestore(button) {
if(button==1) {
restoreContent();
}
}
// restore content
function restoreContent() {
db.transaction(
function(transaction) {
transaction.executeSql(
// change this according to your table name
'DELETE FROM SmartPass', startRestoreContent()
);
});
}
// actually start restore content
function startRestoreContent() {
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem) {
// Change the place where your backup is placed
fileSystem.root.getFile("backup.txt", null, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(evt) {
var data = JSON.parse(evt.target.result);
var items = data.items;
count = items.length;
db.transaction(
function(transaction) {
$.each(items, function(index, item) {
transaction.executeSql(
// change and expand this according to your table name and attributes
'INSERT INTO SmartPass (id, name, nickName, passId, website) VALUES (?, ?, ?, ?, ?)',
[item.attribute1, item.attribute2, item.attribute3, item.attribute4, item.attribute5],
null
);
});
});
};
reader.readAsText(file);
alert("Restore done.");
}, failFile);
}, failFile);
}, failFile);
}
As per the error
error : Uncaught ReferenceError: errorHandler is not defined at file:
The function errorHandler is not defined in the code.
In your function backupContent() {..} you have used errorHandler as callback reference for the transaction.executeSql() call.
transaction.executeSql(....,errorHandler)
You need to define the errorHandler function.
Also you need to consider a scenario as to how do you handle initial database load. If you run the code for the first time there will not be any tables. The following sql statement will fail.
SELECT * FROM SmartPass;
The table SmartPass is not yet created. That is the most likely reason of the errorHandler being called.