Im building a new personal blog and I'm using ajax to post back to a C# Controller to get the results for pagination.
Page 2 loads with the results however, none of the javascript is reloaded because, I believe, when I partially reload the pagination part of the page, it destroys everything in the DOM and because the full page doesn't reload, the javascript isn't invoked.
So I'm looking for a bit of help on working out how to get the external javascript to run again. What it does is adds css classes, gives some fade effects etc.
success: function (data) {
if (data != null) {
var page = data
$('#blogsContainer').empty();
$('#blogsContainer').replaceWith(page);
So the success works, I clear out the blogsContainer with the new data.
I'm guessing I need to add a function after the replace to then apply everything that is in an external main.js file.
The main.js file looks like this
(function($) {
var contentWayPoint = function() {
var i = 0;
$('.ftco-animate').waypoint( function( direction ) {
if( direction === 'down' && !$(this.element).hasClass('ftco-animated') ) {
i++;
$(this.element).addClass('item-animate');
setTimeout(function(){
$('body .ftco-animate.item-animate').each(function(k){
var el = $(this);
setTimeout( function () {
var effect = el.data('animate-effect');
if ( effect === 'fadeIn') {
el.addClass('fadeIn ftco-animated');
} else if ( effect === 'fadeInLeft') {
el.addClass('fadeInLeft ftco-animated');
} else if ( effect === 'fadeInRight') {
el.addClass('fadeInRight ftco-animated');
} else {
el.addClass('fadeInUp ftco-animated');
}
el.removeClass('item-animate');
}, k * 50, 'easeInOutExpo' );
});
}, 100);
}
} , { offset: '95%' } );
};
contentWayPoint();
}
The first page has the following applied to it on page load:
<div class="col-md-4 d-flex ftco-animate fadeInUp ftco-animated">
<div class="blog-entry justify-content-end">
...
</div>
</div>
But as you can see, when I press page 2, the div is missing some key css
<div class="col-md-4 d-flex ftco-animate">
<div class="blog-entry justify-content-end">
</div>
</div>
How would I apply the missing css after the partial reload with ajax?
I hope this is clear what I am trying to do but if not, please just ask.
I think the solution may be to re-execute the contentWayPoint() function at the end of the success callback. However, its likely out of scope by then. There are two simple ways to ensure its not :
The cleanest would be to ensure that the code that sets up your pagination is inside the same (function($) {}) block in main.js - that way it will "capture" the function.
The other, dirtier way, would be to change var contentWaypoint= function... to window.contentWaypoint = function - then use window.contentWaypoint() whenever you need to invoke it. THere are much better ways to doing this, but that might get you going.
Related
I am using multiple off campus menus on my site. So as a user clicks on a certian link to a store they can get a off campus menu with information pertaining to that particular store. I am trying to minimize the JS code so that I don't have a open and close function for each span link that opens and closes a menu. I have tried to create one function that will different menus as to follow a DRY coding practice. I initially tried a switch statement but this only partially worked and I am left at a dead end. Any assistance would be appreciated. Thank you and have a blessed day.
// // prj 1
function workOpenNav() {
document.getElementById('prjOne').style.width = '100%';
}
function workCloseNav() {
document.getElementById('prjOne').style.width = '0%';
}
// // prj 2
function workTwoOpenNav() {
document.getElementById('prjTwo').style.width = '100%';
}
function workTwoCloseNav() {
document.getElementById('prjTwo').style.width = '0%';
}
// // prj 3
function workThreeOpenNav() {
document.getElementById('prjThree').style.width = '100%';
}
function workThreeCloseNav() {
document.getElementById('prjThree').style.width = '0%';
}
<span class="wrk-link span-title" style="cursor:pointer" onclick="workOpenNav()">
Store #1
</span>
<div id="prjOne" class="wrk-overlay overLay">
// Content
</div>
<span class="wrk-link span-title" style="cursor:pointer" onclick="workTwoOpenNav()">
Store #2
</span>
<div id="prjTwo" class="wrk-overlay overLay">
// Content
</div>
<span class="wrk-link span-title" style="cursor:pointer" onclick="workThreeOpenNav()">
Store #3
</span>
<div id="prjThree" class="wrk-overlay overLay">
// Content
</div>
Let's walk through this together. Take these first two functions:
function workOpenNav() {
document.getElementById('prjOne').style.width = '100%';
}
function workCloseNav() {
document.getElementById('prjOne').style.width = '0%';
}
Let's find what they have in common, and turn what they do not have in common into input variables. In this case, the percentage is the only thing different. So:
function workNav(pct) {
document.getElementById('prjOne').style.width = pct;
}
This one function now does the work of two. The other functions you have can similarly be combined into a single function with one input. Let's do that now:
function workTwoNav(pct) {
document.getElementById('prjTwo').style.width = pct;
}
function workThreeNav(pct) {
document.getElementById('prjThree').style.width = pct;
}
But we're not done! Notice that these three functions I've made have mostly everything in common, only the control ID is different. Let's turn that into another parameter!
function workNav(id, pct) {
document.getElementById(id).style.width = pct;
}
Now, all of your functions have been reduced to a single function, which can be called like so:
workNav("prjOne", "100%");
Now, we're still not quite done. Let's clean this up and make it more clear. Your function is intended to show or hide the indicated element, right? So let's rename it to make that intent more clear, and let's tweak the second parameter a bit:
function showNav(id, show) {
document.getElementById(id).style.width = show ? "100%" : "0%";
}
Now, it can be used accordingly. To show:
showNav("prjOne", true)
And to hide:
showNav("prjOne", false)
Why turn the second parameter into a true/false? It will be easier for the programmer to get right. "100%" it would be pretty easy to drop a 0, or the percentage sign. Those typos won't generate an error in your browsers console, but if you make a typo like tru, you'll get an error, which you can then fix. Things are easier to fix when the error is made apparent. Ultimately this change comes down to programmer preference, and isn't necessary to achieve your goals. Would you ever set the width to 50%, or is it always all-or-nothing? Clearer intent is achieved using the boolean.
I'm trying to watch videos onClick in a modal without having to visit the video pages themselves.
I'm using Vue.js and through a series of Ajax calls I am able to get most of the way there.
Codpen: https://codepen.io/nolaandy/pen/BrbBzO
If you click "vs Suns" at top, you get a listing of all video posts. Then clicking any of the images, the modal component pops up and takes in the title of the post dynamically.
I want to run a video in there as well so I try to run this script tag:
< script class="_nbaVideoPlayerScout" data-team="warriors" data-videoId="/video/{{unique videoId from post ajax call}}" data-width="768" data-height="732" src="https://www.nba.com/scout/team/cvp/videoPlayerScout.js"></script>
When the modal pops up, I see the correct title of the post/image I clicked on, and I see the script tag exactly as it should be in the inspector, but the script tag never runs.
Is there some different way I should be injecting this script than this? (This is inside the axios response call)
let theVideoId = response.data.content[0].videoID
let s = document.createElement('script')
s.setAttribute('class', '_nbaVideoPlayerScout')
s.setAttribute('data-team', 'warriors')
s.setAttribute('data-videoId', '/video/' + theVideoId)
s.setAttribute('data-width', '768')
s.setAttribute('data-height', '732')
s.setAttribute('src', 'https://www.nba.com/scout/team/cvp/videoPlayerScout.js')
document.getElementById('popupVideo').appendChild(s);
MODAL COMPONENT -- Fired on the click of one of the post thumbnails
const videoModal = Vue.component('VideoModal', {
props: {
id: {
type: String,
required: true
}
},
data: function () {
return {
post: [],
}
},
mounted() {
const singleApi = 'https://cors-anywhere.herokuapp.com/www.nba.com/warriors/api/1.1/json?textformat=html&nid='
axios.get(singleApi + this.id).then((response) => {
this.post = response.data.content[0]
console.log('THE RESPONSE', response)
let theVideoId = response.data.content[0].videoID
let s = document.createElement('script')
s.setAttribute('class', '_nbaVideoPlayerScout')
s.setAttribute('data-team', 'warriors')
s.setAttribute('data-videoId', '/video/' + theVideoId)
s.setAttribute('data-width', '768')
s.setAttribute('data-height', '732')
s.setAttribute('src', 'https://www.nba.com/scout/team/cvp/videoPlayerScout.js')
document.getElementById('popupVideo').appendChild(s);
}).catch((error) => {
console.log(error)
})
},
methods: {
goBack: function () {
router.go(-1)
}
},
template:`<div>
<div id="video-popup">
<button class="close-video-popup" #click="goBack">close me</button>
<div class="video-popup-wrapper">
<div class="video-popup--title">{{post.title}}</div>
<div class="video-popup--video" id="popupVideo"></div>
<div class="video-popup--share"></div>
</div>
</div>
</div>`
})
On a whim I made this change:
// document.getElementById('scriptMe').appendChild(s);
document.body.appendChild(s);
and boom, script runs and video loads.
Which is super interesting, because "why", right?
Edit:
In addition, trying other script injection methods discussed here.
document.write method
document.write(s.outerHTML) // s is a script node
also works. In fact, you can embed that script node in a div and it works as well.
createContextualFragment method
// var $container = document.getElementById('scriptMe'); // does not work
var $container = document.body
var range = document.createRange()
$container.appendChild(range.createContextualFragment(script_str))
works, where script_str is an html string literal. This will work both as "<script>....</script>" or "<div id="myDiv"><script>...</script></div>"
but all the methods I tested ultimately needed injection to be done in body.
codepen
I wanted to hide some issue link outward & inwards strings of Link type from the Link Issues Popup Window using java script.
I have tried using java script but I am not getting the popup screen from the java script.
Please see the screenshot below :
Can anyone tell me how can I get this popup screen in the java script?
Is there any other method to hide this?
Thanks & Regards,
Renuka.
To hide the clone issue link every page:
edit the file system-webresources-plugin.xml (should be at /atlassian-jira/WEB-INF/classes/), and add to <web-resource key="jira-fields"> this code:
<resource type="download" name="myScript.js" location="/includes/jira/field/script.js">
<param name="source" value="webContextStatic"/>
</resource>
than, on /includes/jira/field/myScript.js write this:
AJS.$(document).ready(function() {
if (AJS.$("#link-type option[value*='clon']").size() > 0) {
// will work even when right clicking on More
// Actions->Link & open it into a new window
AJS.$("#link-type option[value*='clon']").remove()
} else if (AJS.$("#link-issue").size() > 0) {
// will work in case the link menu showing via popup
AJS.$("#link-issue").click(function(){
// wait for the popup to show, and remove the clone options
setTimeout(function (){
AJS.$("#link-type option[value*='clon']").remove();
}, 300);
});
}
});
restart Jira and it that it!
The script attaches a function to the link-menu opening, than gives the menu 0.3 seconds to load, and removes the unwanted items. If it doesn't work well for you, try to raise the timeout from 300 to 500-1000.
On jira 4, run instead:
AJS.$("#issue-link-link-type option[value*='clon']").remove();
The previous solution has an issue:
It will only work when clicking the "Link Issue"-Menu-Item.
When I use the Point (.)-Shortcut-Menu, it won't remove the issue types.
I have established the following solution:
JS-Binding-Part:
AJS.$(document).ready(function() {
JIRA.bind(JIRA.Events.NEW_CONTENT_ADDED, function(e, context, reason) {
hideIssueLinkTypes();
});
});
JS-Backing-Function:
function hideIssueLinkTypes() {
var apiURL = "/rest/scriptrunner/latest/custom/getHiddenLinkTypes"
$.getJSON( apiURL, {
}).done(function( objectData ) {
$.each( objectData, function( i, item ) {
var issueLinkType = item.issueLinkType[0];
AJS.$("#link-type option[value='"+issueLinkType.inwardDescription+"']").remove();
AJS.$("#link-type option[value='"+issueLinkType.outwardDescription+"']").remove();
});
});
}
Scriptrunner-REST-Endpoint:
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate
import groovy.json.JsonBuilder
import groovy.transform.BaseScript
import com.atlassian.jira.issue.link.DefaultIssueLinkTypeManager
import com.atlassian.jira.issue.link.IssueLinkTypeManager
import com.atlassian.jira.issue.link.IssueLinkType
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.properties.ApplicationProperties
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response
#BaseScript CustomEndpointDelegate delegate
String HIDDEN_IDENT="[hidden]"
getHiddenLinkTypes(httpMethod: "GET") { MultivaluedMap queryParams, String body ->
def appProperties = ((ApplicationProperties) ComponentAccessor.getComponentOfType(ApplicationProperties.class));
def appClonersLinkTypeName = appProperties.getDefaultBackedText("jira.clone.linktype.name");
def jsBuilder=new JsonBuilder();
def issueLinkTypes = ((IssueLinkTypeManager) ComponentAccessor.getComponentOfType(IssueLinkTypeManager.class)).getIssueLinkTypes();
jsBuilder issueLinkTypes.findAll({it.getName().contains(HIDDEN_IDENT) || it.getName()==appClonersLinkTypeName }),
{ IssueLinkType linkType ->
issueLinkType linkType.getId(),
name: linkType.getName(),
inwardDescription: linkType.getInward(),
outwardDescription: linkType.getOutward()
}
return Response.ok(jsBuilder.toString()).build();
}
What you can do then ist just annotate and Link-Type with putting [hidden] in the link name and it will disappear for all users (It can still be programmatically added though or created by cloning).
If you don't have Scriptrunner or don't need the dynamic nature of the implementation, you can still hard-code the values as Kuf described in the answer above in hideIssueTypes() like this:
AJS.$("#issue-link-link-type option[value*='clon']").remove();
I have a Jquery Mobile page into which I'm loading a form via AJAX. I'm setting the page dimensions using a plugin, which calculates dimensions AFTER the Ajax has run and the layout has been updated (at least the below consoles come in afterwards).
I need to get the height of the element that received the content, but no matter what I try, I'm just getting rubbish ( ~ 169px instead of some 1200px)
Here is my code:
(inside plugin)
some: function(){
var self = this,
o = self.options,
wrap = $('div:jqmData(wrapper="true").ui-page-active').last(),
// elements
panels = wrap.find('.ui-panel.ui-panel-active').filter(':not(.ui-popover)'),
pages = panels.find('.ui-page'),
contents = pages.find('.ui-content');
// maxHeight contents
for ( var i = 0; i < contents.length; i++){
ct = contents.eq(i);
console.log( ct );
console.log( ct.css("height") )
console.log( ct.height() );
console.log( ct.outerHeight() );
// max
if ( ct.css("height") > parseFloat( o._iPadFixHeight ) ){
o._iPadFixHeight = parseFloat( ct.css("height") ) + parseFloat( ct.css('padding-top')) + parseFloat( ct.css('padding-bottom')) ;
};
}
...
If I'm not using any AJAX this works correctly. If I'm adding content dynamically via AJAX, the consoles all fire after the AJAX, but still only return false values.
Question:
How can I reliably get the content element height after an AJAX update? I tried setting a 10sec timeout after Ajax to wait until everything is there. No difference, after 10sec the content element height is still not correct.
Thanks for help!
EDIT:
Although the consoles log AFTER the AJAX load, I think the function is firing before, so it's calcualting based on pre-AJAX dimensions. I'm thinking to re-fire using this:
$(window).on('dimensionchange', function(){
self.ome();
})
And triggering
$(window).trigger('dimensionchange')
in my AJAX success handler. Not perfect, but I guess this will do.
EDIT2:
Got it to work. #HolgerDSchauf was correct. On my first function run, I set the false values and then after AJAX came in, the false value were still set. I'm now fixing it like this:
Ajax Success:
...
// cleanup dimensions
$(window).trigger( 'dimensionclear');
...
window.setTimeout(function() {
target.removeClass('.fade.in');
// recalculate
$(window).trigger('dimensionchange');
},250);
In my plugin:
$(window).on('dimensionchange', function(){
self.ome();
});
$(window).on('dimensionclear', function(){
self.ome("clear");
});
And in OME function:
// cleanup
if ( from == "clear") {
contents.css({'height':'', 'max-height':''})
return;
}
Works like a charm.
I use this function to keep all my div's updated sizes. Use something like this, but do not forget to call it when document is ready.
function framing() {
/*
Pre : ready.js, self
Post : design.js->framing
Author : Enes Ü.
Date : 15:30, 05 May 12
Summary : framing the page widthly/heightly
Bugs/TODOs : Frame heights are anormal and will be fixed. Prior=5
*/
$("#right_menu").width($("#main").width()-$("#left_menu").width());
$("#left_menu").height(getWinHeight());
$("#top_menu").width($("#main").width()-$("#left_menu").width());
$("#right_menu").height(getWinHeight()-$("#top_menu").height());
$("#map_container").height(getWinHeight());
/*
******* lots of lines like above...
*/
setTimeout(framing,100);
}
you used an cache element with "wrap, panels, ct" refresh this cached variable or use it instantly
I have made a simple accordion for my site using jQuery... It worked great, but I've recently started working on a change where if you click the currently opened segments title (the clickable area to slide up/down), it should close the current section.
var sideMenu = {
activated: {},
setup: function() {
$('.menu-category-heading').bind('click', function() {
sideMenu.slideMenu($('ul', $(this).parent()));
});
},
slideMenu: function(menuObj) {
if (sideMenu.activated == menuObj) {
$(sideMenu.activated).slideUp(400);
sideMenu.activated = null;
console.log('same');
} else {
$(sideMenu.activated).slideUp(400);
menuObj.slideDown(500);
sideMenu.activated = menuObj;
console.log('new');
}
}
}
For some reason the comparison is never working... it does if I add $(menuObj).attr('id') and the same for activated. But this is not ideal as not all items will have an id attribute.
Any suggestions as to make the object comparison work? Or any other tips?
Thank you!
You are probably saving a jQuery object (the result of a $ call) rather than the native element. Each time you do a $(myEl) a new object is created and the references will not match up, but the native element will. Try:
if (slideMenu.activated[0] == menuObj[0]) {
...
}