Jump to content


School User
  • Posts

  • Joined

  • Last visited

Everything posted by Chris.Smith

  1. Anyone who is interested, one of the FrogCode Beta testers has written a pretty cool Google Search Widget using FrogCode! They even added two colour picker preferences allowing you to change the colour of the search button! Who would be interested in using that widget on their FrogLearn?
  2. Hi @sclough, @Graham Quince has a tutorial on just this that you can use as a reference. You need the page entitled 'Calling an API' on this tutorial - https://www.frogcommunity.com/understanding-api In this he discusses how to get the contents of a folder from a uuid. Hope that helps
  3. @Graham Quince @ADT Disappointed with you both for not spotting the FrogOS Global Search box lighting up... See me after class. <script type="text/javascript"> this.element.find('input').on('click', function(ev) { ev.stopPropagation(); }); </script> Stick this at the bottom of @Graham Quince's code and you should be golden
  4. Hi @clangstaff, We are experiencing some problems with browser cache management at the moment. Usually, we want the browser to cache as much as possible, with Preview in FrogCode, we need it to forget those files which is harder than it sounds. For the time being try Refreshing the page, or if that doesn't work, clear your browser cache and refresh the page. A fix is in the works presently. ~ Chris
  5. Our time comes back in the form of EPOC (a timestamp). Therefore the greater the value, the further in the future the date. So for example, 1481621745 is my current timestamp.... and 1481708175 is now plus one day; in a descending order I would expect tomorrow to come first, then today. Here's a larger example: var time_range = [ { alias: 'now', timestamp: moment().format('X') // 1481621745 }, { alias: 'yesterday', timestamp: moment().subtract(1, 'day').format('X') // 1481708175 }, { alias: 'first_sept', timestamp: moment('01/09/16').format('X') // 1452297600 }, { alias: 'fourth_nov', timestamp: moment('04/10/16').format('X') // 1460242800 }, { alias: 'first_jan', timestamp: moment('01/01/17').format('X') // 1483228800 } ]; function sort(direction, a, b) { switch(direction) { case 'asc': return a.timestamp < b.timestamp; case 'desc': return a.timestamp > b.timestamp; default: throw new Error('Unknown direction: '+direction); } } time_range.sort(sort.bind(time_range, 'desc')); // [{first_jan}, {now}, {yesterday}, {fourth_nov}, {first_sept}] time_range.sort(sort.bind(time_range, 'asc')); // [{first_sept}, {fourth_nov}, {yesterday}, {now}, {first_jan}] Hope that clears things up Chris
  6. @clangstaff I would expect the greatest value to be first.
  7. @clangstaff If the order attribute in the data object is not working as intended then that's something we should probably look at... Have you reported this to the Service team? /cc @Graham Quince @Matt
  8. @Graham Quince Yes, you need to added the assignment uuid to the command that opens Assignment (Manager|Monitor|My Childs Work). @clangstaff This is a modified version of the code from "My Child's Work". var params = { site: '', editable: false, assignment_uuid: assignment.attr('assignment_uuid'), mode: 'readonly', viewAs: student // <-- Must be a Lib.Models.User model }; Sites.Models.Assign.findOne({ uuid: assignment.attr('assignment_uuid') }).done( function(site) { params.site = site.attr('link'); FrogOS.openSite(params); }.bind(this) ); It may need modifying as the data it requires is from an "opinionated" API. Hope this helps, ~ Chris
  9. Hi @clangstaff This is due to the nested data structure. You are one level lower than you need to be... { "assignments": { "EC17261D200034DE79F32F10EA83CE0469E09D9CA1235592": { "has_feedback": 0 }, "EC157C3320003748A5E0DFFDF4C73908258D99FC1028A058": { "has_feedback": 0 }, "EC1649BA20003437A9827F2363E912060B3CFE6C71F0AB70": { "has_feedback": 0 }, "EC1788C52000355DDC814F9C192B3603FF9B18FC15015FD9": { "has_feedback": 0 }, "EC17261D200034DE79F32F10EA83CE0469E09D9CA1235592": { "has_feedback": 0 }, "EC173C4220032A07A20DDF3FFF98E106AC26534C1C45D3F6": { // <-- You are here!! "activities": { "total": "1", "complete": 1 }, "assignment": { "uuid": "EC17261D200034DE79F32F10EA83CE0469E09D9CA1235592", "name": "Script Generated Assignment 49" }, // <-- You need to be here "user_info": { "comments": "0", "creator": { "uuid": "EBDD2A0E20005F222E730F4EF076FD08ED03276CE5A4B047", "username": "admin1" }, "has_feedback": 0, "user_info": { "closed": null, "comment": null, "completed": 1481043676, "mark": null, "returned": null, "self_assessment_comment": null, "self_assessment_score": "1", "uuid": "EC173C4220032A07A20DDF3FFF98E106AC26534C1C45D3F6", } } } }, "total_count": 4 } Let me know if you need any further help on this, all the code you need is in the tutorial and previous posts. This code snippet may help: var assignments = data.response.assignments, assignment; for (var uuid in assignments) { if (assignments.hasOwnProperty(uuid)) { assignment = assignments[uuid].assignment; var assignSubject = '<p><strong>' + assignment.subject.name + '</strong></p>'; // etc, etc, etc } } Hope this helps, Chris
  10. Hi Mark, I have had a quick look at the FDP documentation and it confused me... There are two filters, "start_from" and "start_to". They are intended to help you limit the range of start dates. Here is an exert from the Docs... After some consideration I figured out (rather ashamed of how long it took me) that if you set "start_from" to say, the beginning of time (or one year in the past maybe) and then "start_to" to the beginning of the current day, only the assignments you want will appear. I haven't tried it, but I have a sneaking suspicion that you might be able to get away without specifying "start_from". To get the "start_to" try the following: moment().startOf('day').format('X') Hope this helps, Chris
  11. Hi Corinne, Sorry for the delay in getting to you; its been full steam ahead here at Frog Towers recently. The completed attribute is present in one of the response objects we filtered out earlier; Whoops. Here is an example data structure - Hopefully this looks familiar { "assignments": { "EC17261D200034DE79F32F10EA83CE0469E09D9CA1235592": { "has_feedback": 0 }, "EC157C3320003748A5E0DFFDF4C73908258D99FC1028A058": { "has_feedback": 0 }, "EC1649BA20003437A9827F2363E912060B3CFE6C71F0AB70": { "has_feedback": 0 }, "EC1788C52000355DDC814F9C192B3603FF9B18FC15015FD9": { "has_feedback": 0 }, "EC17261D200034DE79F32F10EA83CE0469E09D9CA1235592": { "has_feedback": 0 }, "EC173C4220032A07A20DDF3FFF98E106AC26534C1C45D3F6": { "activities": { "total": "1", "complete": 1 }, "assignment": { "uuid": "EC17261D200034DE79F32F10EA83CE0469E09D9CA1235592", "name": "Script Generated Assignment 49" }, "user_info": { "comments": "0", "creator": { "uuid": "EBDD2A0E20005F222E730F4EF076FD08ED03276CE5A4B047", "username": "admin1" }, "has_feedback": 0, "user_info": { "closed": null, "comment": null, "completed": 1481043676, "mark": null, "returned": null, "self_assessment_comment": null, "self_assessment_score": "1", "uuid": "EC173C4220032A07A20DDF3FFF98E106AC26534C1C45D3F6", } } } }, "total_count": 4 } The problem lies here: .map(function(assignment) { return assignment.assignment; // <-- Here be the start of ye problams, arrh }).filter(function(assignment){ return !assignment.complete; }) Here we are taking that top level aggregation, and grabbing the assignment object. So we need to access some of the data from the "user_info" object. Usually I would say rewrite the widget to accommodate the structure returned from the FDP however in your case, we can do the following as we don't require access to the information after this point. .filter(function(assignment){ return !assignment.user_info.complete; }).map(function(assignment) { return assignment.assignment; }) Hope this helps, Chris
  12. Hey @clangstaff This is totally achievable, in fact, if you swap out the new table HTML with your old one, this *should* work. Failing that, abandon the table as actually; what you want can be better constructed using <ul>, <li> and CSS. Have a go, and let me know how you get on! ~ Chris
  13. Hey @johnmorris01, My best recommendation is to inspect the API response and look at the data structure to find the data you want. If your not sure how to do this, I really recommend @Graham Quince's tutorial on Understanding API's. For example, to get the subject name, on inspection of the API response you would see that there is a subject object on the assignment object, and within that a name attribute. { "assignment": { "subject": { "name": "English" } } } So in our code we would say: assignment.attr('subject').name Interestingly, the creator is not included as part of the assignment object. it is in fact a sibling attribute. I recommend that in the data converter, you move the creator into the assignment as an attribute of the assignment. return Object.values(response).map(function(assignment) { assignment.assignment.creator = assignment.creator; return assignment.assignment; }); This particular endpoint happens to be covered on the old FDP site. http://fdp.frogcommunity.com/questions/view/485/get-assignments-assigned-to-a-user It's worth saying that we are updating our FDP API reference. Hope this helps, ~Chris
  14. Hi All, I have updated the original code and the associated tutorial on the community site. Here's this link! Let me know what you think; if you have any suggestions or requests for amendments, let me know. ~ Chris /cc @Graham Quince
  15. Hi @johnmorris01 Here is the fix for your problem; I have also provided a little update to use the latest API's. <style> .row-template { display: none; } .widget-header { width: 100%; padding: 10px 20px; box-sizing: border-box; background-color: #000000; border-top-left-radius: 6px; border-top-right-radius: 6px; border: 1px solid #000; border-bottom-width: 0; color: #f2d300; } .widget-body { background-color: white; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; border: 1px solid; border-top-width: 0; } .row-no-data td { text-align: center; } tr + .row-no-data { display: none; } </style> <div class="widget-header"> <h4>My most recent homeworks:</h4> </div> <div class="widget-body"> <table class="table table-striped"> <thead> <tr> <th>&nbsp;</th> <th>Title</th> <th>Subject</th> <th>Available on</th> <th>Due</th> </tr> </thead> <tbody> <tr class="row-no-data"> <td colspan="6"> You have no homework currently set </td> </tr> <tr class="row-template"> <td><!-- icon --></td> <td class="title"></td> <td class="subject"></td> <td class="start_date"></td> <td class="due_date"></td> </tr> </tbody> </table> </div> <script type="text/javascript"> FrogOS.fdp({ url: 'assignment/getAssigned', data: { status: 'open', limit: 4, order: 'start desc' }, dataType: 'json assignments', converters: { /* * Instructions for how to deserialize the network response * See: https://api.jquery.com/jQuery.ajax/#using-converters * * @param jqXHr Network Response * @returns Frog.Model.List List of Assignments */ 'json assignments': function(resp) { return Frog.Model.models( Object.values(resp.response.assignments) .map(function(assignment) { return assignment.assignment; }) ); } } }).done(function(assignments) { // Cache the elements we require. We'll use the principle of hoisting // to access them when we need them. var $template = this.element.find('.row-template'), $table = this.element.find('table'); // Iterate over the collection of assignments // See: http://frogasia.github.io/javascriptmvc-3.2-docs/#!jQuery.Model.List.prototype.each assignments.reverse().each(function(idx, assignment) { var $row = $template.clone().removeClass('row-template'); // Clone the template $row.data('link', assignment.attr('link')); // Encapsulate the data we will need later // Place the data in the table row in the correct cells $row.children('.title').text(assignment.attr('name')); $row.children('.subject').text(assignment.attr('subject').name); $row.children('.start_date').text( moment(assignment.attr('start'), 'X').format('Do MMM YYYY') ); $row.children('.due_date').text( moment(assignment.attr('end'), 'X').format('Do MMM YYYY') ); // Before we append row onto the table, add the "click" listener. $row.on('click', function(el, ev) { FrogOS.openSite({ site: el.data('link') // Get the data from the element we clicked }); }.bind(this, $row)); // Apply the current scope, and set the first parameter to the current row $table.find('tbody').prepend($row); // Finally, prepend the row. }.bind(this)); // Apply the current scope to the iterator. }.bind(this)); </script> Hope this helps, ~ Chris /cc @Graham Quince @shutterm
  16. Hi Simon, We don't typically give out these endpoints, we are looking to augment them and present them in a cleaner way, hence FrogOS.js Whilst the official documentation is a few months away; here is a quick summary of the endpoints available to you as of the Dickens Release. /** * Get the current user * @method getUser * @version 2015-06-29 * @author Chris Smith * * @codestart javascript * * var element = jQuery('.welcome-msg'), * user = FrogOS.getUser(); * * element.text( * sprintf('Hello <strong>%s</strong>', user.attr('displayname')) * ); * * @codeend * * @return {Lib.Model.User} An instance of the User Class */ getUser: function() {}, /** * Alias Sprintf into our namespace. * @method sprintf * @version 2015-06-29 * @author Chris Smith * @type {Function} * * @codestart javascript * * var date = moment().format('dddd MMMM YYYY'), * element = jQuery('.welcome-msg'); * * element.text( * sprintf('Here\'s the schedule for %s', date); * ); * * @codeend */ sprintf: sprintf, /** * Alias FDP api method * @method fdp * @version 2015-07-02 * @author Chris Smith * @type {Function} * * @codestart javascript * * FrogOS.fdp({ * url: 'notification/send', * path: '/api/fdp/2/', * type: 'POST', * data: { * recipients: recipients_list, * message: my_message * } * }).done(function(response) { * // Do things * }).fail(function(e) { * // Report Error * }); * * @codeend * * @returns {jQuery.Promise} Promise Object */ fdp: function(options) {}, /** * Open a Site or Assignment * @method openSite * @version 2016-06-20 * @author Chris Smith * * @codestart javascript * * FrogOS.openSite({ * site: '/a_user/example_site' * }); * * @codeend * @return this */ openSite: function(options) {}, /** * Open an application * @param {String} appName Name of App * @param {Object} options Application Info * * @codestart javascript * * // Open Student App * FrogOS.openApp( * 'assignmentreports', * { * view: student * } * ); * * @codend * * @note options parameter currently broken @chris.smith - 06/10/2016 * * @return this */ openApp: function(appName, options) {} Hope this helps
  17. Hi @sclough, You can open the Assignment Monitor app using the new endpoints in FrogOS.js Normally we would do this; FrogOS.openApp( 'assignmentreports', { view: "monitor" } ); But it doesn't seem to be behaving itself at the moment, so lets pull apart what this does under the hood. $('.os_core:first').trigger('os.internal.launchapp', { data: { name: 'assignmentreports', view: 'monitor' } }); The above code will give you the desired result. I will be logging a bug to fix the FrogOS.js and hopefully that will go out in one of the next few hotfixes
  18. @johnmorris01 That's weird.. Hmm. If I get chance this week I will update the tutorial code and "kick the tires" a little; see if I can figure out whats going on for you . Hopefully someone on the community might have a few ideas... /cc @clangstaff @Graham Quince
  19. @johnmorris01 If you are using the latest version of the script available here. Then all should be fine... The only thing I would advise is that if you are experiencing this when you are logged in as yourself (i.e. not the student) then the platform is enforcing the sharing permissions set against the site. I will have a chat with @Graham Quince and see if we can get to the bottom of this in-house. Stay tuned /cc @John Elliott @clangstaff
  20. Chris.Smith


    Hi Sue, This won't be working as to prevent Cross Site Scripting attacks, we actively remove <script> tags from the HTML Widget; there is of course a way around this. <div data-tockify-component="calendar" data-tockify-calendar="events.kennet"></div> <script> var $script = $(document.createElement('script')); $script.attr('data-tockify-script', 'embed') .attr('src', 'https://public.tockify.com/browser/embed.js'); this.element.append($script); </script> Here we are manually creating the script element. We have to do this, as the HTML Widget uses a regex which removes instances of '<script>' and '</script>'. This is also why we can't use jQuery to create the element for us. Hope this helps ~ Chris
  • Create New...