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
+
+ resources/json/demo.json
+
+
+
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 `` 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
+
+ test.json
+
+
+
+