diff --git a/iwsy/README.md b/iwsy/README.md deleted file mode 100644 index e2ad6ee..0000000 --- a/iwsy/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# IWannaShowYou - -IWannaShowYou is a GUI presentation package analagous to PowerPoint but for web-based editing and delivery. It is _not_ a PowerPoint clone, nor does it seek to be compatible in any way. It provides an editing environment that maintains a live view of the presentation at the step being edited. All editing is done by typing values; mouse-based editing may be added later. - -IWannaShowYou differs from PowerPoint in being step-based rather than slide-based. A step is any change to what is currently showing on the screen. If you wish to retain the notion of 'slides' you can regard a slide as an accumulation of a number of steps. Every slide consists of at least one step but there is no upper limit to the number. - -PowerPoint includes a rich set of graphical elements. IWannaShowYou relies more on _actions_, the simplest of which is a cut from one piece of content to another. IWannaShowYou presentations tend to be dynamic, with smooth transitions from one step to the next. The program is modular and permits the addition of plugins to perform any desired effect. Its architecture separates structure and content to allow either to be changed independently of the other. - -IWannaShowYou creates files in plain-text JSON format. - -IWannaShowYou runs in any browser and is usable on a PC or a mobile device. - -This project is under development. \ No newline at end of file diff --git a/iwsy/demo.html b/iwsy/demo.html new file mode 100644 index 0000000..5ee69ef --- /dev/null +++ b/iwsy/demo.html @@ -0,0 +1,21 @@ + + + + + + + + + + +
+ JSON::Presenter
+ Click/Tap or key Space/RightArrow to start in manual mode
+ Click/Tap or key Space/RightArrow to advance
+ Key Enter to start in auto mode
+ Click/Tap to exit auto mode +
+ + + + diff --git a/iwsy/index.html b/iwsy/index.html index e19b3e9..7edaf53 100644 --- a/iwsy/index.html +++ b/iwsy/index.html @@ -2,8 +2,8 @@ - - + + @@ -15,7 +15,8 @@ script Launcher variable Script - rest get Script from `/resources/ecs/main.txt?v=` cat now + require js `dist/plugins/iwsy.js?v=` cat now + rest get Script from `/resources/ecs/iwsy.txt?v=` cat now run Script diff --git a/iwsy/iwsy.js b/iwsy/iwsy.js index fb31b13..485a6be 100644 --- a/iwsy/iwsy.js +++ b/iwsy/iwsy.js @@ -83,10 +83,46 @@ const IWSY = (player, text) => { }, step.duration * 1000); }; + // Get the bounding rectangle of a block + const getBlockRect = (block, r) => { + const left = block.defaults.left; + const top = block.defaults.top; + const width = block.defaults.width; + const height = block.defaults.height; + if (isNaN(left) || isNaN(top) || isNaN(width) || isNaN(height)) { + return rect; + } + const w = r.width / 1000; + const h = r.height / 1000; + const rect = {}; + rect.width = width * w; + rect.height = height * h; + rect.left = left * w; + rect.top = top * h; + return rect; + }; + // Create a block - const createBlock = (block) => { - const w = player.getBoundingClientRect().width / 1000; - const h = player.getBoundingClientRect().height / 1000; + const createBlock = block => { + const r = player.getBoundingClientRect(); + let rect = { + width: r.width, + height: r.height, + left: 0, + top: 0 + } + if (block.defaults.parent) { + for (b of script.blocks) { + if (b.defaults.name === block.defaults.parent) { + rect = getBlockRect(b, rect); + break; + } + } + }; + const w = rect.width / 1000; + const h = rect.height / 1000; + const l = rect.left; + const t = rect.top; const defaults = block.defaults; const element = document.createElement(`div`); player.appendChild(element); @@ -97,15 +133,19 @@ const IWSY = (player, text) => { element.style.position = `absolute`; element.style.opacity = `0.0`; let val = defaults.left; - if (!isNaN(val)) { + if (isNaN(val)) { + element.style.left = val; + } else { val *= w; + element.style.left = `calc(${l}px + ${val}px)`; } - element.style.left = val; val = defaults.top; - if (!isNaN(val)) { + if (isNaN(val)) { + element.style.left = val; + } else { val *= h; + element.style.top = `calc(${t}px + ${val}px)`; } - element.style.top = val; val = defaults.width; if (!isNaN(val)) { val = `${val * w}px`; diff --git a/iwsy/properties.txt b/iwsy/properties.txt deleted file mode 100644 index 82915a9..0000000 --- a/iwsy/properties.txt +++ /dev/null @@ -1 +0,0 @@ -password=$2y$10$Kazqoaw6fGfV22bp3otJeO6Xra4bCsBJXq6JVAV07qOkHNDIFevWG diff --git a/iwsy/resources/README.md b/iwsy/resources/README.md index 58dd2e9..e277613 100644 --- a/iwsy/resources/README.md +++ b/iwsy/resources/README.md @@ -1,3 +1,3 @@ - # IWannaShowYou resources + # JSON::Presenter resources These are all the resources - scripts, images and text files - called for by the website. diff --git a/iwsy/resources/ecs/blocks.txt b/iwsy/resources/ecs/blocks.txt index 37cfe9a..e72dfec 100644 --- a/iwsy/resources/ecs/blocks.txt +++ b/iwsy/resources/ecs/blocks.txt @@ -26,6 +26,7 @@ variable ParentBlock variable Defaults variable PropertyDefaults + variable ParentDefaults variable PropertyNames variable PropertyName variable SelectedBlock @@ -188,8 +189,8 @@ Restart: if M is not SelectedBlock begin put element M of Blocks into ParentBlock - put property `defaults` of ParentBlock into Defaults - json add property `name` of Defaults to BlockNames + put property `defaults` of ParentBlock into ParentDefaults + json add property `name` of ParentDefaults to BlockNames end add 1 to M end diff --git a/iwsy/resources/ecs/iwsy.txt b/iwsy/resources/ecs/iwsy.txt index 6695176..0266387 100644 --- a/iwsy/resources/ecs/iwsy.txt +++ b/iwsy/resources/ecs/iwsy.txt @@ -18,6 +18,7 @@ div BlocksPanel div ContentPanel div Player + div UserPanel span Status span Span input NameEditor @@ -27,10 +28,12 @@ img Save img RunStop img Delete + img User a Link module StepsModule module BlocksModule module ContentModule + module UserModule variable Mobile variable LastSavedState variable Content @@ -38,7 +41,6 @@ variable Presentation variable Name variable CurrentName - variable PasswordValid variable ShowRun variable ReadOnly variable PasswordRequested @@ -50,6 +52,8 @@ variable CurrentScriptName variable Action variable Running + variable UserRecord + variable UserHome variable N ! The browser @@ -71,7 +75,7 @@ ! Test if site is on a static host clear ReadOnly - rest get List from `_list/scripts` + rest get List from `list/scripts` or begin print `Static site` set ReadOnly @@ -105,7 +109,7 @@ L2: set the style of Masthead to `border:0.2em solid purple;text-align:center;color: lemonchiffon;background:darkmagenta;position:relative` create Title in Masthead - set the style of Title to `font-size:4em;font-weight:bold;font-style:italic` + set the style of Title to `font-size:4em;font-weight:bold` set the content of Title to `I Wanna Show You` create Subtitle in Masthead set the style of Subtitle to @@ -116,7 +120,7 @@ L2: set the style of Controls to `padding:0 0.5em` create Buttons in Controls - set the style of Buttons to `width:100%;padding:0.5em 0` + set the style of Buttons to `width:100%;padding:0.5em 0;position:relative` create ScriptName in Controls set the style of ScriptName to `display:flex` @@ -151,10 +155,15 @@ L2: set the style of RunStop to `width:40px;margin-right:1.5em` set attribute `src` of RunStop to `resources/icon/run.png` set attribute `title` of RunStop to `Run` + create Link in Buttons + create User in Link + set the style of User to `width:40px;position:absolute;top:0.5em;right:0.5em` + set attribute `src` of User to `resources/icon/user.png` + set attribute `title` of User to `Login` create Status in Buttons if Mobile set the style of Status to `height:1em` - else set the style of Status to `float:right;margin:0.5em 0 0 0;color:green` + else set the style of Status to `float:right;margin:0.5em 70px 0 0;color:green` create Player in Left set the style of Player to `margin:0.5em` @@ -228,6 +237,7 @@ L2: set the text of CloseButton to `Close` put empty into LastSavedState + put empty into UserRecord on click New begin @@ -243,7 +253,7 @@ L2: set the content of Status to `No script name has been given` go to ResetStatus end - if PasswordValid rest post Presentation to `_save/json/` cat Name + if UserRecord rest post Presentation to `save/` cat UserHome cat `/` cat Name else put Presentation into storage as CurrentName end end @@ -260,7 +270,6 @@ L2: on click Save begin gosub to SaveChanges - gosub to GetPassword put the content of NameEditor into Name if Name is empty begin @@ -274,11 +283,11 @@ L2: if Name is not CurrentScriptName put empty into LastSavedState if Presentation is not LastSavedState begin - if PasswordValid + if UserRecord begin put Presentation into Content json format Content - rest post Content to `_save/json/` cat Name + rest post Content to `save/` cat UserHome cat `/` cat Name end else put Presentation into storage as Name put Presentation into LastSavedState @@ -297,7 +306,6 @@ L2: on click Delete begin - gosub to GetPassword put the content of NameEditor into Name if Name is empty begin @@ -307,7 +315,7 @@ L2: end if confirm `Are you sure you want to delete "` cat Name cat `"?` begin - if PasswordValid rest post to `_delete/json/` cat Name + if UserRecord rest post to `delete/` cat UserHome cat `/` cat Name else remove Name from storage gosub to SetStatusGreen set the content of Status to `Script "` cat Name cat `" deleted` @@ -320,6 +328,21 @@ L2: end on click RunStop go to DoRunStop + on click User + begin + if UserRecord + begin + put empty into UserRecord + set attribute `src` of User to `resources/icon/user.png` + set attribute `title` of User to `Login` + gosub to SetStatusRed + set the content of Status to `Not logged in` + put empty into storage as `email` + put empty into storage as `password` + go to ResetStatus + end + else send `login` to UserModule + end gosub to CreateNewPresentation put Presentation into LastSavedState @@ -330,6 +353,11 @@ L2: gosub to SelectSection clear Running iwsy load Player Presentation + + create UserPanel in Controls + rest get Script from `/resources/ecs/user.txt?v=` cat now + run Script with UserPanel as UserModule + send to UserModule on message begin @@ -354,6 +382,16 @@ L2: put property `block` of Message into N iwsy block N end + else if Action is `user` + begin + put property `user` of Message into UserRecord + put property `home` of UserRecord into UserHome + set attribute `src` of User to `resources/icon/user-loggedin.png` + set attribute `title` of User to `Logged in as ` cat property `name` of UserRecord + gosub to SetStatusGreen + set the content of Status to `Logged in as '` cat Name cat property `name` of UserRecord cat `'` + fork to ResetStatus + end end stop @@ -427,15 +465,13 @@ SaveChanges: return DoOpen: -! gosub to StopTestModule - gosub to GetPassword clear FileIsOpen if Presentation is not LastSavedState begin if confirm `Content has changed. Do you want to save it?` begin - if PasswordValid rest post Content to `_save/json/` cat Name + if UserRecord rest post Content to `save/` cat UserHome cat `/` cat Name else put Content into storage as Name end end @@ -456,9 +492,9 @@ DoOpen: set style `display` of FileListing to `inline-block` ! Fill the browser with content from the server - if PasswordValid + if UserRecord begin - rest get Files from `_list/json` + rest get Files from `list/` cat UserHome put the json count of Files into FileCount put empty into Content put 0 into N @@ -478,7 +514,10 @@ DoOpen: while N is less than FileCount begin put element N of Files into Item - if left 1 of Item is not `.` json add Item to Content + if left 1 of Item is not `.` + begin + if the position of `.json` in Item is not -1 json add Item to Content + end add 1 to N end end @@ -528,10 +567,11 @@ SelectFile: index File to the index of FileName set the content of NameEditor to File put File into CurrentScriptName - if PasswordValid rest get Presentation from `/resources/json/` cat File cat `?v=` cat now + if UserRecord rest get Presentation from `/resources/` cat UserHome cat `/` cat File cat `?v=` cat now else get Presentation from storage as File put Presentation into LastSavedState gosub to UpdateCurrentSection + gosub to SetStatusGreen set the content of Status to `Presentation '` cat File cat `' loaded` fork to ResetStatus set ShowRun @@ -607,42 +647,3 @@ ClearStepsButtons: set property `action` of Message to `clear` send Message to StepsModule return - -GetPassword: - if ReadOnly - begin - clear PasswordValid - return - end - if the hostname is `localhost` go to SetPasswordValid - if the hostname is `127.0.0.1` go to SetPasswordValid - - if not PasswordRequested - begin - set PasswordRequested - if hostname is `localhost` goto SetPasswordValid - if hostname is `127.0.0.1` goto SetPasswordValid - get Password from storage as `.password` - if Password is empty - begin - put `Please provide the admin password` cat newline - cat `or click OK to use private browser storage.` into Message - put prompt Message with `` into Password - end - rest get PasswordValid from `_verify/` cat Password - or begin - clear PasswordValid - return - end - if PasswordValid is `yes` - begin - put Password into storage as `.password` - set PasswordValid - end - else clear PasswordValid - end - return - -SetPasswordValid: - set PasswordValid - return \ No newline at end of file diff --git a/iwsy/resources/ecs/main.txt b/iwsy/resources/ecs/main.txt deleted file mode 100644 index 63e6c72..0000000 --- a/iwsy/resources/ecs/main.txt +++ /dev/null @@ -1,559 +0,0 @@ -! IWSY - - script IWSY - - div Body - div Left - div Right - div Controls - div ContentDiv - div Buttons - div Tabs - div Tab - div ScriptName - div StepsPanel - div BlocksPanel - div ContentPanel - div Player - span Status - span Span - input NameEditor - button SectionButton - img New - img Open - img Save - img RunStop - img Delete - img Cycle - a Link - module StepsModule - module BlocksModule - module ContentModule - variable Mobile - variable LastSavedState - variable Content - variable Script - variable Presentation - variable Name - variable CurrentName - variable PasswordValid - variable ShowRun - variable ReadOnly - variable PasswordRequested - variable Password - variable CallStack - variable Message - variable Section - variable Item - variable CurrentScriptName - variable N - - ! The browser - div Overlay - div Scroller - div Media - div FileListing - div FileRow - div LowerPanel - button CloseButton - a FileName - variable Alpha - variable List - variable FileList - variable FileCount - variable File - variable Files - variable FileIsOpen - -! Test if site is on a static host - clear ReadOnly - rest get List from `_list/scripts` - or begin - print `Static site` - set ReadOnly - go to L2 - end -L2: - clear PasswordRequested - put empty into CallStack - history set - on restore - begin - put the json count of CallStack into N - end - if portrait - begin - if mobile set Mobile else clear Mobile - end - - set the title to `IWSY` - create Body - if Mobile - set the style of Body to `width:100%;height:100%` - else - set the style of Body to `width:100%;height:100%;display:flex` - -! The left-hand panel - create Left in Body - set the style of Left to `flex:1;height:100%;border-right:1px solid black;margin-right:0.5em` - - create Controls in Left - set the style of Controls to `padding:0 0.5em` - - create Buttons in Controls - set the style of Buttons to `width:100%;padding:0.5em 0` - - create ScriptName in Controls - set the style of ScriptName to `display:flex` - if Mobile set style `display` of ScriptName to `none` - create Span in ScriptName - set the style of Span to `flex:15` - set the content of Span to `Script name: ` - create NameEditor in ScriptName - set the style of NameEditor to `flex:85;display:inline-block` - - create Link in Buttons - create New in Link - set the style of New to `width:40px;margin-right:0.5em` - set attribute `src` of New to `resources/icon/new.png` - set attribute `title` of New to `New` - create Open in Link - set the style of Open to `width:40px;margin-right:0.5em` - set attribute `src` of Open to `resources/icon/open.png` - set attribute `title` of Open to `Open` - create Link in Buttons - create Save in Link - set the style of Save to `width:40px;margin-right:1.5em` - set attribute `src` of Save to `resources/icon/save.png` - set attribute `title` of Save to `Save` - create Link in Buttons - create Delete in Link - set the style of Delete to `width:40px;margin-right:1.5em` - set attribute `src` of Delete to `resources/icon/trash.png` - set attribute `title` of Delete to `Delete` - create Link in Buttons - create RunStop in Link - set the style of RunStop to `width:40px;margin-right:1.5em` - set attribute `src` of RunStop to `resources/icon/run.png` - set attribute `title` of RunStop to `Run` - create Link in Buttons - create Cycle in Link - set the style of Cycle to `width:40px` - set attribute `src` of Cycle to `resources/icon/cycle.png` - set attribute `title` of Cycle to `Cycle screens` - - create Status in Buttons - if Mobile set the style of Status to `height:1em` - else set the style of Status to `float:right;margin:0.5em 0 0 0;color:green` - - create Player in Left - set the style of Player to `margin:0.5em` - iwsy init - -! The right-hand panel - create Right in Body - set the style of Right to `flex:1;height:100%;display:flex;flex-direction:column;overflow:hidden` - - create ContentDiv in Right - set the style of ContentDiv to `width:100%;height:100%;position:relative` - - create Tabs in ContentDiv - set the style of Tabs to `width:100%;padding:0.5em 0;text-align:center` - set the elements of SectionButton to 3 - divide 100 by the elements of SectionButton giving N - create Tab in Tabs - set the style of Tab to `display:inline-block;width:` cat N cat `%` - index SectionButton to 0 - create SectionButton in Tab - set the style of SectionButton to `width:100%` - set the content of SectionButton to `Steps` - create StepsPanel in ContentDiv - set the style of StepsPanel to `position:absolute;left:0;top:2.5em;width:100%;height:calc(100% - 2.5em)` - create Tab in Tabs - set the style of Tab to `display:inline-block;width:` cat N cat `%` - index SectionButton to 1 - create SectionButton in Tab - set the style of SectionButton to `width:100%` - set the content of SectionButton to `Blocks` - create BlocksPanel in ContentDiv - set the style of BlocksPanel to `position:absolute;left:0;top:2.5em;width:100%;height:calc(100% - 2.5em)` - create Tab in Tabs - set the style of Tab to `display:inline-block;width:` cat N cat `%` - index SectionButton to 2 - create SectionButton in Tab - set the style of SectionButton to `width:100%` - set the content of SectionButton to `Content` - create ContentPanel in ContentDiv - set the style of ContentPanel to `position:absolute;left:0;top:2.5em;width:100%;height:calc(100% - 2.5em)` - - put 0 into Section - index SectionButton to 0 - on click SectionButton - begin - put the index of SectionButton into N - gosub to SelectSection - end - -! Create the file browser - create Overlay in Body - set the style of Overlay to - `position:absolute;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.0);display:none` - - create Media in Overlay - set style of Media to `display:none;width:100%;height:100%;text-align:center` - - create FileListing in Media - set the style of FileListing to - `display:none;width:50%;height:75%;margin:auto;background-color:white;` - cat `padding:2em 2em 3em 2em;text-align:center;position: absolute;top: 50%;left: 50%;` - cat `transform: translateX(-50%) translateY(-50%)` - - create Scroller in FileListing - set the style of Scroller to `height:100%;overflow:scroll;text-align:left` - - create LowerPanel in FileListing - - create CloseButton in LowerPanel - set the style of CloseButton to `margin-left:2em` - set the text of CloseButton to `Close` - - put empty into LastSavedState - - on click New - begin -! gosub to StopTestModule - if Presentation is not LastSavedState - begin - if confirm `Content has changed. Do you want to save it?` - begin - put the content of NameEditor into Name - if Name is empty - begin - gosub to SetStatusRed - set the content of Status to `No script name has been given` - go to ResetStatus - end - if PasswordValid rest post Presentation to `_save/json/` cat Name - else put Presentation into storage as CurrentName - end - end - clear FileIsOpen - set the content of NameEditor to empty - put empty into CurrentScriptName - gosub to CreateNewPresentation - put Presentation into LastSavedState - gosub to UpdateCurrentSection - end - - on click Open go to DoOpen - - on click Save - begin - gosub to SaveChanges - gosub to GetPassword - put the content of NameEditor into Name - if Name is empty - begin - gosub to SetStatusRed - set the content of Status to `No script name has been given` - go to ResetStatus - end - if the position of `.json` in Name is -1 put Name cat `.json` into Name - replace ` ` with `_` in Name - set the content of NameEditor to Name - if Name is not CurrentScriptName put empty into LastSavedState - if Presentation is not LastSavedState - begin - if PasswordValid rest post Presentation to `_save/json/` cat Name - else put Presentation into storage as Name - put Presentation into LastSavedState - gosub to SetStatusGreen - set the content of Status to `Presentation '` cat Name cat `' saved` - put Name into CurrentScriptName - fork to ResetStatus - end - else - begin - gosub to SetStatusGreen - set the content of Status to `Nothing has changed` - fork to ResetStatus - end - end - - on click Delete - begin - gosub to GetPassword - put the content of NameEditor into Name - if Name is empty - begin - gosub to SetStatusGreen - set the content of Status to `Nothing to delete` - go to ResetStatus - end - if confirm `Are you sure you want to delete "` cat Name cat `"?` - begin - if PasswordValid rest post to `_delete/json/` cat Name - else remove Name from storage - gosub to SetStatusGreen - set the content of Status to `Script "` cat Name cat `" deleted` - set the content of NameEditor to empty - put empty into CurrentScriptName - put empty into Presentation - put Presentation into LastSavedState - go to ResetStatus - end - end - - gosub to CreateNewPresentation - put Presentation into LastSavedState - gosub to SetupSteps - gosub to SetupBlocks - gosub to SetupContent - put 0 into N - gosub to SelectSection - - on message - begin - put the message into N - iwsy goto N - end - stop - -CreateNewPresentation: - set Presentation to object - set Item to object - set property `blocks` of Presentation to Item - set property `content` of Presentation to Item - set Item to array - set property `steps` of Presentation to Item - return - -SetupSteps: - if StepsModule is not running - begin - rest get Script from `/resources/ecs/steps.txt` - run Script with StepsPanel and Presentation as StepsModule - end - return - -SetupBlocks: - if BlocksModule is not running - begin - rest get Script from `/resources/ecs/blocks.txt` - run Script with BlocksPanel and Presentation as BlocksModule - end - return - -SetupContent: - if ContentModule is not running - begin - rest get Script from `/resources/ecs/content.txt` - run Script with ContentPanel and Presentation as ContentModule - end - return - -! Select one of the 3 sections -SelectSection: - gosub to SaveChanges - index SectionButton to Section - set style `background` of SectionButton to `` - put N into Section - index SectionButton to Section - set style `background` of SectionButton to `lightgray` - -! Update the current section -UpdateCurrentSection: - set style `display` of StepsPanel to `none` - set style `display` of BlocksPanel to `none` - set style `display` of ContentPanel to `none` - if Section is 0 - begin - set style `display` of StepsPanel to `block` - send to StepsModule - end - else if Section is 1 - begin - set style `display` of BlocksPanel to `block` - send to BlocksModule - end - else if Section is 2 - begin - set style `display` of ContentPanel to `block` - send to ContentModule - end - return - -SaveChanges: - send `save` to StepsModule - send `save` to BlocksModule - send `save` to ContentModule - return - -DoOpen: -! gosub to StopTestModule - gosub to GetPassword - - clear FileIsOpen - if Presentation is not LastSavedState - begin - if confirm `Content has changed. Do you want to save it?` - begin - if PasswordValid rest post Content to `_save/json/` cat Name - else put Content into storage as Name - end - end - - ! Animate the background - set style `display` of Overlay to `block` - put 0 into Alpha - while Alpha is less than 8 - begin - set style `background-color` of Overlay to `rgba(0,0,0,0.` cat Alpha cat `)` - wait 4 ticks - add 1 to Alpha - end - wait 10 ticks - - ! Make the browser panel visible - set style `display` of Media to `block` - set style `display` of FileListing to `inline-block` - - ! Fill the browser with content from the server - if PasswordValid - begin - rest get Files from `_list/json` - put the json count of Files into FileCount - put empty into Content - put 0 into N - while N is less than FileCount - begin - put element N of Files into Item - if property `type` of Item is `json` json add property `name` of Item to Content - add 1 to N - end - end - else - begin - get Files from storage - put the json count of Files into FileCount - put empty into Content - put 0 into N - while N is less than FileCount - begin - put element N of Files into Item - if left 1 of Item is not `.` json add Item to Content - add 1 to N - end - end - json sort Content - put empty into FileList - put the json count of Content into FileCount - set the elements of File to FileCount - set the elements of FileName to FileCount - ! Add a row for each file - put 0 into N - while N is less than FileCount - begin - index File to N - index FileName to N - put `
` - cat `
` into File - replace `INDEX` with N in File - if N is even replace `ODDEVEN` with `ec-even` in File - else replace `ODDEVEN` with `ec-odd` in File - put FileList cat File into FileList - add 1 to N - end - - set the content of Scroller to FileList - ! Add the document names - put 0 into N - while N is less than FileCount - begin - index File to N - index FileName to N - put element N of Content into File - attach FileRow to `ec-file-row-` cat N - attach FileName to `ec-file-name-` cat N - set the content of FileName to File - if N is even set style `background` of FileRow to `lightgray` - on click FileName go to SelectFile - add 1 to N - end - on click CloseButton - begin - put LastSavedState into Content - go to CloseBrowser - end - stop - -SelectFile: - index File to the index of FileName - set the content of NameEditor to File - put File into CurrentScriptName - if PasswordValid rest get Presentation from `/resources/json/` cat File - else get Presentation from storage as File - put Presentation into LastSavedState - gosub to UpdateCurrentSection - set the content of Status to `Presentation '` cat File cat `' loaded` - fork to ResetStatus - set ShowRun - iwsy load Player Presentation - -CloseBrowser: - set style `background-color` of Overlay to `rgba(0,0,0,0.0)` - set style `display` of Overlay to `none` - set style `display` of Media to `none` - stop - -SetStatusRed: - set style `color` of Status to `red` - return - -SetStatusGreen: - set style `color` of Status to `green` - return - -ResetStatus: - wait 2 - set the content of Status to `` - stop - -GetPassword: - if ReadOnly - begin - clear PasswordValid - return - end - if the hostname is `localhost` go to SetPasswordValid - if the hostname is `127.0.0.1` go to SetPasswordValid - - if not PasswordRequested - begin - set PasswordRequested - if hostname is `localhost` goto SetPasswordValid - if hostname is `127.0.0.1` goto SetPasswordValid - get Password from storage as `.password` - if Password is empty - begin - put `Please provide the admin password` cat newline - cat `or click OK to use private browser storage.` into Message - put prompt Message with `` into Password - end - rest get PasswordValid from `_verify/` cat Password - or begin - clear PasswordValid - return - end - if PasswordValid is `yes` - begin - put Password into storage as `.password` - set PasswordValid - end - else clear PasswordValid - end - return - -SetPasswordValid: - set PasswordValid - return \ No newline at end of file diff --git a/iwsy/resources/ecs/scripted.txt b/iwsy/resources/ecs/scripted.txt index bdf4407..afee677 100644 --- a/iwsy/resources/ecs/scripted.txt +++ b/iwsy/resources/ecs/scripted.txt @@ -42,7 +42,7 @@ get Password from storage as `.password` if Password is empty put prompt `Please type the admin password` with `` into Password - rest get Valid from `_verify/` cat Password + rest get Valid from `verify/` cat Password or begin print Valid alert `Unable to verify password.` @@ -129,7 +129,7 @@ put the content of ContentEditor into Content if Content is not Current begin - rest post Content to `_save/ecs/` cat Name + rest post Content to `save/ecs/` cat Name put Content into Current set the content of Status to `Script '` cat Name cat `' saved` fork to ResetStatus @@ -155,7 +155,7 @@ if confirm `Are you sure you want to delete '` cat Name cat `'?` begin codemirror close ContentEditor - rest post to `_delete/ecs/` cat Name + rest post to `delete/ecs/` cat Name set the content of Status to `Script '` cat Name cat `' deleted` set the content of NameEditor to empty put empty into Content @@ -173,7 +173,7 @@ DoOpen: begin if confirm `Content has changed. Do you want to save it?` begin - rest post Content to `_save/ecs/' cat CurrentName + rest post Content to `save/ecs/' cat CurrentName codemirror attach to ContentEditor codemirror set content of ContentEditor to Content end @@ -201,7 +201,7 @@ DoOpen: set style `display` of FileListing to `inline-block` ! Fill the browser with content from the server - rest get Files from `_list/ecs?v=` cat now + rest get Files from `list/ecs?v=` cat now put the json count of Files into FileCount put empty into Content put 0 into N diff --git a/iwsy/resources/ecs/user.txt b/iwsy/resources/ecs/user.txt new file mode 100644 index 0000000..ce42007 --- /dev/null +++ b/iwsy/resources/ecs/user.txt @@ -0,0 +1,378 @@ +! Users + + script User + + import div Container + + div LoginDiv + div ItemDiv + div ButtonDiv + div EmailDiv + div ResetDiv + div PasswordDiv + div Password2Div + div NameDiv + div ConfirmationDiv + label Label + label Reset + label Back + input EmailInput + input ResetInput + input PasswordInput + input Password2Input + input NameInput + input ConfirmationInput + button LoginButton + button RegisterButton + button ResetPasswordButton + a Link + variable LabelWidth + variable FieldWidth + variable FieldHeight + variable Record + variable PasswordHash + variable ConfirmationCode + variable UserName + variable Email + variable Password + variable Validated + variable Message + + put 25 into LabelWidth + put 78 into FieldWidth + put `height:2em` into FieldHeight + + set the style of Container to `padding-top:0.5em` + + create LoginDiv in Container + set the style of LoginDiv to `padding:0.5em;border:1px solid black;display:none` + + create EmailDiv in LoginDiv + set the style of EmailDiv to `display:flex` + create Label in EmailDiv + set the style of Label to `padding-top:0.8em;flex:` cat LabelWidth + set the content of Label to `Email:` + create EmailInput in EmailDiv + set the style of EmailInput to FieldHeight cat `;padding:4px;flex:` cat FieldWidth + set the size of EmailInput to 40 + + create PasswordDiv in LoginDiv + set the style of PasswordDiv to `display:flex` + create Label in PasswordDiv + set the style of Label to `padding-top:0.8em;flex:` cat LabelWidth + set the content of Label to `Password:` + create PasswordInput in PasswordDiv + set the style of PasswordInput to FieldHeight cat `;flex:` cat FieldWidth + set the size of PasswordInput to 40 + set attribute `type` of PasswordInput to `password` + + create Password2Div in LoginDiv + set the style of Password2Div to `display:none` + create Label in Password2Div + set the style of Label to `padding-top:0.8em;flex:` cat LabelWidth + set the content of Label to `Password (again):` + create Password2Input in Password2Div + set the style of Password2Input to FieldHeight cat `;flex:` cat FieldWidth + set the size of Password2Input to 40 + set attribute `type` of Password2Input to `password` + + create ResetDiv in LoginDiv + set the style of ResetDiv to `display:none` + create Label in ResetDiv + set the style of Label to `padding-top:0.8em;flex:` cat LabelWidth + set the content of Label to `Reset Code:` + create ResetInput in ResetDiv + set the style of ResetInput to FieldHeight cat `;padding:4px;flex:` cat FieldWidth + set the size of ResetInput to 6 + + create NameDiv in LoginDiv + set the style of NameDiv to `display:none` + create Label in NameDiv + set the style of Label to `padding-top:0.8em;flex:` cat LabelWidth + set the content of Label to `Name or Nickname:` + create NameInput in NameDiv + set the style of NameInput to FieldHeight cat `;padding:4px;flex:` cat FieldWidth + set the size of NameInput to 40 + + create ConfirmationDiv in LoginDiv + set the style of ConfirmationDiv to `display:none` + create Label in ConfirmationDiv + set the style of Label to `padding-top:0.8em;flex:` cat LabelWidth + set the content of Label to `Confirmation Code:` + create ConfirmationInput in ConfirmationDiv + set the style of ConfirmationInput to FieldHeight cat `;padding:4px;flex:` cat FieldWidth + set the size of ConfirmationInput to 6 + + create ItemDiv in LoginDiv + set the style of ItemDiv to `display:flex;margin-top:0.5em` + create Label in ItemDiv + set the style of Label to `flex:` cat LabelWidth + + create ButtonDiv in ItemDiv + set the style of ButtonDiv to `flex:` cat FieldWidth + create LoginButton in ButtonDiv + set the style of LoginButton to `margin-right:1em` + set the text of LoginButton to `Login` + on click LoginButton go to ProcessLogin + create RegisterButton in ButtonDiv + set the style of RegisterButton to `margin-right:1em` + set the text of RegisterButton to `Register` + on click RegisterButton go to Register + create ResetPasswordButton in ButtonDiv + set style `display` of ResetPasswordButton to `none` + set the text of ResetPasswordButton to `Reset Password` + on click ResetPasswordButton go to ResetPassword2 + create Link in ButtonDiv + set the style of Link to `margin-left:3em` + create Reset in Link + set the text of Reset to `I lost my password` + on click Reset go to ResetPassword + create Link in ButtonDiv + set the style of Link to `margin-left:3em` + create Back in Link + set style `display` of Back to `none` + set the text of Back to `Back` + on click Back go to GoBack + + on message + begin + put the message into Message + if Message is `login` go to ShowLoginForm + else go to Start + end + set ready + stop + +! Start the user manager +Start: + get Email from storage as `email` + get Password from storage as `password` + if Email is empty stop + if Password is empty stop + go to SetupLogin + +! Show the login form +ShowLoginForm: + set the content of EmailInput to `` + set the content of PasswordInput to `` + set style `display` of LoginDiv to `block` + stop + +! Preload email and password fields +SetupLogin: + set the content of EmailInput to Email + set the content of PasswordInput to Password + +! Process a login request +ProcessLogin: + if EmailInput is empty go to FillAllFields + if PasswordInput is empty go to FillAllFields + rest get Record from `email/` cat EmailInput + if Record is empty go to NoRecord + if property `email` of Record is not EmailInput go to NoRecord + put property `password` of Record into Password + replace `/` with `~` in Password + rest get Validated from `validate/` cat Password cat `/` cat PasswordInput + if Validated is `yes` + begin + gosub to SetStorage + set style `display` of LoginDiv to `none` + gosub to DoLoggedIn + stop + end + +! Deal with no record error +NoRecord: + gosub to ClearStorage + alert `No record exists or incorrect password for ` cat EmailInput cat `.` + stop + +! Logged in, so tell the parent and hide the interface +DoLoggedIn: + gosub to SetStorage + set Message to object + set property `action` of Message to `user` + set property `user` of Message to Record + send Message to parent + set style `display` of LoginDiv to `none` + return + +ClearStorage: + put empty into storage as `email` + put empty into storage as `password` + return + +SetStorage: + put EmailInput into storage as `email` + put PasswordInput into storage as `password` + return + +! Register as new user +Register: + set style `display` of PasswordDiv to `flex` + set style `display` of Password2Div to `flex` + set style `display` of ResetDiv to `none` + set style `display` of NameDiv to `flex` + set style `display` of LoginButton to `none` + set style `display` of RegisterButton to `inline-block` + set style `display` of ResetPasswordButton to `none` + set style `display` of Reset to `none` + set style `display` of Back to `inline` + on click RegisterButton go to ProcessRegistration + stop + +! Process the registration +ProcessRegistration: + if EmailInput is empty go to FillAllFields + if PasswordInput is empty go to FillAllFields + if Password2Input is empty go to FillAllFields + if NameInput is empty go to FillAllFields + if PasswordInput is not Password2Input + begin + alert `Passwords do not match` + stop + end + + rest get Record from `email/` cat EmailInput + if Record is not empty go to EmailExists + rest get Record from `name/` cat NameInput + if Record is not empty go to NameExists + + put random 900000 into ConfirmationCode + add 100000 to ConfirmationCode + set Record to object + set property `from` of Record to `admin@iwannashowyou.com` + set property `to` of Record to EmailInput + set property `subject` of Record to `Confirmation code` + set property `message` of Record to `` + cat `Hi ` cat NameInput cat `

` + cat `Please use this code to confirm your registration at I Wanna Show You:
` + cat `

` cat ConfirmationCode cat `

` + cat `If you did not request this email, please ignore it and no action will be taken.` + cat `` + rest post Record to `email` + set style `display` of ConfirmationDiv to `flex` + set the text of RegisterButton to `Confirm registration` + wait 10 ticks + alert `We have sent a confirmation code to ` cat Email cat `.` cat newline + cat `When it arrives, type or paste it in the "Confirmation Code" box ` + cat `and click "Confirm Registration".` + on click RegisterButton + begin + if ConfirmationInput is not ConfirmationCode + begin + alert `Invalid confirmation code - no action taken.` + stop + end + gosub to SetStorage + set Record to object + set property `email` of Record to EmailInput + rest get PasswordHash from `hash/` cat PasswordInput + set property `password` of Record to PasswordHash + set property `name` of Record to NameInput + rest post Record to `user` + set style `display` of ConfirmationDiv to `none` + set the text of RegisterButton to `Register` + gosub to DoLoggedIn + end + stop + +! Email is already in use +EmailExists: + alert `A record already exists for ` cat EmailInput cat `.` + stop + +! Name is already in use +NameExists: + alert `A record already exists for ` cat NameInput cat `.` + stop + +! One or more fileds are empty +FillAllFields: + alert `Please fill in all the fields.` + stop + +! Reset the password +ResetPassword: + set style `display` of ResetDiv to `none` + set style `display` of PasswordDiv to `none` + set style `display` of Password2Div to `none` + set style `display` of LoginButton to `none` + set style `display` of RegisterButton to `none` + set style `display` of ResetPasswordButton to `inline-block` + set style `display` of Reset to `none` + set style `display` of Back to `inline-block` + wait 10 ticks + alert `Please type the email you used for your registration then click Reset Password.` + on click ResetPasswordButton go to ResetPassword2 + stop + +! Process the password reset +ResetPassword2: + if EmailInput is empty go to FillAllFields + rest get Record from `email/` cat EmailInput + if Record is empty + begin + alert ` No record exists for ` cat EmailInput cat `.` + go to Register + end + put property `name` of Record into UserName + put random 900000 into ConfirmationCode + add 100000 to ConfirmationCode + set Record to object + set property `from` of Record to `admin@iwannashowyou.com` + set property `to` of Record to EmailInput + set property `subject` of Record to `Password reset key` + set property `message` of Record to `` + cat `Hi ` cat NameInput cat `

` + cat `Please use this code to confirm your password reset request at I Wanna Show You:
` + cat `

` cat ConfirmationCode cat `

` + cat `If you did not request this email, please ignore it and no action will be taken.` + cat `` + rest post Record to `email` + set style `display` of ResetDiv to `flex` + set style `display` of PasswordDiv to `flex` + set the content of PasswordInput to `` + set style `display` of Password2Div to `flex` + set the content of Password2Input to `` + set the text of ConfirmationInput to `` + on click ResetPasswordButton go to ResetPassword3 + wait 10 ticks + alert `We have sent a password reset code to ` cat Email cat `.` cat newline + cat `When it arrives, use it on this screen to confirm your new password.` + stop + +! Confirm new password +ResetPassword3: + if PasswordInput is empty go to FillAllFields + if Password2Input is empty go to FillAllFields + if PasswordInput is not Password2Input + begin + alert `Passwords do not match` + stop + end + if ResetInput is not ConfirmationCode + begin + alert `Invalid password reset code - no action taken.` + stop + end + set Record to object + set property `email` of Record to EmailInput + rest get PasswordHash from `hash/` cat PasswordInput + set property `password` of Record to PasswordHash + set property `name` of Record to UserName + rest post Record to `user` + gosub to SetStorage + go to DoLoggedIn + +! Go back to the initial state +GoBack: + set style `display` of ResetDiv to `none` + set style `display` of PasswordDiv to `flex` + set style `display` of Password2Div to `none` + set style `display` of NameDiv to `none` + set style `display` of LoginButton to `inline-block` + set style `display` of Reset to `inline` + set style `display` of Back to `none` + on click RegisterButton go to Register + stop \ No newline at end of file diff --git a/iwsy/resources/icon/user-loggedin.png b/iwsy/resources/icon/user-loggedin.png new file mode 100644 index 0000000..f008575 Binary files /dev/null and b/iwsy/resources/icon/user-loggedin.png differ diff --git a/iwsy/resources/icon/user.png b/iwsy/resources/icon/user.png new file mode 100644 index 0000000..e79b633 Binary files /dev/null and b/iwsy/resources/icon/user.png differ diff --git a/iwsy/resources/img/SemoigoDawn.jpg b/iwsy/resources/img/SemoigoDawn.jpg new file mode 100644 index 0000000..0198202 Binary files /dev/null and b/iwsy/resources/img/SemoigoDawn.jpg differ diff --git a/iwsy/resources/json/demo.json b/iwsy/resources/json/demo.json deleted file mode 100644 index e34df5c..0000000 --- a/iwsy/resources/json/demo.json +++ /dev/null @@ -1,306 +0,0 @@ -{ - "blocks": [ - { - "defaults": { - "name": "background", - "left": 0, - "top": 0, - "width": "100%", - "height": "100%", - "background": "url('resources/img/SemoigoDawn.jpg')", - "border": "1px solid gray", - "borderRadius": "", - "fontFamily": "", - "fontSize": 50, - "fontWeight": "", - "fontStyle": "", - "fontColor": "", - "textAlign": "", - "textMarginLeft": "", - "textMarginTop": "" - } - }, - { - "defaults": { - "name": "mask", - "left": 0, - "top": 0, - "width": "100%", - "height": "100%", - "background": "white", - "border": "", - "borderRadius": "", - "fontFamily": "", - "fontSize": 50, - "fontWeight": "", - "fontStyle": "", - "fontColor": "", - "textAlign": "", - "textMarginLeft": "", - "textMarginTop": "" - } - }, - { - "defaults": { - "name": "title", - "left": 0, - "top": 800, - "width": "100%", - "height": 300, - "background": "", - "border": "", - "borderRadius": "", - "fontFamily": "", - "fontSize": 0, - "fontWeight": "", - "fontStyle": "", - "fontColor": "#dddd88", - "textAlign": "center", - "textMarginLeft": "", - "textMarginTop": "" - } - }, - { - "defaults": { - "name": "center title", - "background": "", - "border": "", - "borderRadius": "", - "fontColor": "#dddd88", - "fontFamily": "", - "fontSize": 70, - "fontStyle": "", - "fontWeight": "", - "height": 300, - "left": 0, - "textAlign": "center", - "textMarginLeft": "", - "textMarginTop": "", - "top": 300, - "width": "100%" - } - }, - { - "defaults": { - "name": "top title", - "background": "", - "border": "", - "borderRadius": "", - "fontColor": "#ccffff", - "fontFamily": "", - "fontSize": 40, - "fontStyle": "", - "fontWeight": "", - "height": 220, - "left": 0, - "textAlign": "center", - "textMarginLeft": "", - "textMarginTop": "", - "top": 20, - "width": "100%" - } - }, - { - "defaults": { - "name": "main content", - "left": 50, - "top": 250, - "width": 900, - "height": 700, - "background": "", - "border": "", - "borderRadius": "", - "fontFamily": "", - "fontSize": 50, - "fontWeight": "", - "fontStyle": "", - "fontColor": "yellow", - "textAlign": "left", - "textMarginLeft": 20, - "textMarginTop": 20 - } - }, - { - "defaults": { - "name": "left", - "background": "rgba(80,80,80,0.5)", - "border": "1px solid white", - "borderRadius": "", - "fontColor": "yellow", - "fontFamily": "", - "fontSize": 50, - "fontStyle": "", - "fontWeight": "", - "height": 700, - "left": 50, - "textAlign": "left", - "textMarginLeft": 20, - "textMarginTop": 20, - "top": 250, - "width": 400 - } - }, - { - "defaults": { - "name": "right", - "background": "rgba(80,80,80,0.5)", - "border": "1px solid white", - "borderRadius": "", - "fontColor": "yellow", - "fontFamily": "", - "fontSize": 50, - "fontStyle": "", - "fontWeight": "", - "height": 700, - "left": 550, - "textAlign": "left", - "textMarginLeft": 20, - "textMarginTop": 20, - "top": 250, - "width": 400 - } - } - ], - "content": [ - { - "name": "blank", - "content": "" - }, - { - "name": "a new dawn", - "content": "# A new dawn is coming..." - }, - { - "name": "iwannashowyou", - "content": "# I Wanna Show You%0a%0a### _knockout web-based presentations_" - }, - { - "name": "page 1 left", - "content": "### PowerPoint%0a%0a - is slide-based%0a - is a PC application%0a - is hard to embed%0a%0aPowerPoint is organized mainly around static text blocks and is tied to the desktop." - }, - { - "name": "page 1 right", - "content": "### I Wanna Show You%0a - is step based%0a - runs in your browser%0a - is fully embeddable%0a%0aIWannaShowYou is built to handle color, movement and the online environment." - } - ], - "steps": [ - { - "title": "My demo presentation", - "action": "init", - "label": "", - "aspect ratio": "160:89", - "background": "", - "border": "" - }, - { - "title": "Setup background and initial content", - "action": "set content", - "label": "", - "blocks": [ - { - "block": "background", - "content": "blank" - }, - { - "block": "mask", - "content": "blank" - }, - { - "block": "title", - "content": "a new dawn" - }, - { - "block": "left", - "content": "page 1 left" - }, - { - "block": "right", - "content": "page 1 right" - } - ] - }, - { - "title": "Show background and mask", - "action": "show", - "label": "", - "blocks": [ - "background", - "mask", - "title" - ] - }, - { - "title": "Pause before starting", - "action": "pause", - "label": "", - "duration": 1 - }, - { - "title": "Fade down mask", - "action": "fade down", - "label": "", - "blocks": [ - "mask" - ], - "duration": 3 - }, - { - "title": "Wait 1 second", - "action": "pause", - "label": "", - "duration": 1 - }, - { - "title": "Slide up title", - "action": "transition", - "label": "", - "target": "center title", - "duration": 2, - "block": "title" - }, - { - "title": "Wait 3 seconds", - "action": "pause", - "label": "", - "duration": 3 - }, - { - "title": "Change title", - "action": "crossfade", - "label": "", - "block": "title", - "target": "iwannashowyou", - "duration": 1 - }, - { - "title": "Wait 1 second", - "action": "pause", - "label": "", - "duration": 1 - }, - { - "title": "Move the title to the top", - "action": "transition", - "label": "", - "target": "top title", - "duration": 2, - "block": "title" - }, - { - "title": "Wait 1 second", - "action": "hold", - "label": "", - "duration": 1 - }, - { - "title": "Fade up first page", - "action": "fade up", - "label": "", - "blocks": [ - "left", - "right" - ], - "duration": 1 - } - ] -} \ No newline at end of file diff --git a/iwsy/resources/json/test.json b/iwsy/resources/json/test.json index 6b25e74..39dce42 100644 --- a/iwsy/resources/json/test.json +++ b/iwsy/resources/json/test.json @@ -90,7 +90,7 @@ "background": "", "border": "", "borderRadius": "", - "fontColor": "#ccffff", + "fontColor": "#aaffff", "fontFamily": "", "fontSize": 40, "fontStyle": "", @@ -134,16 +134,16 @@ "borderRadius": "", "fontColor": "yellow", "fontFamily": "", - "fontSize": 50, + "fontSize": 72, "fontStyle": "", "fontWeight": "", - "height": 700, - "left": 50, + "height": 1000, + "left": 0, "textAlign": "left", "textMarginLeft": 20, "textMarginTop": 20, - "top": 250, - "width": 400, + "top": 0, + "width": 450, "parent": "main content" } }, @@ -155,16 +155,16 @@ "borderRadius": "", "fontColor": "yellow", "fontFamily": "", - "fontSize": 50, + "fontSize": 72, "fontStyle": "", "fontWeight": "", - "height": 700, + "height": 1000, "left": 550, "textAlign": "left", "textMarginLeft": 20, "textMarginTop": 20, - "top": 250, - "width": 400, + "top": "00", + "width": 450, "parent": "main content" } } @@ -176,11 +176,11 @@ }, { "name": "a new dawn", - "content": "# A new dawn is coming..." + "content": "# A new dawn is here..." }, { "name": "iwannashowyou", - "content": "# I Wanna Show You%0a%0a### _knockout web-based presentations_" + "content": "# I Wanna Show You%0a%0a### _powerful web-based presentations_" }, { "name": "page 1 left", @@ -193,7 +193,7 @@ ], "steps": [ { - "title": "My demo presentation", + "title": "My demo ", "action": "init", "label": "", "aspect ratio": "160:89", diff --git a/iwsy/resources/properties.txt b/iwsy/resources/properties.txt index 82915a9..3cfa224 100644 --- a/iwsy/resources/properties.txt +++ b/iwsy/resources/properties.txt @@ -1 +1,16 @@ +# The properties file for I Wanna Show You + +# The URL of the MySQL server +sqlhost=mysql.iwannashowyou.com + +# The name of the database user +sqluser=graham + +# The database password +sqlpassword=eyore1948 + +# The database to use +sqldatabase=iwannashowyou + +# Admin password password=$2y$10$Kazqoaw6fGfV22bp3otJeO6Xra4bCsBJXq6JVAV07qOkHNDIFevWG diff --git a/iwsy/rest.php b/iwsy/rest.php index 4d5d87c..d7276ba 100644 --- a/iwsy/rest.php +++ b/iwsy/rest.php @@ -1,13 +1,12 @@ query("SELECT id from $table"); - //print "{\"count\":".mysqli_num_rows($result)."}"; - print mysqli_num_rows($result); - mysqli_free_result($result); - break; - - case 'list': - // List items by ID, with optional offset & count, defaulting to 0 & 10 - // Endpoint: {site root}/easycoder/rest.php/{table}/list/{offset}/{count} - switch (count($request)) { - case 2: - $offset = 0; - $count = $request[1]; - break; - case 3: - $offset = $request[1]; - $count = $request[2]; - break; - default: - $offset = 0; - $count = 10; - break; - } - $result = $conn->query("SELECT id FROM $table LIMIT $offset, $count"); - $response = '['; - while ($row = mysqli_fetch_object($result)) { - if ($response != '[') { - $response .= ','; - } - $response .= $row->id; - } - mysqli_free_result($result); - $response .= ']'; - print $response; - break; - - case 'names': - // List items by name in ascending alphabetical order, - // with optional offset & count, defaulting to 0 & 10 - // Endpoint: {site root}/easycoder/rest.php/{table}/names/{offset}/{count} - switch (count($request)) { - case 2: - $offset = 0; - $count = $request[1]; - break; - case 3: - $offset = $request[1]; - $count = $request[2]; - break; - default: - $offset = 0; - $count = 10; - break; - } - $result = $conn->query("SELECT name FROM $table ORDER BY name LIMIT $offset, $count"); - $response = '['; - while ($row = mysqli_fetch_object($result)) { - if ($response != '[') { - $response .= ','; + case 'email': + // Endpoint: {site root}/rest.php/email/{email} + $email= $request[0]; + if ($email) { + logger("SELECT * from users WHERE email='$email'"); + $result = query($conn, "SELECT * from users WHERE email='$email'"); + if ($row = mysqli_fetch_object($result)) { + $response->id = $row->id; + $response->email = $row->email; + $response->password = $row->password; + $response->name = $row->name; + $response->home = $row->year . '/' . str_pad($row->day, 3, '0', STR_PAD_LEFT); + print json_encode($response); } - $response .= "\"$row->name\""; - } - mysqli_free_result($result); - $response .= ']'; - print $response; - break; - - case 'id': - // Get a record given its id - // Endpoint: {site root}/easycoder/rest.php/{table}/id/{id} - if (count($request) < 2) { - http_response_code(400); - print "Incomplete REST query."; - exit; - } - $id = $request[1]; - $result = $conn->query("SELECT value FROM $table WHERE id='$id'"); - if ($row = mysqli_fetch_object($result)) { - print $row->value; } else { http_response_code(404); - print "Cannot get item id '$id' as it does not exist."; + print "{\"message\":\"REST: Email is empty.\"}"; } - mysqli_free_result($result); break; - + case 'name': - case 'query': - // Get a record given its name - // Endpoint: {site root}/easycoder/rest.php/{table}/name/{name} - if (count($request) < 2) { - http_response_code(400); - print "Incomplete REST query."; - exit; - } - $name = $request[1]; - $result = $conn->query("SELECT value FROM $table WHERE name='$name'"); - if ($row = mysqli_fetch_object($result)) { - print $row->value; - } else if ($action == 'name') { + // Endpoint: {site root}/rest.php/name/{name} + if ($request[0]) { + logger("SELECT * from users WHERE name='" . $request[0] . "'"); + $result = query($conn, "SELECT * from users WHERE name='" . $request[0] . "'"); + if ($row = mysqli_fetch_object($result)) { + $response->id = $row->id; + $response->email = $row->email; + $response->password = $row->password; + $response->name = $row->name; + $response->home = $row->year . '/' . str_pad($row->day, 3, '0', STR_PAD_LEFT); + print json_encode($response); + } + } else { http_response_code(404); - print "Cannot get item named '$name' as it does not exist."; + print "{\"message\":\"REST: Name is empty.\"}"; } break; - + default: http_response_code(404); - print "I don't understand this request."; + print "{\"message\":\"REST: Unknown action '$action'.\"}"; break; } } - ///////////////////////////////////////////////////////////////////////// // POST - function post($conn, $table, $request) { + function post($conn, $action, $request) { $ts = time(); - $action = $request[0]; switch ($action) { - case 'set': - // Set the value of a record - if (count($request) > 2) { - switch ($request[1]) { - case 'id': - // Set by id. The record must already exist - // Endpoint: {site root}/easycoder/rest.php/{table}/id/{id} - header("Content-Type: application/text"); - $value = stripslashes(file_get_contents("php://input")); - $id = $request[2]; - // See if there's an item with this id - $result = $conn->query("SELECT id FROM $table WHERE id=$id"); - if (mysqli_fetch_object($result)) { - // It exists, so update it - $value = urldecode($value); - logger("UPDATE $table SET value='$value',ts=$ts WHERE id=$id"); - query($conn, "UPDATE $table SET value='$value',ts=$ts WHERE id=$id"); - } else { - // Not found - http_response_code(404); - logger("{\"code\":\"404\",\"message\":\"Cannot set record $id of $table.\"}"); - print "{\"message\":\"Cannot set record $id of $table.\"}"; - } - mysqli_free_result($result); - break; - - case 'name': - // Set by name. If the record does not exist, add it - // Endpoint: {site root}/easycoder/rest.php/{table}/name/{name} - header("Content-Type: application/text"); - $value = stripslashes(file_get_contents("php://input")); - $name = $request[2]; - // See if there's an item with this name - $result = $conn->query("SELECT id FROM $table WHERE name='$name'"); - if (mysqli_fetch_object($result)) { - // It exists, so update it - query($conn, "UPDATE $table SET value='$value',ts=$ts WHERE name='$name'"); - } else { - // Add a new item - query($conn, "INSERT INTO $table (name,value,ts) VALUES ('$name','$value','$ts')"); - http_response_code(201); - } - mysqli_free_result($result); - break; - - default: - http_response_code(400); - print "{\"message\":\"Value '".$request[1]."' should be 'id' or 'name'.\"}"; - break; - } + case 'user': + // Endpoint: {site root}/rest.php/user + header("Content-Type: application/json"); + $value = stripslashes(file_get_contents("php://input")); + $json = json_decode($value); + $email = $json->email; + $password = $json->password; + $name = $json->name; + // Check if this user is already present + $result = query($conn, "SELECT id FROM users WHERE email='$email'"); + if ($row = mysqli_fetch_object($result)) { + // Yes, so update the record + logger("UPDATE users SET password='$password',name='$name',ts=$ts WHERE email='$email'"); + query($conn, "UPDATE users SET password='$password',name='$name',ts=$ts WHERE email='$email'"); } else { - http_response_code(400); - print "{\"message\":\"Incomplete REST query.\"}"; - } - break; - - case 'delete': - // Delete a record, by id or by name - // Endpoint: {site root}/easycoder/rest.php/{table}/delete/{id} - // Or: ...{site root}/easycoder/rest.php/table/delete/{name} - if (count($request) > 1) { - $item = $request[1]; - if (is_int($item)) { - // Delete the requested id - query($conn, "DELETE FROM $table WHERE id=$id"); - } else { - // Delete the named item - query($conn, "DELETE FROM $table WHERE name='$item'"); - } + // No, so add a new record + $year = date('Y'); + $day = str_pad(date('z'), 3, '0', STR_PAD_LEFT); + logger("INSERT INTO users (email,password,name,year,day,ts) VALUES ('$email','$password','$name','$year','$day','$ts')"); + query($conn, "INSERT INTO users (email,password,name,year,day,ts) VALUES ('$email','$password','$name','$year','$day','$ts')"); + mkdir("resources/$year/$day", 0777, true); } - break; - - case 'rename': - // Rename a record - // Endpoint: {site root}/easycoder/rest.php/{table}/rename - $value = $_POST['value']; - $id = $_POST['id']; - if (!$id && count($request) > 1) { - $id = $request[1]; - } - if ($id) { - query($conn, "UPDATE $table SET name='$name',value='$value' WHERE id=$id"); - } else { - $name = $_POST['name']; - $newname = $_POST['newname']; - // See if there's a data item with the new name - $result = $conn->query("SELECT id FROM $table WHERE name='$newname'"); - if ($row = mysqli_fetch_object($result)) { - // Conflict - http_response_code(409); - print "{\"message\":\"Cannot rename item '$name' to '$newname' as it already exists.\"}"; - } else { - // See if there's a data item with this name - $result = $conn->query("SELECT id FROM $table WHERE name='$name'"); - if ($row = mysqli_fetch_object($result)) { - // There's a data item to rename - $id = $row->id; - query($conn, "UPDATE $table SET name='$newname',value='$value' WHERE id=$id"); - } else { - // Not found - http_response_code(404); - print "{\"message\":\"Cannot rename item '$name' as it does not exist.\"}"; - } - } mysqli_free_result($result); - } break; - + default: - http_response_code(404); - print "{\"message\":\"Unrecognised action '$action' requested.\"}"; + http_response_code(400); + print "{\"message\":\"REST: Unknown action '$action' for 'users'.\"}"; break; } } diff --git a/iwsy/test.html b/iwsy/test.html new file mode 100644 index 0000000..29b1ced --- /dev/null +++ b/iwsy/test.html @@ -0,0 +1,20 @@ + + + + + + + + +
+ I Wanna Show You
+ Click/Tap or key Space/RightArrow to start in manual mode
+ Click/Tap or key Space/RightArrow to advance
+ Key Enter to start in auto mode
+ Click/Tap to exit auto mode +
+ + + + +