Jump to content

Graham Quince

Administrators
  • Posts

    2,046
  • Joined

  • Last visited

Everything posted by Graham Quince

  1. @ADT - well this thread talks about Adam's custom widget, so I was just checking. Have you reported it to the service desk?
  2. Is that just the regular create event widget?
  3. Glitter Text A less distracting option for the festive season is: Hard to depict in a screenshot, but the white dots twinkle / sparkle. To change the message, simply adapt the line: <h1 class="christmas">Seasons Greetings!</h1> Here's the full code: <style> @import url(https://fonts.googleapis.com/css?family=Mountains+of+Christmas:700); .christmas-blue { color: #035ee2; background: -webkit-linear-gradient(transparent, transparent), url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/191814/blue_glitter.gif) repeat; background: -o-linear-gradient(transparent, transparent) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; margin: 0; padding: 0; font-weight: 900; width: 100%; text-align: center; letter-spacing: 1px; z-index: 999999; -webkit-background-clip: text; } .christmas-gold { color: #D81E1E; color: gold; background: -webkit-linear-gradient(transparent, transparent), url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/191814/gold_glitter.gif) repeat; background: -o-linear-gradient(transparent, transparent) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; margin: 0; padding: 0; font-weight: 900; width: 100%; text-align: center; letter-spacing: 1px; z-index: 999999; -webkit-background-clip: text; } .christmas { font-size: 100px; line-height: 100px; text-align: center; color: #000000; font-family: 'Mountains of Christmas', cursive; } </style> <h1 class="christmas">Seasons Greetings!</h1> <script> var christmasText = arguments[0].find('.christmas'); function glitterLetters() { christmasArray = christmasText.text().split(''); christmasText.empty(); for (var i = 0; i < christmasArray.length; i++) { christmasText.append( '<span class="christmas-' + (i % 2 == 0 ? 'gold' : 'blue') + '">' + christmasArray[i] + '</span>' ) } } glitterLetters(); </script>
  4. Flying Santa If anyone would like a Flying Santa for the Dashboards, then I found and adjusted the code below. To use, you'll need to upload a gif to somewhere on the same site, I prefer to use a Text widget for this, as you can right-click on the image and get the URL. Once you've copied the URL, you can hide the widget and add it to the code, like so: background: url('WEB_ADDRESS_OF_SANTA_GIF'); becomes: background: url('/app/file/asset/A273372C200303B6297B8F7901942B050783045C6F3B715C'); <!-- GIF from https://www.animatedimages.org/cat-santa-claus-359.htm --> <style> .ui-theme-basicnavigation-wrapmain { overflow-x: hidden; } .santa { background: url('WEB_ADDRESS_OF_SANTA_GIF'); animation-name: sleigh; animation-duration: 10s; animation-iteration-count: infinite; width: 350px; height: 120px; position: fixed; z-index: 1; -moz-transform: scaleX(-1); -o-transform: scaleX(-1); -webkit-transform: scaleX(-1); transform: scaleX(-1); filter: FlipH; -ms-filter: "FlipH"; } /* The animation code */ @keyframes sleigh { 0% { left: -550px; top: 0px; } 33% { top: 500px; } 66% { top: 100px; } 100% { left: calc(100vw + 350px); top: 0px; } } </style> <div class="santa"></div> I used this GIF: https://www.animatedimages.org/cat-santa-claus-359.htm Feedback from the team though was this was particularly distracting, if you alter the line to change the value of 10vw, you can increase the distance Santa flies so he is off screen longer. left: calc(100vw + 350px);
  5. Hi @Sue Busher Inspired by some other recent work, I've put together a new Academy product as a Staff Directory: There's an HTML widget which uses the Users API to display a table of all Staff, Admins and Governor profiles. It then cross-references a form staff need to complete so they tag their own department, room and extension. Being based in an HTML widget, it's simple to remove columns for photos etc... When Parents / Students view the same, they can only see the entries made in the Your Details form, so it will be sparse until most staff complete the form. There's the "Who has filled in my form?" widget so you can quickly see who you need to chase. The Your Details form allows staff to supplement their data (I've shortened the department list) for the screenshot. Staff can send a message if their name / email is wrong in Frog
  6. This bit of code took a lot more faffing than I was expecting, but I think it might be useful. Imagine you want to display a random tip from a bank of tips each time someone logs in: Add a noticeboard Hide the Refresh options Get the noticeboard's UUID and add the following code: <div class="styling"></div> <script> var noticeboardUUID = '5594BCA620028E9D37048F60FB777D056CBF7E6CC2DFC92B'; function shuffle(array) { let currentIndex = array.length, randomIndex; while (currentIndex != 0) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; // And swap it with the current element. [array[currentIndex], array[randomIndex]] = [ array[randomIndex], array[currentIndex]]; } return array; } arguments[0].find('.styling').append( '<style>'+ 'div[data-content-uuid="' + noticeboardUUID + '"] .notice-table {'+ 'display: none;'+ '}'+ '</style>' ); setTimeout(function(){ tips = $('div[data-content-uuid="' + noticeboardUUID + '"]').find('.notice-table'); var tipsArray = []; $.each(tips.find('.topic-row'), function (key, tip) { tipsArray.push( $(this).attr('class') ); $(this).hide(); }); shuffle(tipsArray); var classToShow = tipsArray[0].split(' '); tips.find('.'+classToShow[3]).show(); tips.show(); }, 3000); </script>
  7. I loved both of these ideas when Martyn shared them with me - which he did while working through the Frog Genius course.
  8. I've just had a thought. Frog's Calendars could actually serve this purpose. I could put together a widget which allowed the students to quickly add events to their calendar. I think they could delete and amend them directly AND if so, i could include a "tag" in the title to highlight when the item is completed. Teachers would be able to add To Do Events to their class (probably) and be able to view all the events for a student either by going to My Class. and viewing their calendar or it would be simple enough to build in a listener for the User Select widget. Does this cover everything a To-Do List / Student-compete Planner needs to do?
  9. Just in time for autumn, I've adapted @Sean_M's code for falling leaves: <script> var widthArray = [], sA = [10,11,12], timeArray = [2,4,6,8,10,12,14], sizeArray = [20,30,40], coloursArray = ['#B31218','#FFB900','#A29A0F','#E28204','#D83708'], leafArray = ['&#127809;', '&#127810;', '<i class="fa fa-pagelines"></i>','<i class="fa fa-leaf"></i>']; function randomise(arraytoUse) { return arraytoUse[Math.floor(Math.random() * arraytoUse.length)]; } for (var i = 0; i < $(window).innerWidth(); i++) { widthArray.push(i) }; for (var i = 0; i < 15; i++) { $('<div class="leaf" style="position: fixed; color: '+randomise(coloursArray)+'; top: -20px; left: '+randomise(widthArray)+'px; font-size: '+randomise(sizeArray)+'px;">'+randomise(leafArray)+'</div>').appendTo( this.element.closest('.app-sites') ) }; $('.leaf').each(function(){ var el = $(this) setTimeout(function(){ el.animate({'top' : '100%'}, randomise(sA) * 1000, function(){ $(this).css('top', -20); setInterval(function(){ el.animate({'top' : '100%'}, randomise(sA) * 1000, function(){ $(this).css('top', -20); })}, randomise(timeArray) * 1000); }) }, randomise(timeArray) * 1000); }); </script>
  10. Graham Quince

    SSO's?

    Yes, please. The Service Desk will need to configure the settings in Frog and I think they also have to contact SchoolCloud to have them configure settings.
  11. Graham Quince

    SSO's?

    Just Staff SSO, I'm afraid.
  12. Hi, We are aware of this issue, and it's been addressed. Unfortunately the fix does require an update to your platforms as well as a release to the app. It's expected to be out in the next update. It's currently in testing.
  13. it came very close, but all the extra requirements you added meant it was becoming too difficult to debug - so I gave up. Sorry.
  14. Yeah - this is why I need help testing it - I need real world examples so I can spot the differences in the API returned data. I know I could ask the Devs, but they are pretty busy at the moment.
  15. Send me a message to where it is. Did you set the UUID?
  16. The above code works for FrogCode widgets, this code works for the HTML widgetL <script> $('div[data-content-uuid="SELECT_USER_WIDGET_CONTENT_UUID"]').on('broadcast.selectedUser',function(el, ev) { console.log(ev); console.log("user name = "+ev.model.displayname); console.log("user uuid = "+ev.model.uuid); }); </script>
  17. The things I do for you: <style> .assignmentReportsTables td, .assignmentReportsTables th { text-align: center; vertical-align: middle; line-height: 25px; height: 54px; } .assignmentReportsTables { font-size: 16px; line-height: 25px; } .hw { min-width: 50px; height: 50px; line-height: 25px; vertical-align: middle; overflow: hidden; border: 1px solid #CCCCCC; text-align: center; background: #ffffff; float: left; margin-right: 2px; margin-bottom: 2px; } .hw:hover { background: #CCCCCC; } .hw .status { position: relative; background-size: cover; height: 24px; width: 24px; margin-left: auto; margin-right: auto; font-weight: bold; } .hw .bottom-right { position: absolute; right: -14px; bottom: -1px; width: 15px; height: 15px; line-height: 15px; font-size: 13px; background-color: #000; color: #ffffff; } .hw .late { background: #FF0000; } .hw .absent { background: #000000; } .hws { width: 50%; } .childHeading { font-size: 25px; font-weight: bold; line-height: 35px; } </style> <div class="AssignmentSummary"></div> <script> var startOfYear = moment('1/9/2021 1:00', "D/M/YYYY H:mm").unix(); var AssignmentSummary = arguments[0].find('.AssignmentSummary'); var user = FrogOS ? FrogOS.getUser() : self.getUser(); function getAssignments(view,child_uuid) { var self = this; var assignmentsObject = {}; AssignmentSummary.empty(); var data = { end_from: startOfYear, end_to: parseInt(moment()/1000), status: 'closed', order: 'start desc', } if (view !== 'student') { data = { end_from: startOfYear, end_to: parseInt(moment()/1000), status: 'closed', order: 'start desc', assigned_user: child_uuid } } AssignmentSummary.append( '<table class="assignmentReportsTables table-hover table-bordered table sum_'+child_uuid+'">'+ '<tr>'+ '<th>Subject</th>'+ '<th>No. of assignments</th>'+ '<th>Average Mark</th>'+ '<th>Late Hand In</th>'+ '<th>Not done</th>'+ '<th>Homeworks</th>'+ '</tr>'+ '</table>' ); var myMarks = AssignmentSummary.find('.sum_'+child_uuid); FrogOS.fdp({ url: 'assignment/getAssigned', data }).done(function(response) { var homeworks = response.response.assignments; var SubjectsArray = []; $.each(homeworks, function(index,homework) { var subject = homework.assignment.subject.name; var subjectClass = subject.replace(/\s/g, "").replace("&", ""); if (SubjectsArray.indexOf(subject) < 0) { // Add all unique subjects as a row SubjectsArray.push(subject); myMarks.append( '<tr>'+ '<td>'+subject+'</td>'+ '<td class="'+subjectClass+'_total" >0</td>'+ '<td class="'+subjectClass+'_average" >0</td>'+ '<td class="'+subjectClass+'_late">0</td>'+ '<td class="'+subjectClass+'_notdone">0</td>'+ '<td class="'+subjectClass+'_hws hws"></td>'+ '</tr>' ) assignmentsObject[subject] = { total:0, massMarks: 0, totalMarked: 0, late: 0, notdone: 0 } }; // end of all unique subjects var lateAbsent = ''; var completed = homework.user_info.completed; var duedate = homework.assignment.end; if (completed > duedate) { lateAbsent = '<div class="bottom-right late">L</div>'; assignmentsObject[subject].late += 1; } if (homework.user_info.status == "absent") { lateAbsent = '<div class="bottom-right absent">A</div>'; } if (homework.user_info.status == "notdone") { assignmentsObject[subject].notdone += 1; } assignmentsObject[subject].total += 1; var markscheme = ''; if (homework.user_info.mark !== null) { // IF the homework has been marked if (homework.assignment.mark_scheme.name !== 'markscheme.percentage.name' ) { var grades = homework.assignment.mark_scheme.data_values.grades; assignmentsObject[subject].massMarks += parseInt(grades[homework.user_info.mark]); } var markscheme = ' (Mark Scheme: '+homework.assignment.mark_scheme.name+')'; if (markscheme == ' (Mark Scheme: markscheme.percentage.name)') { assignmentsObject[subject].massMarks += homework.user_info.mark; markscheme = ' (Mark Scheme: Percent)'; } assignmentsObject[subject].totalMarked += 1; } else { // end of if homework marked homework.user_info.mark = 'N/A'; } if (homework.user_info.status == 'ontime') { homework.user_info.status = 'ready'; // makes a tick } if (homework.user_info.status == null) { homework.user_info.status = 'inprogress'; // makes a grey tick } if (homework.user_info.status && homework.user_info.mark == "N/A") { homework.user_info.status = "notdone"; } myMarks.find('.'+subjectClass+'_total').text(assignmentsObject[subject].total); myMarks.find('.'+subjectClass+'_average').text(parseInt(assignmentsObject[subject].massMarks/assignmentsObject[subject].totalMarked)+'%'); if (myMarks.find('.'+subjectClass+'_average').text() == 'NaN%') { myMarks.find('.'+subjectClass+'_average').text('-'); } myMarks.find('.'+subjectClass+'_late').text(parseInt(100*assignmentsObject[subject].late/assignmentsObject[subject].total)+'%'); myMarks.find('.'+subjectClass+'_notdone').text(parseInt(100*assignmentsObject[subject].notdone/assignmentsObject[subject].total)+'%'); myMarks.find('.'+subjectClass+'_hws').append( '<div class="hw" title="'+homework.assignment.name+markscheme+'" data-assignment-link="' + homework.assignment.link + '">'+ homework.user_info.mark+ '<div class="center status ui-svg-icon-'+homework.user_info.status+'">'+ lateAbsent+ '</div>' ); }) // end of $.each }).fail(function(e) { console.log("FAILED"); }); }; // End of GetAssignments function $(AssignmentSummary).on('click', '.hw', function(el){ $(this).trigger('os.app.siteviewer', { data: { site: el.currentTarget.dataset.assignmentLink } }); }); if (user.profile.type == 'student') { getAssignments('student',user.uuid); } else { $('div[data-content-uuid="SELECT_USER_WIDGET_CONTENT_UUID"]').on('broadcast.selectedUser',function(el, ev) { getAssignments('parent',ev.model.uuid); }); } </script>
  18. Almost a year and no issues. I think it's safe to say we've all moved on
  19. Just tidying up the forum. I believe this issue was sorted through investigation with the service desk
  20. If you hover the mouse over an assignment tile, it's displayed along with the mark scheme
  21. Just been experimenting with this for a school and thought others might like the idea: <style> .assignmentReportsTables td, .assignmentReportsTables th { text-align: center; vertical-align: middle; line-height: 25px; height: 54px; } .assignmentReportsTables { font-size: 16px; line-height: 25px; } .hw { min-width: 50px; height: 50px; line-height: 25px; vertical-align: middle; overflow: hidden; border: 1px solid #CCCCCC; text-align: center; background: #ffffff; float: left; margin-right: 2px; margin-bottom: 2px; } .hw:hover { background: #CCCCCC; } .hw .status { position: relative; background-size: cover; height: 24px; width: 24px; margin-left: auto; margin-right: auto; font-weight: bold; } .hw .bottom-right { position: absolute; right: -14px; bottom: -1px; width: 15px; height: 15px; line-height: 15px; font-size: 13px; background-color: #000; color: #ffffff; } .hw .late { background: #FF0000; } .hw .absent { background: #000000; } .hws { width: 50%; } .childHeading { font-size: 25px; font-weight: bold; line-height: 35px; } </style> <div class="AssignmentSummary"></div> <script> var startOfYear = moment('1/9/2021 1:00', "D/M/YYYY H:mm").unix(); var AssignmentSummary = arguments[0].find('.AssignmentSummary'); var user = FrogOS ? FrogOS.getUser() : self.getUser(); function getAssignments(view,child_uuid) { var self = this; var assignmentsObject = {}; var myMarksSpace = AssignmentSummary; var data = { end_from: startOfYear, end_to: parseInt(moment()/1000), status: 'closed', order: 'start desc', } if (view !== 'student') { data = { end_from: startOfYear, end_to: parseInt(moment()/1000), status: 'closed', order: 'start desc', assigned_user: child_uuid } myMarksSpace = AssignmentSummary.find('.child_'+child_uuid); } myMarksSpace.append( '<table class="assignmentReportsTables table-hover table-bordered table sum_'+child_uuid+'">'+ '<tr>'+ '<th>Subject</th>'+ '<th>No. of assignments</th>'+ '<th>Average Mark</th>'+ '<th>Late Hand In</th>'+ '<th>Not done</th>'+ '<th>Homeworks</th>'+ '</tr>'+ '</table>' ); var myMarks = myMarksSpace.find('.sum_'+child_uuid); FrogOS.fdp({ url: 'assignment/getAssigned', data }).done(function(response) { var homeworks = response.response.assignments; var SubjectsArray = []; $.each(homeworks, function(index,homework) { /*if (homework.assignment.subject.name == "Chemistry") { console.log(homework); }*/ var subject = homework.assignment.subject.name; var subjectClass = subject.replace(/\s/g, "").replace("&", ""); if (SubjectsArray.indexOf(subject) < 0) { // Add all unique subjects as a row SubjectsArray.push(subject); myMarks.append( '<tr>'+ '<td>'+subject+'</td>'+ '<td class="'+subjectClass+'_total" >0</td>'+ '<td class="'+subjectClass+'_average" >0</td>'+ '<td class="'+subjectClass+'_late">0</td>'+ '<td class="'+subjectClass+'_notdone">0</td>'+ '<td class="'+subjectClass+'_hws hws"></td>'+ '</tr>' ) assignmentsObject[subject] = { total:0, massMarks: 0, totalMarked: 0, late: 0, notdone: 0 } }; // end of all unique subjects var lateAbsent = ''; var completed = homework.user_info.completed; var duedate = homework.assignment.end; if (completed > duedate) { lateAbsent = '<div class="bottom-right late">L</div>'; assignmentsObject[subject].late += 1; } if (homework.user_info.status == "absent") { lateAbsent = '<div class="bottom-right absent">A</div>'; } if (homework.user_info.status == "notdone") { assignmentsObject[subject].notdone += 1; } assignmentsObject[subject].total += 1; var markscheme = ''; if (homework.user_info.mark !== null) { // IF the homework has been marked if (homework.assignment.mark_scheme.name !== 'markscheme.percentage.name' ) { var grades = homework.assignment.mark_scheme.data_values.grades; assignmentsObject[subject].massMarks += parseInt(grades[homework.user_info.mark]); } var markscheme = ' (Mark Scheme: '+homework.assignment.mark_scheme.name+')'; if (markscheme == ' (Mark Scheme: markscheme.percentage.name)') { assignmentsObject[subject].massMarks += homework.user_info.mark; markscheme = ' (Mark Scheme: Percent)'; } assignmentsObject[subject].totalMarked += 1; } else { // end of if homework marked homework.user_info.mark = 'N/A'; } if (homework.user_info.status == 'ontime') { homework.user_info.status = 'ready'; // makes a tick } if (homework.user_info.status == null) { homework.user_info.status = 'inprogress'; // makes a grey tick } if (homework.user_info.status && homework.user_info.mark == "N/A") { homework.user_info.status = "notdone"; } myMarks.find('.'+subjectClass+'_total').text(assignmentsObject[subject].total); myMarks.find('.'+subjectClass+'_average').text(parseInt(assignmentsObject[subject].massMarks/assignmentsObject[subject].totalMarked)+'%'); if (myMarks.find('.'+subjectClass+'_average').text() == 'NaN%') { myMarks.find('.'+subjectClass+'_average').text('-'); } myMarks.find('.'+subjectClass+'_late').text(parseInt(100*assignmentsObject[subject].late/assignmentsObject[subject].total)+'%'); myMarks.find('.'+subjectClass+'_notdone').text(parseInt(100*assignmentsObject[subject].notdone/assignmentsObject[subject].total)+'%'); myMarks.find('.'+subjectClass+'_hws').append( '<div class="hw" title="'+homework.assignment.name+markscheme+'" data-assignment-link="' + homework.assignment.link + '">'+ homework.user_info.mark+ '<div class="center status ui-svg-icon-'+homework.user_info.status+'">'+ lateAbsent+ '</div>' ); }) // end of $.each }).fail(function(e) { console.log("FAILED"); }); }; // End of GetAssignments function $(AssignmentSummary).on('click', '.hw', function(el){ $(this).trigger('os.app.siteviewer', { data: { site: el.currentTarget.dataset.assignmentLink } }); }); if (user.profile.type == 'student') { getAssignments('student',user.uuid); } else { Frog.Model.api('users.getChildren').done(function(listResponse) { var children = listResponse.data; $.each(children, function(index,child) { AssignmentSummary.append( '<div class="childHeading">'+ child.displayname+"'s Assignment Summary</div>"+ '<div class="child_'+child.uuid+'">'+ '</div><hr>' ); getAssignments('parent',child.uuid); }); }); } </script> I'm not sure I'll turn this into a widget as there's so many parameters to adapt - I don't think I've caught all the marking possibilities yet either. Each individual homework tile opens the homework, I had to include markschemes in the tile's Title tag as it was possible to have a 5 in GCSE and another homework have a 5 for Effort. I'd be interested in feedback on this, if anyone wants to try it out.
  22. Here's the code snippet required should you wish to trigger a growl in FrogLearn: Frog.Controller.prototype.growl('Quick alert','HTML Widget','app-name',{time:5000, icon: 'sites/widget/1D88867A2001BB391A801F0DE1E6D50A0244F78C1CDBCD72/icon.png'}); (The time variable is the length of time in milliseconds that the growl will appear for.)
  23. I always struggle to remember the format needed to call an API, so thought it might make sense to have them here for copy-and-paste-and-adapt purposes Internal* Frog API (GET) Frog.Model.api('API_URL_GOES_HERE', { param1: 'PARAM1', param2: 'PARAM2' }).done(function(response) { // do something with the response data var data = response; }).fail(function(e) { // Report Error console.log("failed"); }); Internal Frog API (POST) Frog.Model.api('API_URL_GOES_HERE', { param1: 'PARAM1', param2: 'PARAM2' },{ type: 'POST' }).done(function(response) { // do something with the response data var data = response; }).fail(function(e) { // Report Error console.log("failed"); }); FDP API (GET) FrogOS.fdp({ url: 'API_URL_GOES_HERE', path: '/api/fdp/2/', data: { param1: 'PARAM1', param2: 'PARAM2' } }).done(function(response) { // do something with the response data var data = response; }).fail(function(e) { // Report Error console.log("failed"); }); FDP API (POST) FrogOS.fdp({ url: 'API_URL_GOES_HERE', path: '/api/fdp/2/', type: 'POST', data: { param1: 'PARAM1', param2: 'PARAM2' } }).done(function(response) { // do something with the response data var data = response; }).fail(function(e) { // Report Error console.log("failed"); }); * Internal APIs are subject to change by our developers. FDP APIs are set in stone. You can use the Network tab in your browser's Developer Console to identify an internal API and its required parameters. On each of your Frog platforms, there is an application called FDP API Reference (if it's not visible, you may need to publish this via Package Manager). Within this, you'll find a list of all the FDP APIs, their URLs and available parameters. The one element this application lacks is the above example, but hopefully this will help with that.
  24. “Give a man a program, frustrate him for a day. Teach a man to program, frustrate him for a lifetime.” Muhammad Wasee0m ?
×
×
  • Create New...