We are creating a screening tool and this is the questions part. There is a progressbar under the question with the time but it only fills the bar or shows the progress when you reload the page.
This is the code
public function screening(Request $request){
$user_test = User_test::find(Session::get('user_test_id'));
$test = $user_test->test;
var_dump($user_test->questionsLeft());
$time = floor((strtotime(date('Y-m-d H:i:s')) - strtotime($user_test->started_at))/60);
if($test->time <= $time){
$user_test->unanswered = array_sum($user_test->questionsLeft());
$user_test->finished_at = date('Y-m-d H:i:s');
$user_test->score = $user_test->calculateScore();
$user_test->save();
return Redirect::route('user.dashboard')->with('error', ['test timed out']);
}
//Get user test object
$test = $user_test->test;
$current = $test->test_subcategories()->sum('amount') - array_sum($user_test->questionsLeft()) + 1;
//Get next question
if(Session::get('question_id') == null){
$question = $user_test->getNextQuestion();
Session::flash('question_id', $question->id);
} else if(!$user_test->answers()->where('question_id', Session::get('question_id'))->exists()){
$question = Question::find(Session::get('question_id'));
} else {
$question = $user_test->getNextQuestion();
Session::flash('question_id', $question->id);
}
// Calculate time
if($user_test->started_at == null){
return Redirect::route('user.dashboard');
} else {
$time = round((strtotime(date('Y-m-d H:i:s')) - strtotime($user_test->started_at))/60);
}
$lang = Sentinel::check()->text_lang_code;
return view('screening.test', array(
'test' => $test,
'question' => $question,
'lang' => $lang,
'time' => $time,
'current' => $current
));
}
This is the progressbar
<progress value="{{$time}}" max="{{$test->time}}"></progress>
Filling/updating progress bar is front-end job.
You need ajax request to calculate and then based on response update progress bar using jQuery.
something like
you are getting response from ajax
$.ajax({
url: "{your path}",
})
.done(function( data ) {
jQuery('progress').attr('value',time);
jQuery('progress').attr('max',test.time);
});
This is how we managed to get it right
$(document).ready(function(){
var progress = $('progress');
progress.val();
progress.prop('max');
progress.data('time', progress.val());
function countTimer() {
if(progress.data('time') < progress.prop('max') + 10){
progress.val(progress.val()+1);
progress.data('time', progress.data('time')+1);
} else {
location.reload();
console.log('timed out');
}
}
var setinterval = setInterval(countTimer, 6 * 1000);
});
Related
I have been working on an online newspaper/blogging application with CodeIgniter 3.1.8 and Twitter Bootstrap 4.
I am currently working on loading more posts via AJAX.
By default, the posts are paginated and displayed 12 at a time, at http://myblog.com/, http://myblog.com/?page=2, and so on.
In the Posts controller (application\controllers\Posts.php) I have
private function _initPagination($path, $totalRows, $query_string_segment = 'page')
{
//load and configure pagination
$this->load->library('pagination');
$config['base_url'] = base_url($path);
$config['query_string_segment'] = $query_string_segment;
$config['enable_query_strings'] = TRUE;
$config['reuse_query_string'] = TRUE;
$config['total_rows'] = $totalRows;
$config['per_page'] = 12;
if($this->Static_model->get_static_data()['has_pager']){
$config['display_pages'] = FALSE;
$config['first_link'] = FALSE;
$config['last_link'] = FALSE;
$config['prev_tag_open'] = '<li class="prev">';
$config['prev_tag_close'] = '</li>';
$config['next_tag_open'] = '<li class="next">';
$config['next_tag_close'] = '</li>';
}
if (!isset($_GET[$config['query_string_segment']]) || $_GET[$config['query_string_segment']] < 1) {
$_GET[$config['query_string_segment']] = 1;
}
$this->pagination->initialize($config);
$limit = $config['per_page'];
$offset = ($this->input->get($config['query_string_segment']) - 1) * $limit;
return array(
'limit' => $limit,
'offset' => $offset
);
}
public function index()
{
//call initialization method
$config = $this->_initPagination("/", $this->Posts_model->get_num_rows());
$data = $this->Static_model->get_static_data();
$data['base_url'] = base_url("/");
$data['pages'] = $this->Pages_model->get_pages();
$data['categories'] = $this->Categories_model->get_categories();
$data['search_errors'] = validation_errors();
//use limit and offset returned by _initPaginator method
$data['posts'] = $this->Posts_model->get_posts($config['limit'], $config['offset']);
$this->twig->addGlobal('pagination', $this->pagination->create_links());
// featured posts
if ($data['is_featured']) {
$data['featured'] = $this->Posts_model->featured_posts();
$this->twig->addGlobal('featuredPosts', "themes/{$data['theme_directory']}/partials/hero.twig");
}
$this->twig->display("themes/{$data['theme_directory']}/layout", $data);
}
In order to load the posts via jQuery Ajax instead, I have:
(function($) {
var currentPage = 1;
$('.pagination').hide();
$(window).scroll(function() {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
loadMore();
}
});
function loadMore() {
$.ajax({
url: baseUrl + '?page=' + currentPage,
type: 'GET',
beforeSend: function() {
$('.loader').show();
}
})
.done(function(data) {
$('.loader').hide();
// Get post from page 2 onward
if (currentPage >= 2) {
var posts = $(data).find('#postsContainer').html();
}
// If there are no more posts, hide loader
// Otherwise, load more posts
if (posts == 'undefined') {
$('.loader').hide();
} else {
$('#postsContainer').append(posts);
currentPage = currentPage + 1;
}
});
}
})(jQuery);
The problem:
After loading the last post, if I scroll back up (or up and down), the loader is displayed and hidden repeatedly.
What am I doing wrong? How can I fix this bug?
I solved the problem by initializing the variable posts with null and making sure that posts is not undefined before showing the loader:
(function($) {
var currentPage = 2,
maxPage = $('#postsContainer').data('max-page'),
posts = null;
$('.pagination').hide();
$(window).scroll(function() {
var toBottom = $(window).scrollTop() >= $(document).height() - $(window).height() - 25;
if (toBottom && currentPage <= maxPage) {
loadMore();
}
});
function loadMore() {
$.ajax({
url: baseUrl + '?page=' + currentPage,
type: 'GET',
beforeSend: function() {
if (typeof posts != 'undefined') {
$('.loader').show();
}
}
})
.done(function(data) {
$('.loader').hide();
posts = $(data).find('#postsContainer').html();
if (typeof posts != 'undefined') {
$('#postsContainer').append(posts);
currentPage = currentPage + 1;
if (currentPage > maxPage) {
$('#postsContainer').append('<p class="text-center text-muted">No more posts to load</p>');
}
}
});
}
})(jQuery);
In the controller:
public function index()
{
//call initialization method
$config = $this->_initPagination("/", $this->Posts_model->get_num_rows());
$data = $this->Static_model->get_static_data();
$data['base_url'] = base_url("/");
$data['pages'] = $this->Pages_model->get_pages();
$data['categories'] = $this->Categories_model->get_categories();
$data['search_errors'] = validation_errors();
$data['posts'] = $this->Posts_model->get_posts($config['limit'], $config['offset']);
$data['max_page'] = ceil($this->Posts_model->get_num_rows() / 12);
$this->twig->addGlobal('pagination', $this->pagination->create_links());
// Featured posts
if ($data['is_featured']) {
$data['featured'] = $this->Posts_model->featured_posts();
$this->twig->addGlobal('featuredPosts', "themes/{$data['theme_directory']}/partials/hero.twig");
}
$this->twig->display("themes/{$data['theme_directory']}/layout", $data);
}
In the view:
<div id="postsContainer" data-max-page="{{max_page}}">
I created a photos share page which refreshs with ajax. The page has 3 links (allphotos, high quality photos, poor quality photos). When clicking each of them, datas(photos) are loading with ajax. And after scrolling, ajax provides to bring more photo. each page (because of filtering ) has different javascript functions which are allphotos() and gallery(). Both have same scroll event function. After scrolling down, datas started to become confused. One gets data from function allphoto and one gets data from function gallery() I cant solve how to fix this. Here are my javascript and php codes.
(Codes diveded 2 main part, one has javacript codes and php codes which related each others)
javascript page (app.js)
function allphotos(){
open_popup();
var limit_load = 5;
var start_load = 0;
var action = "inactive"
function load_photo_profile(limit_load, start_load) {
var url = baseUrl+"exhibition/loadmore";
$.ajax({
url: url,
method: "POST",
data: { limit: limit_load, start: start_load },
cache: false,
success: function (response) {
if (response == '') {
$("#included_image_message").html("<h1>No data found</h1>");
action = "active";
} else {
$(".included_image").append(response);
$("#included_image_message").html("<h1>Please Wait</h1>");
action = "inactive";
}
}
});
};
if (action == "inactive") {
action = "active";
load_photo_profile(limit_load, start_load);
}
$(window).scroll(function () {
if ($(window).scrollTop() + 250 >= $(document).height() - $(window).height() && action == "inactive" && localStorage.getItem("scroll") == "all") {
action = "active";
start_load = start_load + limit_load;
setTimeout(() => {
load_photo_profile(limit_load, start_load);
}, 500);
}
});
}
function gallery(){
var limit_load = 5;
var start_load = 0;
var action = "inactive"
function load_photo_profile(limit_load, start_load) {
var url = baseUrl + "exhibition/gallery";
$.ajax({
url: url,
method: "POST",
data: { limit: limit_load, start: start_load },
cache: false,
success: function (response) {
if (response == '') {
$("#included_image_message").html("<h1>No data found</h1>");
action = "active";
} else {
$(".included_image").append(response);
$("#included_image_message").html("<h1>Please Wait</h1>");
action = "inactive";
}
}
});
};
if (action == "inactive") {
action = "active";
load_photo_profile(limit_load, start_load);
}
$(window).scroll(function () {
if ($(window).scrollTop() + 250 >= $(document).height() - $(window).height() && action == "inactive" && localStorage.getItem("scroll") == "all") {
action = "active";
start_load = start_load + limit_load;
setTimeout(() => {
load_photo_profile(limit_load, start_load);
}, 500);
}
});
}
control.php (only in order to get data from db) (codeigniter)
public function loadmore()
{
$limit = $this->input->post("limit");
$start = $this->input->post("start");
$viewData = new StdClass();
$viewData->viewFolder = $this->viewFolder;
$viewData->subViewFolder = "profile";
$get_images = $this->photo_model->get_all_limit(
array(
"Durum" => 1
),
"Id DESC",
$limit,
$start
);
if (!$get_images == "") {
$viewData->items = $get_images;
$activeUser=get_active_user();
$viewData->activeUser = $activeUser;
$render_html = $this->load->view("{$viewData->viewFolder}/assist/mygallery", $viewData, true);
echo $render_html;
}
}
function gallery()
{
$limit = $this->input->post("limit");
$start = $this->input->post("start");
$viewData = new StdClass();
$viewData->viewFolder = $this->viewFolder;
$viewData->subViewFolder = "profile";
$get_images = $this->photo_model->get_all_limit(
array(
"Durum" => 1,
"Tur" => 1
),
"Id DESC",
$limit,
$start
);
if (!$get_images == "") {
$viewData->items = $get_images;
$activeUser = get_active_user();
$viewData->activeUser = $activeUser;
$render_html = $this->load->view("{$viewData->viewFolder}/assist/mygallery", $viewData, true);
echo $render_html;
}
}
In my opinion in spide of loading refreshing ajax, the codes at below confuses because of the scroll event execute already at same page
$(window).scroll(function (){
if ($(window).scrollTop() + 250 >= $(document).height() - $(window).height() && action == "inactive" && localStorage.getItem("scroll") == "all") {
action = "active";
start_load = start_load + limit_load;
setTimeout(() => {
load_photo_profile(limit_load, start_load);
}, 500);
}
});
i have buttons created via display suite(the buttons contain 'join' text i need to run the function check to see the value should be join or leave.
you can find my js code and my check function code. my problem is i think im calling the function the wrong way.
function init() {
$('div').each(function(){
$ajax('checkteam')
.then(function(){
if (res.data === true){
var button = $(this).find('.button.pulse');
$(button).text === 'Leave';
$(button).data('leave', true);
}
else {
}
}
)
})
}
'checkteam' => array(
'type' => MENU_CALLBACK,
'page callback' => 'card_generator_check_team_ajax',
'page arguments' => array(2),
'access arguments' => array('access content'),
),
function card_generator_check_team_ajax($term_name) {
global $user;
$term = reset(taxonomy_get_term_by_name($term_name));
$tid = $term->tid;
$user_fields = user_load($user->uid);
$arrlength = (sizeof(($user_fields->field_teams[und])));
for($x = 0; $x < $arrlength; $x++) {
$mytid = ($user_fields->field_teams[und])[$x]['tid'];
if ($tid == $mytid){
return true;
}
return false;
}
}
i need to get the data from checkteam function and if its true then the value should be leave.
here is my code right now but it has one issue which is always execute onetime and not for each (views-row). i will attach my layout in picture.
(function ($) {
Drupal.behaviors.card_generator = {
attach: function (context, settings) {
$('.views-row', context).each(function(){
var button = $(this).find('.button.pulse'),
termName = $(this).find('.field-name-title .field-item');
$.ajax({
url: Drupal.settings.setProject.ajaxUrlcheck + '/' +
$(termName).text(),
method: "GET",
})
.then(function(res){
if (res === 'true'){
$(button).text('Leave');
}
}
)
})
}
};
})(jQuery);
problem solved! the php function was wrong.
function card_generator_check_team_ajax($term_name)
{
global $user;
$term = reset(taxonomy_get_term_by_name($term_name));
$tid = $term->tid;
$user_fields = user_load($user->uid);
$arrlength = (sizeof(($user_fields->field_teams[und])));
for ($x = 0; $x < $arrlength; $x++) {
$mytid = ($user_fields->field_teams[und])[$x]['tid'];
if ($tid == $mytid) {
$arr = 'true';
continue;
}
}
drupal_json_output($arr);
}
Your post looks like a crazy mix of PHP and JavaScript. Here are some basic changes I might suggest.
$("div", context).each(function(i, el) {
var termName = $(".field-name-title .field-item", this).text().trim();
$.get(Drupal.settings.setProject.ajaxUrlcheck + "/" + termName,
function(res){
if (res === "false") {
$(".button.pulse", el).html("Leave");
}
}
);
});
.each() iterates each element, so you can get the index and element. You can use $(el).find('.button.pulse') or you can use $(".button.pulse", el) to select the proper elements in jQuery.
I'm creating a form to send emails with the recaptcha. Everything was working perfectly, but I noticed that the recaptcha v3 only lasted 3 minutes and needed to reset. From there it started to give a "missing-input-response" error.
index.php
<script>
grecaptcha.ready(function() {
grecaptcha.execute('key', {action: 'homepage'}).then(function(token) {
document.getElementById('g-recaptcha-response').value=token;
});
});
</script>
<script>
var callback = function() {
grecaptcha.render('id-of-render-element', {
'sitekey': 'key',
'expired-callback': expCallback
});
};
var expCallback = function() {
alert("Your recatpcha has expired, please verify again ...");
setInterval(function(){ grecaptcha.reset(); }, 5 * 60 * 1000 );
};
</script>
<div id="id-of-render-element"></div>
<script src="https://www.google.com/recaptcha/api.js?onload=callback&render=explicit" async defer></script>
class captcha
<?php
class Captcha{
public function getCaptcha($SecretKey){
$Resposta = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=key&response={$SecretKey}");
$Retorno = json_decode($Resposta);
return $Retorno;
}
public function returnCaptcha(){
echo "entrou calss_captcha";
$EnviaMail = False;
$ObjCaptcha = new Captcha();
$Retorno=$ObjCaptcha->getCaptcha($_POST['g-recaptcha-response']);
var_dump($Retorno);
if($Retorno->success == true && $Retorno->score > 0.5){
$EnviaMail = True;
}else{
$EnviaMail = False;
}
return $EnviaMail;
}
}
?>
As per the user comment working for Version 2. You need to specify additional parameters to the file_get_contents function call and If your site has SSL then setting the context options.
class Captcha{
public function getCaptcha($SecretKey){
if($SecretKey){
// Input data
$secret = 'SECRET_KEY';
$response = $SecretKey;
$remoteip = $_SERVER['REMOTE_ADDR'];
$url = "https://www.google.com/recaptcha/api/siteverify";
$post_data = http_build_query(
array(
'secret' => $secret,
'response' => $response,
'remoteip' => $remoteip
)
);
$options=array(
// If site has SSL then
'ssl'=>array(
// In my case its /etc/ssl/certs/cacert.pem
'cafile' => '/path/to/cacert.pem',
'verify_peer' => true,
'verify_peer_name' => true,
),
'http' =>array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $post_data
)
);
$context = stream_context_create( $options );
$Resposta = file_get_contents( $url, false, $context );
$Retorno = json_decode($Resposta);
return $Retorno;
}
}
public function returnCaptcha(){
echo "entrou calss_captcha";
$EnviaMail = False;
$ObjCaptcha = new Captcha();
$Retorno=$ObjCaptcha->getCaptcha($_POST['g-recaptcha-response']);
var_dump($Retorno);
if($Retorno->success == true && $Retorno->score > 0.5){
$EnviaMail = True;
}else{
$EnviaMail = False;
}
return $EnviaMail;
}
}
I have this function where on onkeyup it verifies the mobile number whether it exists in the database already or not now the issue is even if the response is "true" it will always show as false
PHP
elseif ($action == 'check_mobile_phone')
{
$mobile = trim($_GET['mobile']);
$mobile = json_str_iconv($mobile);
if (mobile_register($mobile))
{
echo 'false';
}
else
{
echo 'true';
}
}
Ajax Call
function checkMobilePhone(mobile)
{
if (mobile == '')
{
error.find('#mobile_notice_text').html('Mobile number cant be empty.');
submit_disabled = true;
}
else if (!Utils.isMobile(mobile))
{
error.find('#mobile_notice_text').html('Please enter mobile number in local format.');
}
if( submit_disabled )
{
document.forms['formUser'].elements['Submit'].disabled = 'disabled';
return false;
}
Ajax.call( 'user.php?act=check_mobile_phone', 'mobile=' + mobile, check_mobile_callback , 'GET', 'TEXT', true, true );
}
Response
function check_mobile_callback(result)
{
var logform = $('form[name="formUser"]');
var error = logform.find('#mobile_notice');
if ( result === "true" )
{
document.forms['formUser'].elements['Submit'].disabled = '';
}
else
{
error.find('#mobile_notice_text').html('Phone number already exists.');
document.forms['formUser'].elements['Submit'].disabled = 'disabled';
}
}
function mobile_register($mobile)
{
$res = $GLOBALS['db']->getOne("SELECT COUNT(*) FROM " . $GLOBALS['db']->table('users') .
" WHERE mobile_phone = '$mobile'");
return $res;
}