Jump to content

pconkie

Frog Community Genius
  • Posts

    598
  • Joined

  • Last visited

Everything posted by pconkie

  1. Very simple test case - skeleton widget with one widget preference defined. Com.Frog.Utils.require( '//package/widgets/66B544F32001B847B89EDFF5526AEC0B4851A10C0C50286B/assets/styles/main.css', '//package/widgets/66B544F32001B847B89EDFF5526AEC0B4851A10C0C50286B/assets/views/main.ejs', '//package/widgets/66B544F32001B847B89EDFF5526AEC0B4851A10C0C50286B/widget.ejs' ).then(function() { Com.Frog.Controllers.Widget.extend('Widget.Test', { }, { prefs: { file: { type: 'upload', label: "Select a File to Display", showDiscover: false, showClipboard: false, filter: ['image'], view: 'mini', sources: ['native'] } }, packageID: '66B544F32001B847B89EDFF5526AEC0B4851A10C0C50286B', /** * Constructor. Runs when the widget is first loaded. * * @method init */ init: function() {}, /** * Event fired by the Site Controller. * * @event 'widget.live' */ 'widget.live': function(el, ev, data) { this.element.html( this.view('main.ejs') ); }, /** * Event fired by the Site Controller. Tells the widget that the site is in Edit Mode. * * @event 'widget.edit' */ 'widget.edit': function(el, ev, data) { this.element.html( this.view('./widget.ejs') ); } }); }); When dragged on to a site the site fails to save unless a file has previously been selected. Is there a way around this? I would like to give teachers the option of loading a file into the widget, but if they want to start "with a clean slate" that would be fine too..... Thanks Paul
  2. Hello everyone. I've got a couple of ideas but not sure about the best way to proceed... 1. If i upload an asset to a Frog Code app/widget (e.g. an image) what is the best way to refer to that asset in Frog Code? if I've uploaded my image to Projects --> Widget --> My Widget --> Assets --> picture.png Can i refer to this asset in code whilst retaining this relative path and file name? <img src="externalapps/icon/widget_ID" /> works for the widget icon but <img src="externalapps/assets/picture/widget_ID" /> (and other permutations) does not work for other assets. Yes, i can find the assets ID and use that, but what will happen if the widget is ever moved from one frog box to another? 2. Let's say i create App A and Widget A. Would it be possible for different instances of Widget A to open App A and pass to it an object to help it initialise? I've had a look at the App widget preference but got a bit lost. Is this even possible and if so what's the best way to test if App A is already open? 3. The feedback app converts various files into images. Is there an api to tap into this? Thanks Paul
  3. Sharing this in case it is of use to anybody else..... I've been looking at creating a widget that is aware of and can interact with other widgets around it. As a test case I've made a "class discussion" widget that is like a forum, but only for members of a pre-determined class. Even then, some members of the class are allowed to see what others are writing and others are not. Some get a writing frame to structure their response and others don't. This widget needs to "take over" a forum widget in order to save the settings I've mentioned and also to save the students responses. However I want to avoid having to use the console to inspect the forum and go hunting for it's uuid. So far I've got this.... https://drive.google.com/open?id=0B2QYvi40BJqDSWI5dWZOZmJPUlE
  4. @mobrien Most likely explanation is - we are not sending the name of the subject into the function. This is why all lessons return the colour black - nothing can be matched. Do you know how to use the console? You can check what is being passed to the function (what is contained in the variable 'subject') by adding console.log(subject); to line 2 of the function. You can then open the console and have a look at what has been outputted. I have a feeling that it was advantageous when creating dynamic colours to make the string that was sent to the older function as long as possible. It is possible therefore that we are not sending the subject name alone into the function. I'll just check now...... Ok - find this line: var bgcolor = stringToColour(periods.subject+periods.teacher.username); You have presumably already changed it to: var bgcolor = subjectToColour(periods.subject+periods.teacher.username); Just one more small tweak so that it is: var bgcolor = subjectToColour(periods.subject); That should do it. Any further issues will be most likely to do with subject names in the function not matching SIMS. Hope this gets it working for you. Paul
  5. Hi @mobrien setting this up with widget preferences would be ideal - this way we could use the frog colour pickers to set the subject colours. However, this would take some thinking about as we would need to set a colour for every possible subject that could come up and we would have to do this every time the widget was dragged into a page. So I think for now, if this is what you want, perhaps it's best just to write an alternative function for the one you pasted. Something like this might work... var subjectToColour = function(subject) { var colour = ""; switch(subject.toLowerCase()) { case "maths": case "economics": colour = "green"; break; case "english": case "english language": case "english literature": colour = "#FF0000"; break; default: colour = "black";} return colour; }; you can can use certain colour names, but you would be better off googling HTML colour codes as per the English example. You need to keep you subject names identical to what you use in your MIS. All in lower case. Look at how I've grouped some subjects together so that they have the same colour. You will need to copy from "case" to "break" and paste between the { } for additional subjects/colours. Once completed you would need to copy the new function into the code and replace all instances of "stringToColour" for the new "subjectToColour". Good luck!
  6. email.html Hi @johnmorris01 This little widget should do what you want.... Instructions for set up 1. create a new site and drag a html widget onto the page 2. copy and paste the attached code, then save the site.email.html Instructions for use 1. Search for a class in the first box. Just type a few letters of the class name and a list to choose from should appear 2. Select a class and the member of that class will appear - all will be selected by default 3. Un-select any students you do not want to email by clicking on them 4, Press the "copy" button and the email address list will be copied to your clipboard. A member of staff would then need to open a new gmail message and paste (or ctrl+p) the address list into the send to field. If clipboard access is not supported by the browser, a box will appear containing the email address list. This can be copied in the more conventional way and then pasted later. Hope it helps! Paul
  7. Hi @Chris.Smith It was the notice board widget. Thanks Paul
  8. Hi Chris Saving was hit and miss yesterday - sometimes yes, sometime no. That has continued today for my teacher account (the account I have been using for all the frogcode stuff i've been doing). So something in Austin isn't behaving itself. With a super-dupa admin account the issues seem to have gone away! Paul
  9. Morning @Graham Quince I had my NM create me a new frog account with access to everything... This seems to have sorted the FrogCode issues i was experiencing yesterday. I have been able to update the widget to sort out the issues with when and where the new notice button should appear. I have also added in the over-ride to ensure it is off when you want it off. Waiting for you when you get a chance to take the latest version. Paul PS: I can't see the video that goes with the widget on the showcase. That might mean loots of other community members can't see it either. I can see the office365 video if that helps?
  10. Just got Austin yesterday and FrogCode seems to be misbehaving... 1. Little thing - the alpha badge has been replaced with the beta badge again. 2. Several times pressing save gives the usual save notification. But closing the browser and reopening reveals that the changes have been lost (or were never saved). This has never happened before. 3. Despite incrementing the version number of the widget. And despite getting the right noises from the package manager the widget more often fails to update than updates. Could be linked to #2, not sure. Dickens alpha seemed more solid. Hope this info helps in some way. P
  11. What's happened to FrogCode?! We got Austin yesterday and now I can't update any widgets via package manager?
  12. Hi @Graham Quince Also worth noting that contribute access is required by the forums api to submit a new post (notice). Just wondering why a student would need "contribute" access to their dashboard? In theory Paul could also have solved his problem by changing the students permissions to "view" for their dashboard. This would be consistent with how other widgets work. Having said that, the original widget does hide the new notice button when that widget is placed directly on the student dashboard (but not the staff dashboard) when the students have contribute access. So this is clearly a different behaviour! If someone can tell what line of code i need to check if the page is a dashboard then i can replicate what the original widget does. Your suggestion of an over-ride is a good one and I can build that in! Paul
  13. Hi @paulmitchell1989 As per the original widget if a user or group has only "view" permission for a site then they won't see the button to create a new notice. If they have "view and contribute" or "admin" permissions then they will see it. That's the theory anyway! And that works on our frog box. I'm not sure what the default sharing settings are for the student dashboard, but if you create a new site and give students "view" sharing permissions and put the noticeboard on that site, then embed that site on your dashboard, it should work like you want it to. We don't let students create notices either! Let me know if you still can't get it to hide. Paul
  14. John In the users app, if you select a student and look at their basic information is the email address show there the address you want to use? If so, its probably do-able as would be to email all the teachers of a specific student. I assume your using gmail? Paul
  15. Thanks for pointing this out Graham - that would be annoying. All changed and tested. Paul
  16. Hi @THaines Does this get you close? I would go down the route of one site per faculty. Copy and paste this into a HTML widget on the first page of a faculty site. This page could be a "welcome" or "instructions" or "important info" etc page. Change these lines - var HOD = and var HEAD = to what your values should be <script> //How have we named the pages in this site? //used display name? e.g. Mr A Smith //var currentuser = FrogOS.getUser().displayname; //used frog username? e.g. asmith var currentuser = FrogOS.getUser().username; //what usernames (or display names) are allowed to see everything? var HOD = "ahod"; var HEAD = "ahead"; //if we are not HOD or HEAD then hide the pages var that = this; setTimeout(function(){ if (currentuser !== HOD || currentuser !== HEAD) { that.elements.site.find("div[data-attr=site-menu] li").hide(); //should we try moving to our page in the site? that.elements.site.find("div[data-attr=site-menu] li a[title="+currentuser+"]").trigger("click"); //keep the instructions? that.elements.site.find("div[data-attr=site-menu] li:first").show(); //show our own page too that.elements.site.find("div[data-attr=site-menu] li a[title="+currentuser+"]").parent().show(); } }, 5); </script> Add a page for each member of staff in the faculty. The names of the pages is going to be very important! You have a few choices, but I would probably go with usernames. So imagine a site with the following pages (tabs) across the top: 1. Instructions (this is where our html widget is sitting) 2. asmith (that's the username of the first member of staff in the department) 3. thaines (that's the username of the next member of staff in the department) etc etc I've just thought the case is probably important, so put all the page titles in lower case for now. Now share the site with the faculty and the Head (actually you could share it with all staff as unless they are this faculties HOD or the Head they should only see the instructions page anyway) Use "open site in safe mode" if it all goes horribly wrong and you can't see any pages! This method hides things only! As you have to share the site with all members of the faculty AND you want certain individual to see everything there is probably a way to get at colleagues pages (especially if the site ID was known). So if you need absolute confidentiality this isn't the way to go. I haven't properly tested it, so let me know if you have any issues. Paul
  17. Made some further improvements to this widget today... 1. If an email address or link is included in the post, it is automatically turned into a clickable link. 2. Introduced a "frog tag" like feature. - Often we have notices that include long lists of student names which take up a lot of screen space! Now we can put a list like this between two tags <start list> and <stop list>. The notice board widget turns this into a collapsible "click to show" / "click to hide" container. If anyone wants the widget, they of course can, but @Graham Quince how would i get if off our platform? Paul
  18. pconkie

    BUGS?

    Hi @Chris.Smith Would you mind jumping on our frog box when you get a chance? Somehow managed to get a duplicate app in frogcode. It's not showing as duplicate in frogcode editor, but it is in package manager and in applications in frog drive. it's called FrogSeats. Thanks Paul
  19. Just a thought..... On app initialisation: 1. Check for the existence of a form 2. If found get uuid and any response data 3. If not found create one and get returned uuid Later any data can be saved to this form using the uuid. just an idea but one issue off the top of my head would be... Do the forms api allow the current users latest response to replace any previous response? This would be essential if all staff were sharing the same form. And how much data could be stored in say a text area field in the form? Unlimited? I've got a bit of time today, I'll try and mock something up.
  20. I'm developing an app that needs to save a small amount of configuration data (in json format). I've tried HTML 5 local storage but my teachers are too mobile for this! I'm going to have to use something like firebase but thinking three steps ahead - if another school were to use this app where would they put the config string required to use their firebase? What i really need is some data storage in frog! (I bet that one hasn't been suggested before?!) Is there anywhere i can save the data in frog? It's non sensitive info... Any ideas? Paul
  21. pconkie

    User photos

    It's not that amazing Graham. 'Proper developers' should avert their eyes from the following 'code' or build photo extraction into the frog extractor! I need to put a health warning on this too. Potentially you may end up attaching the wrong photo to every student and/or getting in a right mess with your user database. Use at your own risk. Outline of the steps: 1. Get all your photos in a folder. Can't really help with this step - suggestions would be ask your NM to get them out of SIMS or get hold the discs the photography company sent you. There are a few free programs out there like this one http://www.salamandersoft.co.uk/free-utilities/ that will do it. 2. Go to frog and log in as admin. Open the Users app, click the cog and then 'Export'. This will give you a spreadsheet of all users in frog. Delete all non student rows and then delete all non MIS-linked rows. Your images from step 1 are likely named by UPN or admission number, so you need to keep the UPN or roll number column. The import into frog requires the frog uuid and frog username fields, so keep these columns too. The other columns can be deleted. 3. Rename all the photos so that they are in the format {frog_uuid}-{frog_username}.jpg (or .png or .gif but not .bmp). I've got a vb script that will loop through the cleaned up spreadsheet from step 2 and re-name the images for you which i will add to this post when i find it again! 4. Take say 20 images to do a test run with first! Zip them up and upload them to a folder in your frog drive (you will want to delete these images when you have finished. It will be much easier to delete one folder than each image individually!). In frog drive select the zip archive click on the cog and select 'unzip'. I've noticed that frog really struggles to unzip archives with more than 200 files in them, so you may have to divide your images into several zip files when you are ready to import the lot. Delete the zip archive(s) once all images have been unzipped. Get the uuid of the folder your images are stored in using the inspector. 5. Remote control: Create a new site and add a html widget Here is the code to add to the html widget <div class="mybox"> <button data-name="go">Start Photo Assignment</button><br /><br /> <div data-name="log"></div> </div> <style> .mybox { margin-top: 100px; margin-bottom: 100px; margin-right: 150px; margin-left: 80px; } </style> <script> var $log = this.element.find("[data-name=log]"); var $mybtn = this.element.find("[data-name=go]"); var image_folder = '5B1A7E882002F46440CF5F6A824FBB052A5F009CC54A2D99'; var x = 1; var i = 1; var start = Date.now(); var thisDelay = 0; var subdelay = 10; $mybtn.click(function() { x = 1; i = 1; subdelay = 10; thisDelay = 0; $log.append(moment().format("hh:mm:ss a") + ": preparing to add images.... please wait<br />"); getImages(); }); function getImages() { Frog.Model .api('resources.getOfType', { sources: ["native"], type: 'staff', author: 'true', root_folder: 'EDAAA0E92002F81B92C2DFCD917CAC05E532634CEE5FEBD9', folder: image_folder, filter: null, exclude_template: 'true' }).done(function(listResponse) { var files = listResponse.data.resources; $log.append(moment().format("hh:mm:ss a") + ": found " + ($(files).length+1) + " images<br />"); var interval = 0; $.each(files, function(index,file) { var e = file.attachment.name.split("-"); setTimeout(updatephoto(e[0], e[1], file.uuid, interval, i),interval); interval = interval + 33000 + x; x = x + 10; i = i + 1; }); }); } function updatephoto(uuid, username, photo, mytime, myi) { setTimeout(function(){ $log.append(moment().format("hh:mm:ss a") + ": #" + myi + " Updating user "+username+"</div>"); }, mytime); setTimeout(function(){ start = Date.now(); $(".app-users .search input:first").val(username).keyup(); $log.append("...searching..."); thisDelay = Date.now() - start; }, mytime+thisDelay+2000); setTimeout(function(){ start = Date.now(); $(".app-users .user-table .users_models_user_"+uuid+":first").trigger("click"); $log.append("selecting user..."); thisDelay = Date.now() - start; }, mytime+thisDelay+7000); setTimeout(function(){ start = Date.now(); $(".app-users .users_edit .action-edit:first").trigger("click"); $log.append("editing..."); thisDelay = Date.now() - start; }, mytime+thisDelay+thisDelay+10000); setTimeout(function(){ start = Date.now(); $(".app-users .users_edit .change-photo:first").trigger("click"); $log.append("choosing photo..."); thisDelay = Date.now() - start; }, mytime+thisDelay+13000); setTimeout(function(){ start = Date.now(); $(".app-resources .resources_mydocuments .lib_models_folder_"+image_folder+":first").trigger("dblclick"); thisDelay = Date.now() - start; }, mytime+thisDelay+17000); setTimeout(function(){ start = Date.now(); $(".app-resources .resources_mydocuments .lib_models_resource_"+photo+":first").trigger("click"); $log.append("selecting photo..."); thisDelay = Date.now() - start; }, mytime+thisDelay+21000); setTimeout(function(){ start = Date.now(); $(".app-resources [data-action=use]:first").trigger("click"); thisDelay = Date.now() - start; }, mytime+thisDelay+23000); setTimeout(function(){ start = Date.now(); $(".app-users .users_edit .action-save:first").trigger("click"); $log.append("saving..."); thisDelay = Date.now() - start; }, mytime+thisDelay+26000); setTimeout(function(){ start = Date.now(); $(".app-resources").prev().find('a.ui-dialog-titlebar-close').trigger("click"); $(".app-users .users_edit .breadcrumbs .os-breadcrumb-link:first").trigger("click"); $log.append("exiting<br />"); thisDelay = Date.now() - start; }, mytime+thisDelay+29000); } </script> Change var image_folder = ''; to the uuid of your folder from step 4 Make sure when you are ready to try this, to open the users app! Your frog drive doesn't need to be open and probably should be closed. This script has a button, which when pressed gets the contents of your images folder. For each image in the folder the file name of the image is split and the frog username is used to search for the student in the user database while the frog uuid is used to open the correct student record from the users returned from the search. The following sequence then occurs as a series of timed events: 1. Remote control performs search for student in users database and return matches (5 seconds allowed for this) 2. Remote control opens the correct student record (3 seconds allowed for this) 3. Remote control presses the "Edit" button (3 seconds) 4. Remote control presses the "Change Photo" button (3 seconds) 5. Remote control opens the correct folder in frog drive (4 seconds) 6. Remote control selects correct image (2 seconds) 7. Remote control selects correct image (2 seconds) 8. Remote control presses the 'Use' button (2 seconds) 9. Remote control presses the 'Save' button (3 seconds) 10. Remote control closes frog drive if not already closed and closes the users record, returning to the use search results (3 seconds) There is some attempt in the code to make adjustments to this timing based upon any major delays cause by the server or more likely your browser. You may need to alter these timing depending on the speed of your network. You may beable to shorten these timings! If you make a few copies of the site and set up images in a few folder it is possible to use different browser (eg chrome, FF and IE) at the same time on the same computer to get this done much faster. The code outputs a log of sorts to the site so that you can get an idea of how far along you have got. Here we are purposefully using $() rather than this.element.find because we WANT to affect things (very carefully) outside the site.
  22. pconkie

    User photos

    I've figured this out, sort of.... Approached it from a completely different way by making a 'remote control' for frog. Was able to leave a computer with the remote control running and by the end of the day it had assigned photos correctly to 98% of students. It's a fairly complicated set-up but if anyone wants the students photos in frog then i'm happy to share the steps and the code.
  23. Amazing Chris, thanks. Makes sense. Couple of related questions.... Does an app (not a widget) support preferences? On smaller screens i've noticed that apps are docked/maximised when they are initialized. Is there a way to force an app to be maximised on initialization regardless of screen size? Thanks Paul
  24. @Chris.Smith @Graham Quince any advice please on the following? I am trying to combine information from two frog api calls. Firstly calling getMembers to return basic information about every student in a particular group. Secondly looping through each student and calling getDataInCategory to return extra information. I am assuming there is no extra parameter I can add to the first call to get the extended information without making the second call! Regardless I quite like to know how you would go about beating the async issues anyway. The issue is that the first call does not wait for the second calls to complete. Frog.Model.api('groups.getMembers',{ignore_profiles: true, uuid: my_group_uuid}).done(function(thisResponse) { $.each(thisResponse.data, function(i, member) { //loop through each member of the group //build object as we go var thismember = {uuid: member.uuid, name: member.displayname, gender: member.gender, thumb: member.thumbnail, data:[]}; Frog.Model.api('users.getDataInCategory',{user_uuid: member.uuid,uuid: student_flags_uuid}).done(function(thatResponse) { $.each(thatResponse.data.fields, function(x, data) { //loop through each field of extra data and add the data to the data array in the thismember object var key = data.label; MyContext[key] = data.value; }); thismember.data.push(MyContext); //this happens after MyGroup.push(thismember) }); //the code below doesnt wait for the inner api call MyGroup.push(thismember); //this line always has 'data' empty. }); }); I've read about closures, async=false and promises. I don't understand the first and last, and async=false seems to be really bad practise, So what's the recommended approach here? How can i get an object out of the end of this which contains basic and extended information for each of the students in the group? Thanks for your continued support P
  25. Hi Graham Thanks! That fixed it. All working as expected now. I did think it was working for my teacher account (I have an admin account too) but seem i was mistaken. Of course now all staff get the little "edit" handle when they follow the link from the notification that is generated from a new post (as the site is nested on our dashboard they don't see the edit handler under all other circumstances). I suppose a member of staff *could* inadvertently delete the widget off the page. It looks like they can't delete the entire site though (because they are not the owner?). Would be nice to have the api to tick! I think with a bit of time to think about it I could probably hide the edit handle for all but those in the admin profile. Thanks again Paul
×
×
  • Create New...