Jump to content

Graham Quince

Administrators
  • Posts

    2,046
  • Joined

  • Last visited

Everything posted by Graham Quince

  1. It was very quiet in the last couple of days leading up to Christmas, so I finally got a chance to put together an advent calendar. Obviously too late for 2023, so all the links are set up for December 2024. There's 48 images on the front page, with Rules managing their visibility. Each "door" links to a different hidden page. There is a fun bit of trivia on each page, but I'd strongly encourage you to edit this and make it your own - you could add: prizes quizzes walls pictures videos messages from teachers You can find it on the FrogStore along with an example with a few open pages. https://www.frogeducation.com/frogstore/content/advent
  2. Love the King's speech stat!
  3. I'll try to find some school contacts for you from the big FrogSnap users, but that's an interesting position by your data team. I take it all the controls around clearing images held no sway with them?
  4. Hi Paul, I'm sorry you're having issues with the signage widget. I'll drop you a line and we can discuss it. Graham
  5. Using the Pencil icon on the Quick launch, you can remove all the links you've set Globally and for yourself, but you can't remove links individuals have made. These links are by definition the links an individual wants quick access to.
  6. ePortfolio Embed and My Notifications both use a model connected to ePortfolios. It's a simple line change, but we were stuck waiting for everyone to get to Turing.
  7. Hi George, We're aware of an issue with a couple of frogcode widgets, but the fix will break pre-Turing schools. I'll get them onto your platform today.
  8. Hi everyone, It seems with the ongoing, ummm... issues with Twitter, that the latest feature to be removed is embedding tweets. I've got this happening on one test platform, is it happening elsewhere? We might need to pull the widget if it can no longer be used. Such a shame Graham
  9. Just had a case where we needed to display the form data in a table: <div class="refresh"> <span class="ff-refresh-mono"></span> Refresh </div> <div style="float: right;" class="btn download_doc"> <span class="ff-download-mono"></span> Download for MS Word </div> <div class="docx"> <div class="WordSection1"> <table class="table table-bordered table-hover my_data"></table> </div> </div> <script> var refreshButtonOBJ = arguments[0].find('.refresh'); var downloadDOC = arguments[0].find('.download_doc'); var docx = arguments[0].find('.docx'); var myDataDiv = arguments[0].find('.my_data'); var user = FrogOS.getUser(); var formUUID = 'FORM_UUID'; function getObjSummary() { myDataDiv.empty(); Frog.Model.api('dataviewer.gettable', { content_uuid: formUUID, current_user_only: 'false', form_uuid: formUUID, limit: 50, module: 'form', offset: '0', sort_dir: 'DESC', sort_field: 'date' }).done(function(response) { var submissions = response.data; myDataDiv.append('<tr class="headerrow"></tr>'); var headers = submissions[0].fields; $.each(headers, function(ind,field) { if (field.type !== 'freetext') { // Freetext is the text widget field myDataDiv.find('.headerrow').append( '<th>'+field.label+'</th>' ); } }); $.each(submissions, function(index, submission) { myDataDiv.append('<tr class="sub_'+index+'""></tr>'); var fields = submission.fields; $.each(fields, function(index1,field) { if (field.type !== 'freetext') { myDataDiv.find('.sub_'+index).append( '<td>'+ field.responses[0].response+ '</td>' ); } }) }); }).fail(function(e) { console.log('Failed to load form'); }); } getObjSummary(); refreshButtonOBJ.click(function(){ getObjSummary(); }); downloadDOC.click(function(){ var html, link, blob, url, css; // EU A4 use: size: 841.95pt 595.35pt; css = ( '<style>' + '@page WordSection1{size: 841.95pt 595.35pt;mso-page-orientation: landscape;}' + 'div.WordSection1 {page: WordSection1;}' + 'table{border-collapse:collapse;}td{border:1px gray solid;width:5em;padding:2px;}'+ '</style>' ); console.log(docx); html = docx[0].innerHTML; blob = new Blob(['\ufeff', css + html], { type: 'application/msword' }); url = URL.createObjectURL(blob); link = document.createElement('A'); link.href = url; // Set default file name. // Word will append file extension - do not add an extension here. link.download = user.displayname+' Objectives Summary'; document.body.appendChild(link); if (navigator.msSaveOrOpenBlob ) navigator.msSaveOrOpenBlob( blob, 'Document.doc'); // IE10-11 else link.click(); // other browsers document.body.removeChild(link); }); </script> <style> .refresh { float: left; color: #919191; cursor: pointer; margin-bottom: 15px; margin-right: 15px; } </style> With a handy option to export this as a word doc too.
  10. @pconkie has updated the Multifile Upload widget - mainly to optimise loading times - it's a very clever implementation for storing the details of files uploaded. You can download the latest version (version: 0.3.2) from the community site: https://www.frogeducation.com/frogstore/widget/multi-file-upload Thank you Paul!
  11. Do these housekeeping reminders help? I'm interested to know how we can better support you removing old users and classes
  12. I built this a while back and its come in quite handy. Date Setter allows admins to set the date for other widgets, such as the MIS Linked Documents widget. The official widget requires parents to select a date, but with date setter, you can set the start date to the first of September and leave it all year. https://www.frogeducation.com/frogstore/widget/date-setter
  13. Here's a cute bit of code that shows that Javascript can read your laptop or Android's battery: <style> .battery_level { font-size: 30px; font-weight: bold; border: 1px solid #cccccc; border-radius: 6px; padding: 20px; } </style> <div class="battery_level"></div> <script> var batteryDiv = arguments[0].find('.battery_level'); let isBatterySupported = 'getBattery' in navigator; if(!isBatterySupported) { batteryDiv.html('Battery not supported'); } else { let batteryPromise = navigator.getBattery(); batteryPromise.then(batteryCallback); function batteryCallback(batteryObject) { var percent = batteryObject.level*100; batteryDiv.html('Your battery is at: '+percent+' %'); } } </script> Probably not of tremendous use, I suppose you could use to remind students to plug in.
  14. A little while back I noticed a new feature in Chrome: Some websites, (including Frog) are setup as Progressive Web Apps (PWAs). If you choose this function, Chrome will create and install on your computer a browser app called Frog OS, with no address bar, separate shortcut on the toolbar. It's searchable in Windows' Start Menu too: Any external links will open in a regular browser and it behaves like a regular browser, but with most features missing. In short, it's treating the platform like a standalone program. Has anyone else tried this out? Can you see a use for this?
  15. I've been playing around with this today, it's more complicated now, but I think I have it: <style> select[id="9EC520B82003FFC1B8C84F291890790236728F8C3D26BB0A"], select[id="9EC520AF2003FBC0C1F0AF732938E9061A807D2CA7348E03"], select[id="9EC520B52003FEABEA582FCAEEEEE90DD087E7DCE9009A4A"] { display: none; } </style> <script> setTimeout(function(){ var form = $('div[data-content-uuid="9EC51EEE200287452C5BFFA9D479C00C908DF88CDDE54F77"]'); var select1 = '9EC520B82003FFC1B8C84F291890790236728F8C3D26BB0A'; var select2 = '9EC520AF2003FBC0C1F0AF732938E9061A807D2CA7348E03'; var select3 = '9EC520B52003FEABEA582FCAEEEEE90DD087E7DCE9009A4A'; form.find('select').show(); var currentSelections = {}; currentSelections[select1] = ''; currentSelections[select2] = ''; currentSelections[select3] = ''; form.on('change', 'select', function() { var selectArray = [select1,select2,select3]; var index = selectArray.indexOf(this.id); selectArray.splice(index, 1); for (var i = 0; i < selectArray.length; i++) { form.find('select[id="'+selectArray[i]+'"]').find('option[value="'+currentSelections[this.id]+'"]').show(); } currentSelections[this.id] = this.value; for (var i = 0; i < selectArray.length; i++) { form.find('select[id="'+selectArray[i]+'"]').find('option[value="'+this.value+'"]').hide(); } }); }, 2000); </script> First off, I hide the select options, to give Frog a chance to load the form before the timeout function runs: <style> select[id="9EC520B82003FFC1B8C84F291890790236728F8C3D26BB0A"], select[id="9EC520AF2003FBC0C1F0AF732938E9061A807D2CA7348E03"], select[id="9EC520B52003FEABEA582FCAEEEEE90DD087E7DCE9009A4A"] { display: none; } </style> Then after two seconds (2000), the HTML widget finds the form and shows the select options. I've also listed the three select dropdowns I care about: setTimeout(function(){ var form = $('div[data-content-uuid="9EC51EEE200287452C5BFFA9D479C00C908DF88CDDE54F77"]'); var select1 = '9EC520B82003FFC1B8C84F291890790236728F8C3D26BB0A'; var select2 = '9EC520AF2003FBC0C1F0AF732938E9061A807D2CA7348E03'; var select3 = '9EC520B52003FEABEA582FCAEEEEE90DD087E7DCE9009A4A'; form.find('select').show(); ... }, 2000); Next, I've made an object to hold a history, so that a user can update their choices and not lose the original options from the other dropdowns: var currentSelections = {}; currentSelections[select1] = ''; currentSelections[select2] = ''; currentSelections[select3] = ''; Then the code waits for a change to any of the dropdowns. @ADT - you have a couple of other dropdowns in your form which might cause an issue with the history. I'd suggest swapping these for radio buttons. On selecting an option, the function creates an array of all three dropdown IDs, then identifies which dropdown was selected and removes that from the list. (This prevents the selected option disappearing from it too). The function then runs through all the dropdowns, turning back on any from the history, before updating the history with the new selection and hiding that selection from the other two dropdowns. form.on('change', 'select', function() { var selectArray = [select1,select2,select3]; var index = selectArray.indexOf(this.id); selectArray.splice(index, 1); for (var i = 0; i < selectArray.length; i++) { form.find('select[id="'+selectArray[i]+'"]').find('option[value="'+currentSelections[this.id]+'"]').show(); } currentSelections[this.id] = this.value; for (var i = 0; i < selectArray.length; i++) { form.find('select[id="'+selectArray[i]+'"]').find('option[value="'+this.value+'"]').hide(); } }); To use, you'll need the Form widget's UUID and the ID's of each select / dropdown: @ADT - I'm blocked from saving HTML on Gosforth, so you'll have to copy the code from the top box. I had to make a copy of the site, so the UUID and IDs might be different.
  16. I know we have Paul's excellent Exam Timetables widget, but I've just been helping a school who couldn't get it to work. They're using SIMS Exam system for another purpose, and needed to display the PDFs to students. I don't know the Exam timetabler all that well, but the school in question had a single PDF produced with 500 students on it. They'd already begun the process of saving the individual pages as separate documents, so I suggested we use the File Drop widget to hold them and show only the matching PDF to the student: <div class="File_PDF"></div> <script> var File_PDF = arguments[0].find('.File_PDF'); var baseURL = Frog.Utilities.getBaseUrl(); var fileDropUUID = 'FILE_DROP_UUID'; var user = FrogOS.getUser(); Frog.Model.api('users.getDataInCategory', { user_uuid: user.uuid, uuid: '60A77B2B2004CAF8CA73CFFA7491B80E180635BCDD1AEDB7' // Users app category for additional information, where the roll number is stored }).done(function(response) { var data = response.data.fields; var MISID = ''; $.each(data, function(index, field) { if (field.label == 'roll_number') { MISID = field.value; Frog.Model.api('filedrop.get', { filedrop: fileDropUUID }).done(function(fileResponse) { var files = fileResponse.data.resources; $.each(files, function(ind,file) { if (file.deleted == 0) { if (file.file.name.indexOf('-'+MISID+'-') > -1) { File_PDF.append( '<embed src="'+baseURL+'/app/file/resource/'+file.file.uuid+'" width="100%" height="1500px" />' ); } } }) }).fail(function(e) { console.log("failed to get file drop"); }); } }); }).fail(function(e) { console.log("failed to get Roll Number"); }); </script>
  17. Hi @Sue Busher I've made the change to your staff dashboard, this works: <style> div[data-content-uuid="WIDGET_UUID"] .countdown_section:nth-child(2), div[data-content-uuid="WIDGET_UUID"] .countdown_section:nth-child(3), div[data-content-uuid="WIDGET_UUID"] .countdown_section:nth-child(4) { display: none !important; } </style> Graham
  18. Here's a bit of code if you don't want free periods labeled as free <style> div[data-content-uuid="WIDGET_UUID"] .free .subject:before { content: 'Study Period \a'; white-space: pre; } div[data-content-uuid="WIDGET_UUID"] .free .subject { height: 20px !important; overflow: hidden !important; } </style>
  19. Sorry, I've been away at a trade show. Umm, I think we're getting into quite complicated territory here - you'd need code to listen to the form for a click response, then make changes to other dropdowns - it could easily get messed up. It might be simpler to create a form in an HTML widget, include these features then on submission submit it using the Form API. Simpler, but a bit time consuming.
  20. For those modal pop-ups, especially with forms, sometimes you just want a bit more width. Dropping this code into an HTML widget will expand ALL modals, so I'm tempted to suggest you don't use it on staff dashboards, as things like the assignment pop-up and share wizard look a little weird: .modal-body { max-height: 560px !important; } .modal { width: 70% !important; left: 30% !important; } Fortunately the Image Carousel's gallery mode pop-up has an extra class: <style> .image_carousel_modal .modal-body { max-height: 600px !important; height: auto !important; } .image_carousel_modal { max-width: 80% !important; } </style>
  21. How many hidden field!?! 🤯 Here you go, it's a bit "belt-and-braces" but it works: <style> div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(14), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(15), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(16), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(17), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(18), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(19), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(20), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(21), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(22), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(23), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(24), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(25), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(26), div[data-content-uuid="FORM_UUID"] .form-body .row-fluid:nth-child(27) { height: 0px !important; max-height: 0px !important; overflow: hidden !important; border-top: 0px !important; margin: 0px !important; padding: 0px !important; } </style>
  22. Lots of variations are possible here, just open an HTML widget and... This will hide all lines: <style> .form-body .row-fluid { border-top: 0px !important; } </style> Or this will hide specific lines: <style> .form-body .row-fluid:nth-child(3), .form-body .row-fluid:nth-child(4) { border-top: 0px !important; } </style> Or this will hide lines only on a specified form: <style> div[data-content-uuid="FORM_UUID"] .form-body .row-fluid { border-top: 0px !important; } </style>
  23. The Form Register stores the data in a form on the same site, so you'll be able to export attendance, correct entries, search for students etc... using a data viewer. For staff to add students, as above, we'd need to build a widget to allow that to happen. So today.... you could do it with you being the middleman (adding students to groups), and in theory a FrogCode widget could sort it out what you need. I could offer to estimate it for you, but I think we both know the answer.
  24. Now that's a tricky one. You're wanting staff to be able to add users to a group, without being able to remove other users from a group? Currently the Groups & Policies role to add users to a group is linked to being able to remove users. They don't have access to add or remove features anyway. And MIS groups are fixed, so they can't alter those users. The Join Club FrogCode widget does allow students to add themselves to a group, as it uses the groups.amendMembers API. So it would be probably be possible for a teacher to search for a student and add them using similar code: Frog.Model.api('groups.amendMembers', { group_uuid: /*GROUP_UUID*/, users: JSON.stringify([{uuid: /*UUID_OF_USER_TO_BE_ADDED*/, leader: false}]) },{type: "POST"}).done(function(response) { // Success }).fail(function(e) { // Report Error }); Alternatively, the Form Register uses a form, so there is the ability to add an individual manually via that form. This form's widget could be set to email the club coordinator (or you) and when you get that email, they (you) could add the new student to the group - so that next time, the register needs to be taken, they will be there - assuming someone has had time to update the club.
  25. I'm wondering about creating accounts for just the Frog Admins in each school, (the likes of you) so that you get an interactive checklist of those Frog tasks you need to do and a record of having done them But, that being said, I wouldn't want people resenting it.
×
×
  • Create New...