I am new to SAPUI5. I have two controllers participantList.controller.js and Topic.controller.js. I have defined function called refreshData in participantList.js and I am trying to call that function Topic.Controller.js. Overall, I have progress indicator set up at top in participantList view. So, every time when I navigate from Topic view to participant view by selecting topic on topic view, I want to restart progress indicator that's on participant view. Please help!
Here is code for ParticipantList.controller.js:
var reset;
var list;
sap.ui.define([
"fiveminuteapp/controller/BaseController",
"fiveminuteapp/controller/Topic.controller"
],
function(BaseController, participant) {
"use strict";
return BaseController.extend("fiveminuteapp.controller.participant.ParticipantList", {
onInit: function() {
var topicheader = this.byId("employeeListPage");
topicheader.setTitle(topic);
this.listfunction();
this.testFunction();
},
refreshData: function() {
clearInterval(reset);
lTime.setText("5:00");
setInterval(reset);
},
testFunction: function() {
var setMinutes = 5;
var originalTime = setMinutes * 60;
var time = originalTime;
var lTime = this.byId("labelTimeLeft");
var progress = this.byId("progressIndicator");
reset = setInterval(function() {
var minutes;
var seconds;
if (time > -1) {
minutes = Math.floor(time / 60);
seconds = time % 60;
time = time - 1;
if (minutes < 10 && seconds < 10) {
lTime.setText("0" + minutes + ":" + "0" + seconds);
} else if (minutes < 10) {
lTime.setText("0" + minutes + ":" + seconds);
} else if (seconds < 10) {
lTime.setText(minutes + ":" + "0" + seconds);
}
progress.setPercentValue((time / originalTime) * 100);
} else {
clearInterval(reset);
lTime.setText("5:00");
setInterval(reset);
if(lTime.getText() === "00:00"){
$.ajax({
type: "post",
data:{username: username},
url:"/fiveminuteapp/AddPoints"
})
}
}
}, 1000);
},
listfunction: function(){
var test = this.getView().byId("participantList");
setInterval(function(){
var aData = $.ajax({
type: "get",
data:{topic : topic},
contentType : "application/json",
url:"/fiveminuteapp/RetrieveName",
dataType: "json",
async:false,
}).responseJSON;
var oModel = new sap.ui.model.json.JSONModel(aData);
test.setModel(oModel, 'listmodel')
},5000)
}
});
});
and here is code for Topic.Controller.js:
sap.ui.define([
"fiveminuteapp/controller/BaseController",
"fiveminuteapp/controller/participant/ParticipantList.controller"
], function(BaseController, participant) {
"use strict";
return BaseController.extend("fiveminuteapp.controller.Topic", {
onNavToParticipant: function(oEvent) {
var otime = window.originalTime;
var oItem = oEvent.getSource();
var oContext = oItem.getBindingContext("topics");
var topicSelected = oContext.getProperty("TopicChoices");
topic = topicSelected;
$.ajax({
type: "post",
data:{username: username, topic : topic},
url:"/fiveminuteapp/InsertTopic"
})
this.getRouter().navTo("participantList");
var time = participant.refreshData();
//sap.ui.controller("ParticipantList.controller.js").refreshData();
}
});
});
Topic view
Participant view
I assume you are using Routing in your application. If yes, you can attach route pattern match handlers to specific routes, which handlers will be invoked by the framework every time when the specific route has been matched.
Register a handler in your ParticipantList.controller.js onInit() method:
oRouter.getRoute("participantList").attachPatternMatched(this._onRouteMatched, this);
Then implement the handler function itself in ParticipantList.controller.js with name _onRouteMatched():
_onRouteMatched: function (oEvent) {
this.refreshData();
}
More details can be found in the official UI5 documentation.
Related
I use tinyMCE 5 in my web site to enter data stored in a database. Therefore I need to limit the entered size, including format information, to the size of the data field. How can I prohibit the user to enter more then the allowed number of bytes, say 2000?
Best of all if I could add some information like "42/2000" on the status bar.
We had a similar requirement in our project (difference: the output should be <entered_chars>/<chars_left> instead of <entered_chars>/<max_chars>), and it ended up being a custom plugin, based on the wordcount plugin. There is some hacks in there, which could make it fail whenever tinyMCE changes, since there is no API for the statusbar in version 5 at this point of time.
But maybe you will still find it useful:
(function () {
'use strict';
var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
var maxChars = function (editor) {
return editor.getParam('number_max_chars', 3600);
};
var applyMaxChars = function (editor) {
return editor.getParam('restrict_to_max_chars', true);
};
var Settings = {
maxChars: maxChars,
applyMaxChars: applyMaxChars
};
var global$1 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
var getText = function (node, schema) {
var blockElements = schema.getBlockElements();
var shortEndedElements = schema.getShortEndedElements();
var isNewline = function (node) {
return blockElements[node.nodeName] || shortEndedElements[node.nodeName];
};
var textBlocks = [];
var txt = '';
var treeWalker = new global$1(node, node);
while (node = treeWalker.next()) {
if (node.nodeType === 3) {
txt += node.data;
} else if (isNewline(node) && txt.length) {
textBlocks.push(txt);
txt = '';
}
}
if (txt.length) {
textBlocks.push(txt);
}
return textBlocks;
};
var strLen = function (str) {
return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '_').length;
};
var countCharacters = function (node, schema) {
var text = getText(node, schema).join('');
return strLen(text);
};
var createBodyCounter = function (editor, count) {
return function () {
return count(editor.getBody(), editor.schema);
};
};
var createMaxCount = function (editor) {
return function () {
return Settings.maxChars(editor);
}
}
var createRestrictToMaxCount = function (editor) {
return function () {
return Settings.applyMaxChars(editor);
}
}
var get = function (editor) {
return {
getCount: createBodyCounter(editor, countCharacters),
getMaxCount: createMaxCount(editor),
getRestrictToMaxCount: createRestrictToMaxCount(editor)
};
};
var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
function isAllowedKeycode(event) {
// allow arrow keys, backspace and delete
const key = event.keyCode;
return key === 37 || key === 38 || key === 39 || key === 40 || key === 8
|| key === 46;
}
var updateCount = function (editor, api) {
editor.getContainer().getElementsByClassName(
'tox-statusbar__text-container')[0].textContent = String(
api.getCount()) + " / " + String(
Settings.maxChars(editor) - api.getCount());
};
var setup = function (editor, api, delay) {
var debouncedUpdate = global$2.debounce(function () {
return updateCount(editor, api);
}, delay);
editor.on('init', function () {
updateCount(editor, api);
global$2.setEditorTimeout(editor, function () {
editor.on('SetContent BeforeAddUndo Undo Redo keyup', debouncedUpdate);
editor.on('SetContent BeforeAddUndo Undo Redo keydown', function (e) {
if (!isAllowedKeycode(e) && Settings.applyMaxChars(editor) &&
api.getCount() >= Settings.maxChars(editor)) {
e.preventDefault();
e.stopPropagation();
}
});
}, 0);
});
};
function Plugin(delay) {
if (delay === void 0) {
delay = 300;
}
global.add('charactercount', function (editor) {
var api = get(editor);
setup(editor, api, delay);
return api;
});
}
Plugin();
}());
Currently I'm working on a preprocessor for the paste plugin, so that the max_length effects also pasted text. That's why you see the charactercount API in the code.
I am trying to plot the following sample data using a LineChart with a CategoryFilter to filter on year.
Data table is defined as:
aggData: [Date: date][Team: string][Score: number]
From the aggData table I dynamically calculate the default hAxis ticks as
var hAxisTicks = [];
var dateRange = aggData.getColumnRange(0);
for (var date = dateRange.min; date <= dateRange.max; date = new Date(date.getFullYear(), date.getMonth() + 1)) {
hAxisTicks.push(date);
}
The year picker and the line chart are configured as:
var yearPicker = new google.visualization.ControlWrapper({
controlType: 'CategoryFilter',
containerId: 'categoryFilter_div',
options: {
filterColumnIndex: 0,
ui: {
allowTyping: false,
allowMultiple: false,
label: 'Year:',
labelStacking: 'vertical'
},
useFormattedValue: true
}
});
var lineChart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'chart_div',
options: {
width: 900,
height: 500,
hAxis: {
format: 'MMM', ticks: hAxisTicks
}
}
});
I added the following event listener
google.visualization.events.addListener(yearPicker, 'statechange', function () {
google.visualization.events.addOneTimeListener(lineChart, 'ready', getTicks);
});
I need to create/recreate the hAxis ticks everytime the yearPicker changes by calling getTicks
function getTicks() {
var ticks = [];
if (yearPicker.getState().selectedValues.length > 0) {
for (var i = 0; i <= hAxisTicks.length; i = i + 1) {
var date = new Date(hAxisTicks[i]);
if (date.getFullYear() == yearPicker.getState().selectedValues[0]) {
ticks.push(date)
}
}
}
else {
for (var i = 0; i <= hAxisTicks.length; i = i + 1) {
var date = new Date(hAxisTicks[i]);
ticks.push(date);
}
lineChart.setOption('hAxis.ticks', ticks);
lineChart.draw();
}
lineChart.setOption('hAxis.ticks', ticks);
lineChart.draw();
}
Here's what happens at different stages
1- When page first loads the graph looks like (the getTicks function is NOT called) which is correct:
2- When the year is changed to 2019, for example, the hAxis ticks get recalculated (the getTicks function is does get called) and the graph appears to be correct
3- Attempting to go back to the default chart to display all years, an a.getTime is not a function error message appears under the CategoryFilter
4- Any subsequent attempts to change the CategoryFilter to any value throws a ```One or more participants failed to draw()
How can I rectify this behavior?
I realized my iteration over the hAxisTics array was incorrect. I should stop at < hAxisTics.length instead of <= hAxisTics.length and I should recalculate inside the event handler
google.visualization.events.addListener(yearPicker, 'statechange', function () {
var ticks = [];
if (yearPicker.getState().selectedValues.length > 0) {
for (var i = 0; i < hAxisTicks.length; i = i + 1) {
var date = new Date(hAxisTicks[i]);
if (date.getFullYear() == yearPicker.getState().selectedValues[0]) {
ticks.push(date)
}
}
}
else {
for (var i = 0; i < hAxisTicks.length; i = i + 1) {
var date = new Date(hAxisTicks[i]);
ticks.push(date);
}
lineChart.setOption('hAxis.ticks', ticks);
lineChart.draw();
}
lineChart.setOption('hAxis.ticks', ticks);
lineChart.draw();
});
What I need to do to circumvent this issue, because when I request data for 2 months I already receive this error, when there is a break per day, I have the following call. With Little data works perfect, but when I increase the period the server brings me
User request limit reached","type":"OAuthException","is_transient":true,"code":17,"error_subcode":2446079,"fbtrace_id":"...
function solicitacaoAssicrona(){
var service = getService()
var batch = [{"method": "GET", "relative_url":"v3.2/act_1125789557444919/insights/impressions,reach,frequency,spend,campaign_name,account_name,clicks,cost_per_10_sec_video_view,cpm,cpp?level=campaign&since=2016-03-03&until=2019-03-04&time_increment=1&limit=100"}]
// var batchUrl = encodeURIComponent(JSON.stringify(batch));
// Logger.log(batchUrl);
var url = "https://graph.facebook.com?include_headers=false&batch=" + encodeURIComponent(JSON.stringify(batch))
var response = UrlFetchApp.fetch(url, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
var result = JSON.parse(response.getContentText());
Logger.log(result)
// response.forEach(function(resp){
// var resp = JSON.parse(resp.body);
// //Logger.log(JSON.stringify(resp, null, 2));
//
//// resp.data[0].values.forEach(function(response){
////
////
//// })
////
// })
}
I'Ve looked at the documentation, but to the moment without success!
https://developers.facebook.com/docs/marketing-api/insights/best-practices/
That's the call I have
var metricas = [
'impressions',
'reach',
'unique_clicks',
'account_currency',
'account_id',
'account_name',
'ad_id',
'ad_name',
'adset_id',
'adset_name',
'buying_type',
'campaign_id',
'campaign_name',
'clicks',
'cost_per_inline_link_click',
'cost_per_inline_post_engagement',
'cost_per_unique_click',
'cost_per_unique_inline_link_click',
'cpc',
'cpm',
'cpp',
'ctr',
'date_start',
//'date_stop',
'frequency',
'inline_link_click_ctr',
'inline_link_clicks',
'inline_post_engagement',
'objective',
'relevance_score',
'social_spend',
'spend',
'unique_ctr',
'unique_inline_link_click_ctr',
'unique_inline_link_clicks',
'unique_link_clicks_ctr',
//'website_ctr',
'video_10_sec_watched_actions',
'cost_per_10_sec_video_view',
'video_30_sec_watched_actions',
'video_avg_percent_watched_actions',
'video_avg_time_watched_actions',
'video_p100_watched_actions',
'video_p25_watched_actions',
'video_p50_watched_actions',
'video_p75_watched_actions',
'video_play_actions',
'video_thruplay_watched_actions',
'video_p95_watched_actions',
]
var parameters = metricas.join(',');
var url = 'https://graph.facebook.com/v3.2/act_xxxxxxxxxx/insights?fields= + parameters + '&level=ad&time_range[since]=2019-02-05&time_range[until]=2019-04-05&time_increment=1&limit=200'
It's to do with how much data you can retrieve with batch requests. For longer periods, you should divide it into smaller chunks, sequential to each other, thus retrieving the data needed in multiple requests. Have a look at this example:
Code.gs
From line 88 of the file, you can see how it can be divided in multiple requests.
https://github.com/halsandr/Facebook_Connector/blob/master/Code.gs
function dateDelta(dObj, num) {
if (isNaN(num)) {
var dateStart = new Date(dObj);
} else {
var dateStart = new Date(dObj);
var dateStart = new Date(dateStart.setDate(dateStart.getDate() + num));
}
var dd = dateStart.getDate();
var mm = dateStart.getMonth()+1; //January is 0!
var yyyy = dateStart.getFullYear();
if(dd<10){
dd='0'+dd;
}
if(mm<10){
mm='0'+mm;
}
var dateStart = yyyy + "-" + mm + "-" + dd;
return dateStart;
}
var gStartDate = new Date(request.dateRange.startDate);
var gStartDate = new Date(dateDelta(gStartDate, -1));
var gEndDate = new Date(request.dateRange.endDate);
var gEndDate = new Date(dateDelta(gEndDate, +1));
var gRange = Math.ceil(Math.abs(gEndDate - gStartDate) / (1000 * 3600 * 24));
var gBatches = Math.ceil(gRange / 92);
if (gBatches < 2) {
var batch = [{"method": "GET", "relative_url": request.configParams.pageID + "/insights/page_fans,page_impressions,page_post_engagements?since=" + dateDelta(gStartDate) + "&until=" + dateDelta(gEndDate)}];
//console.log(batch);
} else {
batch = [];
var iterRanges = gRange / gBatches;
for (i = 0; i < gBatches; i++) {
var iterStart = dateDelta(gStartDate, (iterRanges * i));
if (i == (gBatches - 1)) {
var iterEnd = dateDelta(gEndDate);
} else {
var iterEnd = dateDelta(gStartDate, (iterRanges * (i + 1)) + 1);
}
batch.push({"method": "GET", "relative_url": request.configParams.pageID + "/insights/page_fans,page_impressions,page_post_engagements?since=" + iterStart + "&until=" + iterEnd})
}
//console.log(batch);
}
// Fetch the data with UrlFetchApp
var url = "https://graph.facebook.com?include_headers=false&batch=" + encodeURIComponent(JSON.stringify(batch))
Can anyone/jssor support help me how to change the images of second and third jssor sliders when slide show position change event trigger from the first jssor slider? I would be so much appreciated.
thanks,
c
this jssor_slider2.$GoTo(1); is not working.
++++++++++++++++++++++++++++++
function OnSlidePositionChange(slideIndex, fromIndex) {
var jssor_slider2 = new $JssorSlider$('slider2_container', { $AutoPlay: false });
if (slideIndex == 3)
jssor_slider2.$GoTo(1);
else
jssor_slider2.$GoTo(slideIndex + 1);
}
jssor_slider1.$On($JssorSlider$.$EVT_POSITION_CHANGE, OnSlidePositionChange);
++++++++++++++++++++++++++++++
<script>
jssor_slider1_starter("slider1_container");
jssor_slider2_starter("slider2_container");
jssor_slider3_starter("slider3_container");
</script>
script.js file
jssor_slider1_starter = function (containerId) {
var jssor_slider1 = new $JssorSlider$(containerId, {
...
}
function OnSlidePositionChange(slideIndex, fromIndex) {
//HELP ME PLEASE HERE.....
//var jssor_slider2 = new $JssorSlider$('slider2_container', {});
//if (slideIndex == 3)
// nestedSliders[1].$GoTo(1);
//else
// nestedSliders[1].$GoTo(slideIndex + 1);
}
jssor_slider1.$On($JssorSlider$.$EVT_POSITION_CHANGE, OnSlidePositionChange);
}
jssor_slider2_starter = function (containerId) {
var jssor_slider2 = new $JssorSlider$(containerId, {
......
}
}
jssor_slider3_starter = function (containerId) {
var jssor_slider3 = new $JssorSlider$(containerId, {
......
}
}
$JssorSlider$.$EVT_POSITION_CHANGE fires continuously while sliding.
$JssorSlider$.$EVT_PARK fires while slide change.
Please do this job this way,
function jssor_slider3_starter(containerId_1, containerId_2, containerId_3)
{
var options1 = {};
var options2 = {};
var options3 = {};
...
var jssor_slider1 = new $JssorSlider$(containerId_1, options1);
var jssor_slider2 = new $JssorSlider$(containerId_2, options2);
var jssor_slider3 = new $JssorSlider$(containerId_3, options3);
...
function OnSlidePark(slideIndex, fromIndex) {
if (slideIndex == 3)
jssor_slider2.$GoTo(1);
else
jssor_slider2.$GoTo(slideIndex + 1);
}
jssor_slider1.$On($JssorSlider$.$EVT_PARK, OnSlidePark);
...
}
I have a couple of forms on a site I'm working on and the script that controls them doesn't include a success message, so when they're submitted the input data just disappears and the user doesn't know if it's been actually sent or not. I've looked around a bit for answers, but because this file controls an email submission form, a contact form, and a twitter feed, it's a bit much for me to see what's what.
Here's the code, I'd just like to let users know that their message has been sent for both the email input form and the contact form. I appreciate any help that's out there!
$(document).ready(function() {
//Set default hint if nothing is entered
setHints();
//Bind JavaScript event on SignUp Button
$('#signUp').click(function(){
signUp($('#subscribe').val());
});
//Bind JavaScript event on Send Message Button
$('#sendMessage').click(function(){
if(validateInput()){
sendMail();
}else
{
alert('Please fill all fields to send us message.');
}
});
//Load initial site state (countdown, twitts)
initialize();
});
var setHints = function()
{
$('#subscribe').attachHint('Enter your email to be notified when more info is available');
$('[name=contact_name]').attachHint('Name');
$('[name=contact_email]').attachHint('Email');
$('[name=contact_subject]').attachHint('Subject');
$('[name=contact_message]').attachHint('Message');
};
var signUp = function(inputEmail)
{
var isValid = true;
var emailReg = /^([\w-\.]+#([\w-]+\.)+[\w-]{2,4})?$/;
if(!emailReg.test(inputEmail)){
isValid = false;
alert('Your email is not in valid format');
}
if(isValid){
var params = {
'action' : 'SingUp',
'email' : inputEmail
};
$.ajax({
type: "POST",
url: "php/mainHandler.php",
data: params,
success: function(response){
if(response){
var responseObj = jQuery.parseJSON(response);
if(responseObj.ResponseData)
{
$('#subscribe').val('');
}
}
}
});
}
};
var initialize = function()
{
var params = {
'action' : 'Initialize'
};
$.ajax({
type: "POST",
url: "php/mainHandler.php",
data: params,
success: function(response){
if(response){
var responseObj = jQuery.parseJSON(response);
if(responseObj.ResponseData)
{
$('ul.twitts').empty();
if(responseObj.ResponseData.Twitts){
$('a.followUsURL').attr('href','http://twitter.com/#!/'+responseObj.ResponseData.Twitts[0].Name);
$.each(responseObj.ResponseData.Twitts, function(index, twitt){
var twitterTemplate = '<li>'
+ '#{0}'
+ '{2}'
+ '<span class="time">{3}</span>'
+ '</li>';
$('ul.twitts').append(StringFormat(twitterTemplate, twitt.Name, twitt.StatusID, twitt.Text, twitt.Date));
});
}
if(responseObj.ResponseData.Start_Date)
{
setInterval(function(){
var countDownObj = calculateTimeDifference(responseObj.ResponseData.Start_Date);
if(countDownObj){
$('#days').text(countDownObj.Days);
$('#hours').text(countDownObj.Hours);
$('#minutes').text(countDownObj.Minutes);
$('#seconds').text(countDownObj.Seconds);
}
}, 1000);
}
}
}
}
});
};
var validateInput = function(){
var isValid = true;
$('input, textarea').each(function(){
if($(this).hasClass('required'))
{
if($(this).val()!=''){
if($(this).hasClass('email'))
{
var emailReg = /^([\w-\.]+#([\w-]+\.)+[\w-]{2,4})?$/;
if(!emailReg.test($(this).val())){
isValid = false;
alert('Your email is not in valid format');
}
}
}else
{
isValid = false;
}
}
});
return isValid;
};
var resetInput = function(){
$('input, textarea').each(function() {
$(this).val('').text('');
});
};
var sendMail = function(){
var params = {
'action' : 'SendMessage',
'name' : $('[name=contact_name]').val(),
'email' : $('[name=contact_email]').val(),
'subject' : $('[name=contact_subject]').val(),
'message' : $('[name=contact_message]').val()
};
$.ajax({
type: "POST",
url: "php/mainHandler.php",
data: params,
success: function(response){
if(response){
var responseObj = jQuery.parseJSON(response);
if(responseObj.ResponseData)
$('label.sendingStatus').text(responseObj.ResponseData);
}
resetInput();
$('#sendMail').removeAttr('disabled');
},
error: function (xhr, ajaxOptions, thrownError){
//xhr.status : 404, 303, 501...
var error = null;
switch(xhr.status)
{
case "301":
error = "Redirection Error!";
break;
case "307":
error = "Error, temporary server redirection!";
break;
case "400":
error = "Bad request!";
break;
case "404":
error = "Page not found!";
break;
case "500":
error = "Server is currently unavailable!";
break;
default:
error ="Unespected error, please try again later.";
}
if(error){
$('label.sendingStatus').text(error);
}
}
});
};
var calculateTimeDifference = function(startDate) {
var second = 1000;
var minute = second * 60;
var hour = minute * 60;
var day = hour * 24;
var seconds = 0;
var minutes = 0;
var hours = 0;
var days = 0;
var currentDate = new Date();
startDate = new Date(startDate);
var timeCounter = startDate - currentDate;
if (isNaN(timeCounter))
{
return NaN;
}
else
{
days = Math.floor(timeCounter / day);
timeCounter = timeCounter % day;
hours = Math.floor(timeCounter / hour);
timeCounter = timeCounter % hour;
minutes = Math.floor(timeCounter / minute);
timeCounter = timeCounter % minute;
seconds = Math.floor(timeCounter / second);
}
var tDiffObj = {
"Days" : days,
"Hours" : hours,
"Minutes" : minutes,
"Seconds" : seconds
};
return tDiffObj;
};
var StringFormat = function() {
var s = arguments[0];
for (var i = 0; i < arguments.length - 1; i++) {
var regExpression = new RegExp("\\{" + i + "\\}", "gm");
s = s.replace(regExpression, arguments[i + 1]);
}
return s;
}
You need to hook into the success callbacks of each of the $.ajax calls. You can create a method that will show a message for those:
For example, your signUp function's success callback could look like:
success: function(response){
if(response){
var responseObj = jQuery.parseJSON(response);
if(responseObj.ResponseData)
{
$('#subscribe').val('');
showMessage('Your subscription was received. Thank you!');
}
}
}
And you just create a method that will show the message to the user
var showMessage = function (msg) {
// of course, you wouldn't use alert,
// but would inject the message into the dom somewhere
alert(msg);
}
You would call showMessage anywhere the success callback was fired.
You can add your success notifing code in each of the $.ajax success handlers.