-
Notifications
You must be signed in to change notification settings - Fork 0
Answers Tiny MCE tutorial #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 7 commits
27ebeb5
0e1cb5a
93fa4fd
2553e7a
9e580b9
08ac634
72f924f
8cd6478
e35d46a
db0c9a2
6bb06d3
cf91310
0a14b66
e55e9ee
1cbef4a
a99e5ed
5bb6e34
a4d9f6d
f6a9605
873894a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,10 @@ Let's model the x,y of the top-left and bottom-right corners. | |
| */ | ||
| export interface Boundz { | ||
| // TODO: add fields: x1, y1, x2, y2 | ||
| x1: number; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For this it's fine, but just as a heads up you'll see we normally mark most properties |
||
| y1: number; | ||
| x2: number; | ||
| y2: number; | ||
| } | ||
|
|
||
| /* | ||
|
|
@@ -27,10 +31,7 @@ We tell tsc to transpile to ES5, so IE works. | |
| Notice also that we have an explicit return type. This lets the compiler check that our | ||
| code matches the type signature. | ||
| */ | ||
| export const width = (b: Boundz): number => | ||
| /* TODO */ -1; | ||
|
|
||
| // TODO implement height function | ||
| export const width = (b: Boundz): number => b.x2 - b.x1; | ||
|
|
||
| /* | ||
| 3. Compiling. | ||
|
|
@@ -47,3 +48,5 @@ Ok, so we started off pretty easy. | |
| Now, code is useless without tests, so let's head over to Exercise1CodeStyleTest.ts | ||
| and write some tests. | ||
| */ | ||
|
|
||
| export const height = (b: Boundz): number => b.y2 - b.y1; | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -10,7 +10,7 @@ We don't write loops if we can help it. Instead, we go up a level, and call func | |||||
| The simplest of these is 'each' which just iterates. | ||||||
|
|
||||||
| TODO: Run the following code using this command: | ||||||
| yarn bedrock-auto -b chrome-headless -f src/test/ts/Exercise2ArrayFunctionsTest.ts | ||||||
| yarn bedrock-auto -b chrome-headless -f src/test/ts/part2/Exercise2ArrayFunctionsTest.ts | ||||||
| */ | ||||||
|
|
||||||
| export const runEach1 = (): void => { | ||||||
|
|
@@ -41,6 +41,7 @@ export const myFrogs: Frog[] = [ | |||||
|
|
||||||
| export const runEach2 = (): void => { | ||||||
| // TODO: Use Arr.each and console.log to print the name of each frog | ||||||
| Arr.each(myFrogs, (f: Frog) => console.log(f.name)) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
You don't need to declare the type here as it'll be inferred. We normally try to avoid re-declaring redundant types as if you have to change it later it just makes more work 🤷 |
||||||
| }; | ||||||
|
|
||||||
| /* | ||||||
|
|
@@ -65,8 +66,7 @@ export const runMap2 = (xs: number[]): string[] => | |||||
|
|
||||||
| // TODO: Return the frog's names and check it by running | ||||||
| // yarn bedrock-auto -b chrome-headless -f src/test/ts/Exercise2ArrayFunctionsTest.ts | ||||||
| export const frogNames = (fs: Frog[]): string[] => | ||||||
| []; | ||||||
| export const frogNames = (fs: Frog[]): string[] => Arr.map(fs, (f: Frog) => f.name); | ||||||
|
|
||||||
| // TODO: Return the frog's ages | ||||||
| // TODO: Write a test for this in Exercise2ArrayFunctionsTest | ||||||
|
|
@@ -83,12 +83,10 @@ export const evens = (xs: number[]): number[] => | |||||
|
|
||||||
| // TODO: Write a function that returns all the frogs that ribbit | ||||||
| // TODO: Run the provided test to check your answer. | ||||||
| export const ribbitting = (frogs: Frog[]): Frog[] => | ||||||
| []; | ||||||
| export const ribbitting = (frogs: Frog[]): Frog[] => Arr.filter(frogs, (f: Frog) => f.ribbits === true) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The |
||||||
|
|
||||||
| // TODO: Write a function that returns all frogs aged 8 or older | ||||||
| export const olderFrogs = (frogs: Frog[]): Frog[] => | ||||||
| []; | ||||||
| export const olderFrogs = (frogs: Frog[]): Frog[] => Arr.filter(frogs, (f: Frog) => f.age >= 8) | ||||||
|
|
||||||
| /* | ||||||
| 5. Arr.exists | ||||||
|
|
@@ -97,8 +95,9 @@ Arr.exists returns true if there is one or more element that matches a predicate | |||||
| */ | ||||||
|
|
||||||
| // TODO: Write a function that returns true if there's one or more ribbiting frogs | ||||||
|
|
||||||
| export const oneOrMoreRibbitingFrogs = (frogs: Frog[]) => Arr.exists(frogs, (f: Frog) => f.ribbits === true); | ||||||
| // TODO: Write a function that takes an array of numbers, and returns true if there are any negative numbers | ||||||
| export const hasNegativeNumber = (items: number[]) => Arr.exists(items, (i: number) => i < 0); | ||||||
|
|
||||||
| /* | ||||||
| 6. Arr.bind | ||||||
|
|
@@ -110,8 +109,7 @@ This behaviour of running map then flatten is why this function is sometimes cal | |||||
|
|
||||||
| TODO: Write a function that takes a list of strings, each string containing a comma-separated list of values, and returns all of the values as an array. | ||||||
| */ | ||||||
| export const splitCsvs = (csvs: string[]): string[] => | ||||||
| []; | ||||||
| export const splitCsvs = (csvs: string[]): string[] => Arr.bind(csvs, (s: string) => s.split(',')); | ||||||
|
|
||||||
| /* | ||||||
| 7. Arr.find | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,4 +1,5 @@ | ||||||
| import { Optional } from '@ephox/katamari'; | ||||||
| import { search } from '@ephox/sugar/lib/main/ts/ephox/sugar/api/dom/Focus'; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something went wrong with an auto import here I'm guessing... you'll find you'll get a lint error in any of our regular code for this fwiw. We also prefer used named imports as it makes the code more readable, e.g: |
||||||
|
|
||||||
| /* | ||||||
| Optional | ||||||
|
|
@@ -35,13 +36,19 @@ export const toPositiveInteger = (n: number): Optional<number> => | |||||
| n > 0 ? Optional.some(n) : Optional.none(); | ||||||
|
|
||||||
| // TODO: create a function which takes a string and returns some if the string is non-empty | ||||||
| export const isString = (s: string): Optional<string> => s ? Optional.some(s) : Optional.none(); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will work fine, but just as a style hint we don't allow falsy checks for non-boolean values like this most times, so it should probably be something like this instead:
Suggested change
|
||||||
|
|
||||||
| // TODO: create a function which takes a url as a string and returns the protocol part as an Optional. | ||||||
| // The string may or may not actually have a protocol. For the protocol to be valid, it needs to be all alpha characters. | ||||||
| // You can use a regex. | ||||||
| // Have a look at Exercise3OptionTest.ts for example input. Make sure the tests pass. | ||||||
| export const getProtocol = (url: string): Optional<string> => { | ||||||
| throw new Error("TODO"); | ||||||
| let result = null; | ||||||
| if (url) { | ||||||
| result = url.match(/^http(s)?/); | ||||||
| } | ||||||
|
|
||||||
| return result ? Optional.some(result[0]) : Optional.none(); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would return the wrong value if I had a string such as |
||||||
| }; | ||||||
|
|
||||||
| /* | ||||||
|
|
@@ -57,10 +64,13 @@ TODO: use Optional.from to implement the following DOM function | |||||
| */ | ||||||
|
|
||||||
| export const getNextSibling = (e: Element): Optional<ChildNode> => { | ||||||
| throw new Error("TODO"); | ||||||
| return Optional.from(e ? e.nextSibling : null); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you have a truthy check here as based on the types e cannot be nullable? As such, this could just be this:
Suggested change
|
||||||
| }; | ||||||
|
|
||||||
| // TODO: use Optional.from to implement a similar wrapper for Element.getAttributeNode(string) | ||||||
| export const getElementAttribute = (e: Element, attributeName: string): Optional<Attr> => { | ||||||
| return Optional.from(e && attributeName ? e.getAttributeNode(attributeName) : null) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to my previous comment this could be this instead:
Suggested change
|
||||||
| } | ||||||
|
|
||||||
| /* | ||||||
| How do we get data out of an Optional? Well, that's a bit tricky since there isn't always | ||||||
|
|
@@ -80,11 +90,10 @@ export const message = (e: Optional<string>): string => | |||||
| ); | ||||||
|
|
||||||
| // TODO: Implement a function using fold, that takes an Optional<number>. If it's some, double it. If it's none, return 0; | ||||||
| export const doubleNumber = (n: Optional<number>): number => n.fold(() => 0, (n: number) => n * 2); | ||||||
|
|
||||||
| // TODO: Implement a function that takes an Optional<T> for any type T. Return true if it's some, and false if it's none. | ||||||
| const trueIfSome = <T> (x: Optional<T>): boolean => { | ||||||
| throw new Error("TODO"); | ||||||
| }; | ||||||
| const trueIfSome = <T> (x: Optional<T>): boolean => x.fold(() => false, () => true); | ||||||
|
|
||||||
| /* | ||||||
| The last function you implemented is already part of the Optional type, and is called isSome(). | ||||||
|
|
@@ -107,8 +116,10 @@ You can do this with fold, but getOr is a shortcut. | |||||
| */ | ||||||
|
|
||||||
| // TODO: Using getOr, take an Optional<{age: number}> and turn it into an {age: number}, using a default value of 0. | ||||||
| export const toValueOr = (input: Optional<{age: number}>): {age: number} => input.getOr({age: 0}); | ||||||
|
|
||||||
| // TODO: Write the same function using fold | ||||||
| export const toValueOrWithFold = (input: Optional<{age: number}>): {age: number} => input.fold(() => {return {age: 0};}, (input: {age: number}) => input ); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
As you're using newer ECMAScript syntax here you don't need the |
||||||
|
|
||||||
|
|
||||||
| /* | ||||||
|
|
@@ -118,9 +129,13 @@ Let's explore this by converting Optionals to and from Arrays. | |||||
| */ | ||||||
|
|
||||||
| // TODO: Write a function that converts an Optional<A> to an A[] for any type A. | ||||||
|
|
||||||
| export const optionalToArray = <A>(input: Optional<A>): A[] => { | ||||||
| return input.isSome() ? input.toArray() : []; | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just as a heads up we try to avoid using Worth noting if using |
||||||
| } | ||||||
| // TODO: Write a function that converts an A[] to an Optional<A>. If the array has more than one element, only consider the first element. | ||||||
|
|
||||||
| export const arrayToOptional = <A>(input: A[]): Optional<A> => { | ||||||
| return Array.isArray(input) && input.length > 0 ? Optional.some(input[0]) : Optional.none(); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We already know this is an array, so you don't need the |
||||||
| } | ||||||
|
|
||||||
| /* | ||||||
| One of the most useful functions on Optional is "map". We say this function "maps a function over the Optional". | ||||||
|
|
@@ -139,12 +154,14 @@ const x: Optional<string> = Optional.some(3).map((x) => String(x)); // returns O | |||||
| const y: Optional<string> = Optional.none<number>().map((x) => String(x)); // returns Optional.none<string>() | ||||||
|
|
||||||
| // TODO: Write a function that takes an Optional<number> and adds 3 to the number | ||||||
| export const add3 = (number: Optional<number>) => number.map((x: number) => x + 3); | ||||||
|
|
||||||
| // TODO: Write a function that takes an Optional<string> and prefixes the string with "hello" | ||||||
| export const prefixHello = (input: Optional<string>) => input.map((i: string) => "hello " + i); | ||||||
|
|
||||||
| /* | ||||||
| TODO: If the below function is called, does it return a value or throw an exception? Why should it behave one way or the other? | ||||||
| Answer: ... | ||||||
| Answer: return Optional.none() since there is nothing to runs the function over | ||||||
| */ | ||||||
| const willItKersplode = (): Optional<string> => { | ||||||
| const z = Optional.none<string>(); | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -79,7 +79,15 @@ TODO: Extract a pure function for the logic hiding in this (impure) function | |||||
|
|
||||||
| type Mode = 'code' | 'design' | 'markdown'; | ||||||
|
|
||||||
| const hasMode = (m: Mode): boolean => { | ||||||
| return m === 'code' || m === 'design' || m === 'markdown' ? true : false; | ||||||
| } | ||||||
|
|
||||||
| const switchMode = (m: Mode): void => { | ||||||
| const valid = hasMode(m); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't really do anything meaningful unless you're accepting content from outside of TypeScript, as you can't pass a mode that isn't defined in the |
||||||
| if (valid) { | ||||||
| // do side effect | ||||||
| } | ||||||
| // pretend that something useful happens here that causes a side effect | ||||||
| }; | ||||||
|
|
||||||
|
|
@@ -120,12 +128,12 @@ const getOrElse1 = <A> (oa: Optional<A>, other: A): A => | |||||
| // Hang on - that looks familiar. The function we pass as the "some" case is the identity function. | ||||||
|
|
||||||
| // TODO: write a version of getOrElse1 using Fun.identity. | ||||||
|
|
||||||
| export const getOrElse2 = <A> (oa: Optional<A>, other: A): A => oa.fold(() => other, Fun.identity); | ||||||
| // TODO: What happens if you map the identity function over an Optional? | ||||||
| // Answer: ... | ||||||
| // Answer: Get the value of the Optional | ||||||
|
|
||||||
| // TODO: What happens if you map the identity function over an Array? | ||||||
| // Answer: ... | ||||||
| // Answer: Get the value of each element in the array | ||||||
|
|
||||||
| /* | ||||||
| In FP, we use a lot of little functions like identity, that seem insignificant on their own, but they come in handy | ||||||
|
|
@@ -149,17 +157,19 @@ Again, this looks familiar from our getOrElse1 function above. | |||||
|
|
||||||
| TODO: rewrite getOrElse1 using both Fun.identity and the "constant" function defined above. | ||||||
| */ | ||||||
|
|
||||||
| export const getOrElse3 = <A> (oa: Optional<A>, other: A): A => oa.fold(constant(other), Fun.identity) | ||||||
|
|
||||||
| /* | ||||||
| TODO: use katamari's Fun.constant in your getOrElse and see if it compiles. | ||||||
| */ | ||||||
| export const getOrElse4 = <A> (oa: Optional<A>, other: A): A => oa.fold(Fun.constant(other), Fun.identity) | ||||||
|
|
||||||
| // TODO: Write a function that takes an array of numbers and replaces each value with 9. | ||||||
| export const replaceElementWith9 = (items: number[]) => Optional.from(items).fold(Fun.constant([]), (items) => items.map(Fun.constant(9))); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is overly complicated, as again
Suggested change
|
||||||
|
|
||||||
|
|
||||||
| // TODO: In the previous question, what's the *same* between the input and output values | ||||||
| // Answer: | ||||||
| // Answer: They are the same type (number) and same number of elements?? | ||||||
|
|
||||||
|
|
||||||
| /* | ||||||
|
|
@@ -210,7 +220,7 @@ signature and handling for n-ary functions. Your rule-of-thumb is to use Fun.com | |||||
| */ | ||||||
|
|
||||||
| // TODO: use Fun.compose1 to write a function that doubles a number twice | ||||||
| export const dblX2: (x: number) => number = Fun.compose1(dbl, dbl); | ||||||
|
|
||||||
| // TODO: Rewrite this function to use a single map call and function composition | ||||||
| const dblOs = (oa: Optional<number>): Optional<string> => | ||||||
| oa.map(dbl).map(String); | ||||||
| export const dblOs = (oa: Optional<number>): Optional<string> => oa.map(Fun.compose1(String, dbl)); | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could just be simplified to this for what it's worth 🤷