I have a use-case where I need to programmatically add/remove the onClick event associated with a panel.
I have tried the following solution but receive a cijCell.addEventListener is not a function error.
function cij_enabled(){
var cijCell = app.pages.Home.descendants.cellFour;
var index = cijCell.styles.indexOf('disabled-card');
if (Report.riskOfLoss === 'High') {
cijCell.styles.splice(index, 1);
cijCell.addEventListener("click", function() {
app.popups.Customer.visible = true;
});
} else {
if (index === -1){
cijCell.styles.push('disabled-card');
cijCell.removeEventListener("click", function() {
app.popups.Customer.visible = true;
});
}
}
}
How can I achieve the desired outcome? Is adding eventlisteners possible in this fashion through app maker?
You can definitely do so and you got it almost right. The only thing you need to understand is that the appmaker widget is not a native html element hence the error:
cijCell.addEventListener is not a function
Fortunately, AppMaker has a way of getting the native html elements associated to a widget. You need to use the getElement() method and then you can use the add/remove event listeners methods. So you should change your code from cijCell.addEventListener... to cijCell.getElement().addEventListener...
Reference: https://developers.google.com/appmaker/scripting/api/widgets#Panel
Related
I have a fullCalendar widget created somewhere. I cannot change the code that initialize it. So I cannot add any callbacks in the first call.
Anything like this:
$(elem).fullCalendar({
complete: function () {
...
}
})
Actually creates a new fullCalendar instead of modifying the actual fullCalendar to change/add the complete callback.
Is there an other way to find out when events are loaded I was thinking about polling clientEvents but I realize that I could have no events in one month so I cannot expect the array to always have something in it.
By the way, it's fullCalendar 1.6.
You can define callbacks after the calendar object has been initialized, and to determine when all events have been rendered, use the eventAfterAllRender event. Here's how:
var calendar = $('#calendar').fullCalendar('getCalendar');
calendar.on('eventAfterAllRender', function(view) {
alert('all events rendered!');
});
Nevermind, this feature is only available starting in version 2.4.
Instead, you could poll the DOM for fullcalendar element existence, like this:
function checkForInit() {
if($(".fc-view").children().length) {
alert("initialized!");
} else {
setTimeout(function() {
checkForInit();
}, 10);
}
}
$(document).ready(function() {
checkForInit();
});
You can use eventAfterAllRender event, available from version 1.6:
$(elem).fullCalendar({
eventAfterAllRender: function (view) {
...
}
})
Ok I found a solution that seems to be working!
var waitPrint = true
function autoPrint() {
var elem = $('.fc')
var calendar = elem.data('fullCalendar')
console.log('Searching calendar')
if (calendar && waitPrint) {
waitPrint = false
console.log('Bund new event')
var _super = calendar.options.eventAfterAllRender
calendar.options.eventAfterAllRender = function (event, element, view) {
if (_super) {
_super.apply(this, arguments)
}
window.print()
}
} else if (waitPrint) {
setTimeout(autoPrint, 100)
}
}
autoPrint()
Here I'm polling for an element with the fc class. As soon as I find one, I check for the existence of the "data" named fullCalendar. If it returns a dict, then it means that the fullCalendar instance has been created. This is pretty much what Dane proposed for version 2.4 but this in 1.6 there is no getter. We have to get it ourselves. Luckily, it's stored in the data of the element and not in some other cryptic places.
Move on to the next step, fullCalendar isn't an eventEmitter in 1.x, but we still have access to options which seems to be just a reference to the options that were passed at first. I override the eventAfterAllRender. Call the method that was already defined if present and call my print method when it's done.
Technically from there, we can override almost any defined method from there. The only problem is that you have to do it faster than fullCalendar get initialized.
I believe that if we dig deeper, we could potentially patch the calendar library directly to remove the timing issues. Polling isn't very great.
Best Solution So far
var oldFullCalendar = $.fn.fullCalendar
function newFull(options) {
var _super_func = null
if (typeof options == 'string') {
oldFullCalendar.apply(this, arguments)
} else {
options = options || {}
if (options.loading) {
_super_func = options.loading
}
options.loading = function (loading) {
console.log(loading, 'loading')
if (_super_func) {
_super_func.apply(this, arguments)
}
if (!loading) {
window.print()
}
}
oldFullCalendar.apply(this, arguments)
}
}
$.fn.fullCalendar = newFull
The first solution could probably be improved by overriding loading instead. Since it's the method that notify when loading has been processed and which is also apparently called after the eventAfterAllRender callback.
I am updating some Session variables with Router.onAfterAction whenever my route changes. Then I have a Tracker.autorun() waiting for a the change so it can run some logic and update some DOM classes. I checked the Sessions are set correctly and that the element to-be appended is targeted correctly. But my addClass() does not trigger. No console errors either. What am I missing?
Tracker.autorun(function (c) {
var colActive = Session.equals('navColumnActive', true);
var colVisible = Session.equals('navColumnVisible', true);
var $col = $("#nav-column");
console.log($col);
if (colActive) {
console.log("if triggered");
$col.addClass( "active" );
} else {
console.log("else triggered");
$col.removeClass("active");
}
if (colVisible) {
$col.addClass("visible");
} else {
$col.removeClass("visible");
}
});
I had the same problem just recently. In my case the reactive values triggering the computation where being executed before the DOM and the elements where properly rendered.
I would check if the session vars are being set after the DOM has been rendered. Therefore selectors like $col = $("#nav-column") came back empty, though perfectly worked when executed in the browser console.
You could try the following:
Template.<template_name>.onRendered(function() {
Session.set('navColumnActive', true);
Session.set('navColumnVisible', true);
})
I am using CodeMirror and attempting to do some CSS styling to the autocomplete pop up. This is a bit difficult, because I need it to not go away when I go to inspect styles and stuff.
So I hunted for a way to do this. I found this code in show-hint.js
if (options.closeOnUnfocus !== false) {
var closingOnBlur;
cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); });
cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); });
}
If I comment this out, then the autocomplete pop up does not go away when I click on other things; That's what I wanted. But I thought I would explore this more and try to determine what to do to toggle this on and off at will.
So I wanted to be able to set this closeOnUnfocus option on my own. That seemed simple enough.
I cannot find a way to do this, though. Exploring further I found an example on code mirror's website that demonstrates a way to setup the autocomplete system using the following code;
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword);
}
Exploring further, show-hint.js starts out with a function called showHint that has this signature;
CodeMirror.showHint = function (cm, getHints, options) {
// We want a single cursor position.
if (cm.somethingSelected()) return;
if (getHints == null) {
if (options && options.async) return;
else getHints = CodeMirror.hint.auto;
}
if (cm.state.completionActive) cm.state.completionActive.close();
var completion = cm.state.completionActive = new Completion(cm, getHints, options || {});
CodeMirror.signal(cm, "startCompletion", cm);
if (completion.options.async)
getHints(cm, function (hints) { completion.showHints(hints); }, completion.options);
else
return completion.showHints(getHints(cm, completion.options));
};
Okay, so it stands to reason that I could accomplish what I want by passing my option through here; like this...
CodeMirror.commands.autocomplete = function (cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword, {
closeOnUnfocus: false
});
}
But this doesn't work - in fact, it seems that the options just don't get passed at all. If I do a console.log in the show-hint.js, the options are outright ignored. They never get through.
So how can I pass options through? I am very confused.
If you want to change the styles of of the hint menu, just use the provided CSS hooks. There is no need to mess around with the autocomplete handlers. e.g.:
.CodeMirror-hints {
background-color: red;
}
.CodeMirror-hint {
background-color: green;
}
.CodeMirror-hint-active {
background-color: blue;
color: yellow;
}
And here's a live Demo.
I've just started to use Codemirror (v4.1) and I've found the same problem. After checking show-hint.js contents it seems that documentation is not updated.
Try to write this when you want to get the suggestions:
CodeMirror.showHint({hint: CodeMirror.hint.deluge, completeSingle: false, closeOnUnfocus: true});
If you need to use the async mode of getting suggestions (it was my case), now you have to do this before previous snippet:
CodeMirror.hint.deluge.async = true;
Hope this helps!
You can pass the options like this :
CodeMirror.showHint(cm,CodeMirror.hint.anyword,{completeSingle: false,closeOnUnfocus:false});
You can write the code as follows:
editor.on("keyup",function(cm){
CodeMirror.showHint(cm,CodeMirror.hint.deluge,{completeSingle: false});
});
It's working for me.
This seems very simple, but for some reason it's not working as expected.
I am trying to make a very simple jQuery extension/plugin which allows me to simply reduce my lines of code when requiring a trigger on an enter key (and a similar for an escape)
Here's my code:
$.fn.enterListen = function (callBack) {
$(this).on('keyup', function (e) {
if (e.keyCode == 13) {
callBack;
// $(this).enterListen(callBack); // trying to rebind...
};
})
};
Then when an element is dynamically created with jquery we might do something like:
var input = $('<input'>).enterListen(function (){ alert("Enter was pressed"); });
$(input).appendTo('body');
Now we've added an input element to the page, in which we can type and when enter is pressed it triggers the alert.
This works, except, only once.
You can see a commented out line in my code above where I am trying to rebind the function the the element after the enter trigger is activated, and even that doesn't make it work a second time.
You can press as many other keys as you like before pressing Enter, but as soon as you do, it seems to unbind the keyup event.
IF... however, I run it like this:
function isEnter(e, ele) {
if ((e * 1) == 13) {
$(ele).click();
};
};
Called by:
var input = $('<input'>).on('keyup', function (e) { isEnter(e.keyCode, $(ok)) });
$(input).appendTo('body');
It works fine, but to me it is clumsier in the code, I am trying to create a library of extensions to make the inner coding of this project a bit shorter... perhaps I am just putting too much time into something I needn't...
Anyway, if anyone could shed any light on why the event becomes unbound, that'd be lovely!
Inside a jQuery plugin, this is the jQuery object, no need to rewrap it. e.which is normalized in jQuery. To execute a function you need parenthesis (). And most importantly, you need to return this otherwise the input variable will be undefined, and if you intend to do stuff inside your plugin with selectors containing multiple elements, you need to return this.each(function() { ... }) etc. as explained in the plugin authoring documentation from jQuery.
$.fn.enterListen = function (callBack) {
return this.each(function() {
$(this).on('keyup', function (e) {
if (e.which == 13) {
e.preventDefault();
callBack();
}
});
});
};
var input = $('<input />').enterListen(function (){
alert("Enter was pressed");
});
input.appendTo('body');
FIDDLE
can we use standard 'InsertCpDialog$initialize()' in our javascript like this , so that i can call other function once it get initializes. I used like below code but it is not working. :(
Type.registerNamespace("Extensions");
Extensions.InsertCpDialog.prototype.initialize = function InsertCpDialog$initialize()
{
alert('hi inside insert');
var p = this.properties;
if(window.document.nameProp == "Name" || window.document.title == "Name") {
var browserName=navigator.appName; // Get the Browser Name
if(browserName=="Microsoft Internet Explorer") // For IE
{
alert('hi inside IE');
//window.onload=init(); // Call init function in IE
}
else
{
if (document.addEventListener) // For Firefox
{
alert('hi inside firefox');
//document.addEventListener("DOMContentLoaded", init(), false); // Call init function in Firefox
}
}
}
}
Original(standard) one is like:
Type.registerNamespace ("Tridion.Cme.Views");
Tridion.Cme.Views.InsertCpDialog = function InsertCpDialog()
{
Type.enableInterface(this, "Tridion.Cme.Views.InsertCpDialog");
this.addInterface("Tridion.Cme.Views.DashboardBase");
};
Tridion.Cme.Views.InsertCpDialog.prototype.initialize = function InsertCpDialog$initialize()
{
}
Edit
hi frank thank you, but already i am using same thing in my code to get the list of componet and template listed on a page under CP tab.
function getbtn() {
//alert('inside getbtn');
var sbtn = document.getElementById ("buttonComponentInsert");
$evt.addEventHandler(sbtn , "click", getListofCPBtnClick);
}
function getListofCPBtnClick(e) {
//code will go here
}
My question is :
I need to get selected Component and template Id from Insert CP window.Earlier i was able to get that by changing the CME extension standard code, but i am not suppose to do that, So first i am trying to initialize the "insert CP window" from my javascript code. I can create event handler for that window, but my question is how to initialize that so that i can call any function once it get initialize. Kindly let me know if i anot clear.
Is your script getting loaded into the dialog?
If not, Albert shows how to do that here: http://albertromkes.com/2012/01/30/tridion-gui-extensions-how-to-load-a-javascript-without-showing-a-gui-element/
He then also shows how to listen to events to accomplish something similar to what you are trying to do.