Text goes here!
diff --git a/alt_wide_2.svg b/alt_wide_2.svg new file mode 100644 index 0000000..3610411 --- /dev/null +++ b/alt_wide_2.svg @@ -0,0 +1,69 @@ + diff --git a/bg_1.svg b/bg_1.svg new file mode 100644 index 0000000..4fb6305 --- /dev/null +++ b/bg_1.svg @@ -0,0 +1,57 @@ + diff --git a/data.json b/data.json new file mode 100644 index 0000000..c1e0484 --- /dev/null +++ b/data.json @@ -0,0 +1,1451 @@ +{ + "/": { + "meta title": "Reference", + "chapters": [ + { + "title": "Introduction", + "topics": [ + { + "contents": [ + { + "text": "
SimplyEdit is a tool to build websites and web application user interfaces. It allows you to create an easy to use interface to edit websites or enter data. Most of this can be done without programming, you only need to add a few attributes in your HTML.
SimplyEdit divides your data into two concepts: fields and lists. A field can be any HTML element. When using SimplyEdit to edit a website, a field is any part of a webpage that is meant to be editable.
A list can also be any HTML element. But a list can contain any number of entries. Each entry can contain fields, or further lists. A list is comparable to an array of objects.
Unlike most other systems, SimplyEdit doesn't require you to define a model or schema for your data. Instead SimplyEdit reads your HTML and figures out what your data model or schema is from the attributes in the HTML.
You can still change the HTML without changing your data model, if you keep the nesting of lists and fields, and their names, identical. This is usually more than enough freedom to create completely different layouts for the same data.
", + "data-simply-template": "text" + } + ], + "title": "Basic Concepts" + } + ] + }, + { + "title": "Settings", + "topics": [ + { + "contents": [ + { + "text": "The most important settings for SimplyEdit are set as attributes on the `<script>` tag:
", + "data-simply-template": "text" + }, + { + "code": "<script src=\"//cdn.simplyedit.io/1/simply-edit.js\"\n data-api-key = \"your-key-1234\"\n data-simply-images = \"/img/\"\n data-simply-files = \"/files/\"\n data-simply-storage = \"myStorage\"\n data-simply-endpoint = \"/\"\n data-simply-settings = \"mySettings\"\n data-simply-datasources = \"myDataSources\"\n></script>", + "data-simply-template": "code" + }, + { + "text": "In addition you can specify settings for specific plugins and toolbars using the variable specified in data-simply-settings, e.g.:
", + "data-simply-template": "text" + }, + { + "code": "<script>\n window.mySettings = {\n }\n</script>", + "data-simply-template": "code" + }, + { + "text": "Some storage engines can have extra atributes. E.g. github uses:
You can read more about the different storage engines in the Storage section.
", + "data-simply-template": "text" + } + ], + "title": "Script attributes" + }, + { + "title": "simply-text-selection and simply-text-cursor", + "contents": [ + { + "text": "The text toolbar allows you to specify which block and inline tags to list. Both text toolbars use the same style configuration, but you must specify both of them:
In addition you can specify sets of classes, where the user may select one per set. Each set works like a set of radio buttons:
", + "data-simply-template": "text" + }, + { + "code": "var textSettings = {\n 'style': [\n {\n description: 'Color',\n selector: '*',\n styles: [\n {'class':'red', name: 'Red', icon: 'fa-paint-brush'},\n {'class':'green', name: 'Green', icon: 'fa-paint-brush'},\n {'class':'blue', name: 'Blue', icon: 'fa-paint-brush'}\n ]\n },{\n description: 'Emphasis',\n selector: 'h1,h2,h3,p',\n styles: [\n {'class':'highlight', name: 'Highlight', icon: 'fa-sun-o'},\n {'class':'lowlight', name: 'Lowlight', icon: 'fa-moon-o'}\n ]\n }\n ]\n};", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "Each style entry has a description, which will be shown in the popup toolbar. It has a selector, which is checked against the current selection. The styles are only shown when the current selection matches the selector.
The image toolbar also supports sets of classes, just like the text toolbars:
", + "data-simply-template": "text" + }, + { + "code": "var mySettings = {\n 'simply-image': {\n 'style' : [\n {\n description: 'Border',\n selector: 'img',\n styles: [\n {'class': 'shadow', name: 'Shadow', icon: 'fa-moon-o'},\n {'class': 'border', name: 'Border', icon: 'fa-square-o'}\n ]\n }\n ]\n }\n};", + "data-simply-template": "code" + }, + { + "text": "In addition, you can setup SimplyEdit to automatically use responsive images. This means that all images your users upload will be scaled to the sizes you specify. SimplyEdit will automatically choose the best fitting image size to display for each individual image. This requires you to also load the image scaler plugin:
", + "data-simply-template": "text" + }, + { + "code": "var mySettings = {\n 'simply-image' : {\n 'responsive' : {\n 'sizes' : [ 1024, 720, 640, 320, 160 ]\n }\n },\n 'plugins' : [ 'plugin.simply-scaler.html' ]\n};", + "data-simply-template": "code" + } + ] + }, + { + "title": "Page templates", + "contents": [ + { + "text": "SimplyEdit is a simple content management system. It allows you to create new pages. Each page can have a different template. A template is just a HTML file. You can tell SimplyEdit which page templates there are like this:
", + "data-simply-template": "text" + }, + { + "code": "var mySettings = {\n 'pageTemplates': {\n 'templates': [\n {name: 'Default', template: 'index.html'},\n {name: 'Blog post', template: 'blog.html'}\n ]\n }\n};", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "The default location for templates is in your site root in the templates/
subdirectory.
Makes an HTML element editable in the browser in editmode. It also adds the contents to the data store. This means that you can change the contents of the field in javascript simply by changing the javascript object, like this:
", + "data-simply-template": "text" + }, + { + "code": "editor.pageData.title.innerHTML = 'New Title';", + "data-simply-template": "code" + }, + { + "text": "This attribute can be set on any HTML element. Depending on which HTML element, it will expect and set different properites:
*
: innerHTMLA
: href, name, target, newwindow, nofollow and innerHTMLIMG
: src, class, alt and titleINPUT[type=\"text\"]
: valueINPUT[type=\"hidden\"]
: valueINPUT[type=\"number\"]
: valueINPUT[type=\"radio\"]
: checked, value, simplyData*INPUT[type=\"checkbox\"]
: checkedSELECT
: value, simplyValue*SELECT[multiple]
: selectedOptions, simplyValue*OPTION
: value, innerHTMLTEXTAREA
: valueIFRAME
: srcMETA
: contentFields may not contain other fields, except when using data-simply-content=\"fixed\"
.
Fields with the same name on the same page will always have the same content. Except when the field is part of a list entry, or if you\u2019ve specified a different path with data-simply-path
.
A field name may contain any valid character for HTML attributes, including spaces. But the .
character has a specific meaning, it will assume everything before the .
is the name of an object and after the .
is a property of that object.
Tells SimplyEdit what kind of content the field may contain. Expects one of the following values:
text
Allow only pure text inside this field.fixed
Only attributes on the element are editable. The innerHTML will not be set or updated.attributes
Only make the attributes of the element editable. By default all attributes will be stored. You can override this with the data-simply-attributes attribute.template
The value of the field will be used to select a template. The template name must match the value of the field. If the field is not available in the data store yet, you can set a default value with the data-simply-default-value attribute.Used in combination with data-simply-content=\"attributes\"
, this allows you to specify which attributes are databound using SimplyEdit. The example above shows how you can use this to edit specific attributes. Each div
above is bound to a specific attribute value. By changing the content of the div
, you change the value of the attribute in the button
as well.
You can also change the attributes in javascript, like this:
", + "data-simply-template": "text" + }, + { + "code": "editor.pageData.product['data-item-name'] = 'A splendid product';", + "data-simply-template": "code" + } + ], + "title": "data-simply-attributes" + }, + { + "contents": [ + { + "code": "<input type=\"radio\" name=\"size\" value=\"small\" data-simply-field=\"size\">Small\n<input type=\"radio\" name=\"size\" value=\"large\" data-simply-field=\"size\">Large\n<div data-simply-field=\"size\" data-simply-content=\"template\">\n <template data-simply-template=\"small\">\n Small size selected\n </template>\n <template data-simply-template=\"large\">\n Large size selected\n </template>\n</div>", + "data-simply-template": "code" + }, + { + "text": "Used in combination with data-simply-content=\"template\"
, this allows you to specify which template to use for the content of the current html element. The value of the field is matched with the name of the templates listed in the field. In this case radio buttons are used to select the specific template.
You can also change the template in javascript like this:
", + "data-simply-template": "text" + }, + { + "code": "editor.pageData.size = 'small';", + "data-simply-template": "code" + }, + { + "text": "If no template is specified, nothing is shown. You can specify a default value in the HTML like this:
", + "data-simply-template": "text" + }, + { + "code": "<div data-simply-field=\"size\" data-simply-content=\"template\" \n data-simply-default-value=\"small\">", + "data-simply-template": "code" + } + ], + "title": "data-simply-template" + }, + { + "contents": [ + { + "code": "<ul data-simply-list=\"items\">\n <template>\n <li>\n <a data-simply-field=\"entry\">Entry</a>\n </li>\n </template>\n</ul>", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "Specifies the content is a list of items. Each item can have multiple fields. One or more templates may be defined for the items. If a specific template is selected for an item, the template name will be stored inside the item as data-simply-template. When rendering the list, if no matching template is found, the first template specified will be used.
" + }, + { + "code": "<dl data-simply-list=\"items\">\n <template data-simply-template=\"topic\">\n <dt data-simply-field=\"entry\">Topic</dt>\n </template>\n <template data-simply-template=\"definition\">\n <dd data-simply-field=\"entry\">Definition</dd>\n </template>\n</dl>", + "data-simply-template": "code" + }, + { + "text": "In this example you can choose to add a topic (dt
) or definition (dd
) in a list. The resulting structure will look like this:
Lists may be nested inside other lists:
" + }, + { + "data-simply-template": "code", + "code": "<ul data-simply-list=\"menu\">\n <template data-simply-template=\"item\">\n <li>\n <a data-simply-field=\"item\">Item</a>\n </li>\n </template>\n <template data-simply-template=\"submenu\">\n <li>\n <a data-simply-field=\"submenu item\">Submenu</a>\n <ul data-simply-list=\"menu\">\n <template data-simply-template=\"item\">\n <li>\n <a data-simply-field=\"item\">Item</a>\n </li>\n </template>\n </ul>\n </li>\n </template>\n</ul>" + } + ], + "title": "data-simply-list" + }, + { + "contents": [ + { + "code": "<ul data-simply-list=\"items\" data-simply-sortable>\n <template>\n <li>\n <a data-simply-field=\"entry\">Entry</a>\n </li>\n </template>\n</ul>", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "Only valid in combination with data-simply-list
, this tells SimplyEdit to allow the editor to drag and drop entries within the list.
Only valid inside a data-simply-list
, or a data-simply-field
with data-simply-content=\"template\"
. This specified the name of the template. This is used to select and to store the selected template. If you have more than one template, this attribute is required and must be unique within the same list or field.
This tells SimplyEdit which icon to show in the toolbars when selecting a template. Any icon from Font Awesome 4 can be used.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-icon" + }, + { + "contents": [ + { + "code": "<section class=\"blog\" data-simply-list=\"blog\" data-simply-data=\"rss\">\n <template>\n <article>\n <h1 data-simply-field=\"title\">Title</a>\n <p data-simply-field=\"description\">Description</p>\n <p><a data-simply-field=\"link\">link</a></p>\n </article>\n </template>\n</section>", + "data-simply-template": "code" + }, + { + "text": "Connects a list to a data source. Read the chapter Data Sources for more information on their use.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-data" + }, + { + "contents": [ + { + "code": "<select data-simply-list=\"years\" data-simply-entry=\"year\">\n <template>\n <option data-simply-field=\"year\">2017</option>\n </template>\n</select>", + "data-simply-template": "code" + }, + { + "code": "editor.pageData.years = [ 2015, 2016, 2017 ];", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "Specifies which name to use for direct values of an array. In this case the years array is a simple list of values, not objects. So data-simply-entry=\"year\"
tells SimplyEdit to match the field year
with the full entry in the array.
This attribute is set automatically by SimplyEdit on each item in a list. It can be used to prefill a list in your HTML. Each item with this attribute is automatically appended to the list, even if it is not in the list data yet. This allows you to create a template with a list with a few list items set by default.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-list-item" + }, + { + "contents": [ + { + "code": "<nav>\n <ul data-simply-list=\"menu\" data-simply-path=\"/\">\n <template data-simply-template=\"item\">\n <li>\n <a data-simply-field=\"item\">Item</a>\n </li>\n </template>\n </ul>\n</nav>", + "data-simply-template": "code" + }, + { + "text": "Specifies the path to store all child data in. Most useful for site navigation and global footers.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-path" + }, + { + "contents": [ + { + "text": "This attribute is automatically set by SimplyEdit on any item that is user selectable, like list items, fields, etc.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-selectable" + }, + { + "contents": [ + { + "text": "Any element marked with this attribute will be hidden when in edit mode. This allows you to hide certain elements that would otherwise interfere with editing a webpage.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-hidden" + }, + { + "contents": [ + { + "text": "Used to make static images responsive. A static image is an image which is not editable, e.g. a website logo. By using this attribute instead of the normal src attribute, SimplyEdit will look for the best fitting size and set the src automatically. Remember that the image must be uploaded with SimplyEdit so that all the sizes set in the image settings are available.
", + "data-simply-template": "text" + }, + { + "code": "<img data-simply-src=\"logo.png\" alt=\"my logo\">", + "data-simply-template": "code" + } + ], + "title": "data-simply-src" + }, + { + "contents": [ + { + "text": "This attribute is automatically set by SimplyEdit on the body
element, when the editor is started. This allows you to check if the editor is started in javascript as well as css:
Used in combination with data-simply-content=\"template\"
, this allows you to specify the default template to use, if no other data is set.
Only applicable on the SimplyEdit script tag, this is your personal API key that is connected to your websites domain. Without a valid key SimplyEdit will not start the editor. Everything else will work without a valid key.
", + "data-simply-template": "text" + } + ], + "title": "data-api-key" + }, + { + "contents": [ + { + "text": "Only applicable on the SimplyEdit script tag, this specifies the name of the settings variable. To read more about the settings, see the chapter titled 'Settings'.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-settings" + }, + { + "contents": [ + { + "text": "Only applicable on the SimplyEdit script tag, this specifies the URL endpoint where SimplyEdit will store the site data. This does not include the images and files, they have a seperate attribute.
The default storage layer in SimplyEdit will store data through a PUT
request to this storage endpoint URL, appended with data/data.json
.
Specifies the root URL to store and retrieve images.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-images" + }, + { + "contents": [ + { + "text": "Specifies the root URL to store and retrieve files.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-files" + }, + { + "contents": [ + { + "text": "This attribute is set by SimplyEdit automatically, to keep track of all the fields and lists that have been 'stashed'. This means their data is collected and will be sent to the storage layer to save.
", + "data-simply-template": "text" + } + ], + "title": "data-simply-stashed" + } + ] + }, + { + "title": "Data Binding", + "topics": [ + { + "contents": [ + { + "text": "SimplyEdit automatically initializes a databinding for each field and list it finds in the HTML template. It connects all the data in your data.json to their corresponding fields and lists in the HTML. There is no initialization needed.
", + "data-simply-template": "text" + } + ], + "title": "Setup" + }, + { + "contents": [ + { + "text": "All the fields and lists are added to editor.pageData
, which is a shortcut for editor.currentData[{currentpath}]
.
When your site data is loaded from storage, e.g. the data.json file, this data will be inserted into editor.currentData
. All the fields in your json that correspond to a field or list in your HTML are automatically bound to their DOM elements. Whenever the editor.currentData
changes, so will the DOM.
The other way around also works. Whenever the DOM changes, SimplyEdit will notice and push the change on its internal stack. With a slight delay this change will then be applied to the editor.currentData
as well. This change is not instantanious, by design.
You can hook into the databinding flow with a few events. These events are fired by the databinding layer and you can listen in on them:
databind:resolved
is fired on the document whenever a change in data is rendered in the DOM.databind:elementresolved
is fired on each DOM element whenever a change in data is rendered there.In addition these events you can fire yourself to influence the databinding resolution and rendering. You will only need these when working with very large sets of data and changes. Otherwise just let SimplyEdit handle all this automatically.
databinding:valuechanged
Fire this when a value is changed in the DOM, but SimplyEdit isn't aware of it. This can happen when you change some elements values through javascript.databinding:pause
Fire this when you are working on a set of changes in a time sensitive javascript routine. Don't forget to fire databinding:resume
later and perhaps databinding:valuechanged
.databinding:resume
Start the normal databinding flow up again after pausing it.A data source is a way to use lists of data, without two-way databinding. This has a few advantages:
A datasource is automatically loaded and rendered by SimplyEdit. A datasource can only be applied on a list.
A minimal datasource looks like this:
" + }, + { + "data-simply-template": "code", + "code": "editor.addDataSource('myDataSource', {\n load: function(el, callback) {\n var data = [1, 2, 3, 4];\n callback(data);\n }\n});" + }, + { + "data-simply-template": "text", + "text": "The name is used to apply the datasource to a SimplyEdit list:
" + }, + { + "data-simply-template": "code", + "code": "<select data-simply-list=\"options\" data-simply-data=\"myDataSource\" data-simply-entry=\"entry\">\n <template>\n <option data-simply-field=\"entry\"></option>\n </template>\n</select>" + }, + { + "data-simply-template": "text", + "text": "Note: Because the data in the datasource doesn't consists of objects with properties, the code above uses the data-simply-entry
attribute to define a name (entry
) for each entry in the data array.
A full list of arguments to addDataSource looks like this:
", + "data-simply-template": "text" + }, + { + "code": "editor.addDataSource(\n 'myDataSource',\n load: data, // may also be a function, see previous example\n save: function(stash) {\n },\n get: function(list) {\n },\n set: function(list, listData) {\n },\n applyOnce: true //false is the default\n);", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "The load and save methods manage data retrieval and saving to external sources. The get and set methods manage the same for the internal data retrieval and saving. For example, you can define a datasource that loads data from a Google Spreadsheet and updates the spreadsheet when data is changed in the SimplyEdit editor. For this you use the load and save methods.
However if you want the user to select which Google spreadsheet to load, you use the get and set methods to store and retrieve this information in the data.json.
The methods are called in this order:
On loading the data.json
:
set(listElement, listData)
load(listElement, callback) -> void, call callback(resultListData)
On pressing save
get(listElement) -> returns data to be saved in the data.json
save(stash) -> void
Finally SimplyEdit saves the data.json
In general you probably only need the load, optionally with the save method. Or you just want the get and set methods. Here are a few use cases with the methods you need to override:
You only need to use the save()
method if you want to save data to an external resource, after it is edited in SimplyEdit.
So what is this stash mentioned in the previous topic? SimplyEdit needs to gather all the data in the current page and send it to the server when you press the save button. It does this by collecting it in something called the stash. But data from a datasource shouldn't get saved in the data.json, so it also creates a stash per datasource.
This datasource stash contains all the fields and their data, as used in each list that uses the datasource. So if you have a single datasource used by multiple lists, the get() and save() methods on the datasource are called for each list.
The stash contains the following data:
list
: the list element that uses the datasourcedataPath
: a representation of the field and list nesting in this page, similar to a JSON pointerdataName
: the name of the list as stored in the data.json
data
: the list data as returned by load()
and perhaps edited by the userWhen you add your own save()
method, it is your responsibility to do whatever you need to do to save any changes made by the user back to the external resource, using the information above.
SimplyEdit uses a simple plugin system. For historic reasons the terms plugin and toolbars are considered equivalent. Each plugin or toolbar consists of a single file that may contain HTML, CSS and Javascript. Consider the toolbar.simply-icon.html plugin:
" + }, + { + "data-simply-template": "code", + "code": "<section id=\"simply-icon\" class=\"simply-section\">\n <h1>Insert icon toolbar</h1>\n <div class=\"simply-toolbar\">\n <ul class=\"simply-buttons\">\n <li><button data-simply-action=\"simply-symbol\">\n <i class=\"fa fa-rocket\"></i>Insert icon\n </button></li>\n </ul>\n </div>\n</section>\n<script type=\"text/javascript\">\n editor.addToolbar({\n \"name\" : \"simply-icon\",\n \"filter\" : {\n \"selector\" : \"i.fa\"\n }\n });\n</script>" + }, + { + "data-simply-template": "text", + "text": "This defines a toolbar that allows you to insert an icon using the Font Awesome icon set. Each plugin that has its own UI should define this inside a HTML <section>
tag with the class name simply-section
and a unique ID. You may define multiple such sections inside a single plugin.
Then add a <script> tag in which you call the SimplyEdit API to do the real work. In this case the addToolbar()
method is called, which requires the name (or ID) of the toolbar definition specified in the HTML earlier. And it requires a filter, which consists of one or more CSS selectors that define when the toolbar becomes visible.
SimplyEdit only allows one toolbar to be visible at any time. It uses the filter and the selectors inside them to calculate which toolbar has precedence. You can make the filter more specific by adding parent selectors:
" + }, + { + "data-simply-template": "code", + "code": "editor.addToolbar({\n name: 'simply-image',\n filter: {\n selector: 'IMG',\n parent: {\n selector: '*'\n }\n }\n});" + }, + { + "data-simply-template": "text", + "text": "In this case the image toolbar adds a parent selector that matches everything. This makes the image toolbar filter have a higher precedence than other toolbars that might match on the IMG
tag. If you create your own toolbars, you may have to experiment a bit with the correct filter setting. You can ask SimplyEdit to show what scores it has calculated for each toolbar it considered:
This will print the information for each toolbar SimplyEdit has considered and which toolbar has won. So:
" + }, + { + "data-simply-template": "code", + "code": "console.log(editor.context.explain.validFilters);" + }, + { + "data-simply-template": "text", + "text": "Will show all the filters that match the current selection, and their respective scores. Higher is better.
Toolbars can also define actions and an init and update method:
" + }, + { + "data-simply-template": "code", + "code": "editor.addToolbar({\n name: 'my-toolbar',\n filter: {\n selector: 'a.my-link',\n parent: {\n selector: '*'\n }\n },\n actions: {\n 'my-action': function(el) {\n alert('This is my action');\n }\n },\n init: function(config) {\n // intialize your settings\n },\n update: function(toolbar) {\n // update the visible toolbar\n }\n});" + }, + { + "data-simply-template": "text", + "text": "The init
function is called once, when the editor starts. It passes any information set for this toolbar in the global settings variable, the one named in the script tags data-simply-settings
parameter.
The update
function is called whenever the selection changes and this toolbar is visible. It has one argument: the toolbars section
element.
Besides toolbars you can add other plugins as well. The only difference really is whether or not you call the editor.addToolbar()
method. If you create a plugin that is not strictly a toolbar, consider using the editor.plugins
namespace to add your own. e.g.:
Actions are labels that connect a user interface or HTML element to a specific javascript function. Actions are defined either in toolbars, in the actions
parameter of the editor.addToolbar()
method, or as seperate actions using the editor.addAction()
method.
Actions are added to a toolbar button or input element, as a data-simply-action
attribute:
You can create as many buttons or input elements with a certain action as you like. You can specify any action that is added by any toolbar, as long as that toolbar or action is loaded. All actions are defined globally.
Note: actions are only loaded when the toolbars are. So if the editor isn't started, the actions aren't available. SimplyEdit doesn't even check for any data-simply-action
attribute untill the toolbars are loaded. So although you can add actions to elements in the normal page content, they will only work once the editor is started.
You can specify an action explicitly like this:
", + "data-simply-template": "text" + }, + { + "data-simply-template": "code", + "code": "editor.addAction('my-action', editor.plugins.myPlugin.myAction);" + }, + { + "data-simply-template": "text", + "text": "Actions only require a name and a method to call. The method has only one argument: the element with the data-simply-action
attribute that triggered this action:
Fires on the document
when SimplyEdit is finished initializing the page content. It has no parameters. Use this event instead of DocumentReady.
Fires on the document
when the user starts the editor. You can\u2019t prevent this.
Fires on the document
when the editor is finished loading all the toolbars and plugins. Use this to change or append to the toolbars.
Fires on the document
whenever data managed by SimplyEdit changes. It is fired after the change is resolved, so the DOM and the Editor should be in sync.
Parameters: - dataBinding
", + "data-simply-template": "text" + } + ] + }, + { + "title": "simply-data-applied", + "contents": [ + { + "text": "Fires on a data-simply-list
after it has been updated.
Parameter: - Target list element.
", + "data-simply-template": "text" + } + ] + }, + { + "title": "simply-data-saved", + "contents": [ + { + "text": "Fires on the document
after editor.currentData
is saved by a storage layer.
Parameter:
newData
The saved data as returned by the storage layer.*
Any other parameters may be set by the storage layer.Fires on the document
immediately after the storage layer has been initialized.
Fires on the document
after a file is saved by the storage layer. This event can be cancelled by calling preventDefault()
on it. The file will still be saved, but the files dialog won't be updated.
Parameters
path
The path that was passed to the storage layer.response
The http responseTextmessage
An error message, if error
is true
error
Boolean. True if an error occured. The error message is in message
.Fires on the document
after a file has been deleted by the storage layer. This event can be cancelled by calling preventDefault() on it. The file will still be deleted, but the files dialog won't be updated.
Parameters
path
The path that was passed to the storage layer.response
The http responseTextmessage
An error message, if error is trueerror
Boolean. True if an error occured. The error message is in message.Fires on the document
before SimplyEdit starts to collect the data for the storage layer and thus before the data is saved. This event cannot be cancelled. You can use this event to do some data manipulation before the data is saved. Especially useful if you have created data sources that have the editor.currentData
as their source.
Fires on the document
after SimplyEdit has collected all the data for the storage layer. This data is now also available in localStorage.data
. You could now revert any changes made in the simply-stash
event, without affecting the data sent to the storage layer.
Fires on the document
after trying to save an image using the storage layer has failed. This event can be cancelled by calling event.preventDefault()
. This means that SimplyEdit will not show an error message.
Parameters
path
The path of the imageresponse
The response of the storage layermessage
The error messageerror
true
Fires on the document
after trying to save a file using the storage layer has failed. This event can be cancelled by calling event.preventDefault()
. This means that SimplyEdit will not show an error message.
Parameters
path
The path of the fileresponse
The response of the storage layermessage
The error messageerror
true
Fires on the document
after trying to save a page using the storage layer has failed. This event can be cancelled by calling event.preventDefault()
. This means that SimplyEdit will not show an error message.
Parameters
path
The path of the pageresponse
The response of the storage layermessage
The error messageerror
true
Fired on the document
whenever a new list item is inserted.
Fired on a DOM element whenever its contents have been updated to reflect changes elsewhere.
", + "data-simply-template": "text" + } + ] + }, + { + "title": "databind:resolved", + "contents": [ + { + "text": "Fired on the document
whenever changes to the DOM have been made to reflect changes in the data structure.
An event you can fire to force the databinding to update the data bound to the field or list the event is fired upon. Some DOM changes cannot be detected automatically. This event allows you to still update the databinding in those cases.
", + "data-simply-template": "text" + }, + { + "code": "field.setAttribute('data-foo','bar');\neditor.fireEvent('databinding:valuechanged',field);", + "data-simply-template": "code" + } + ] + }, + { + "title": "databinding:pause", + "contents": [ + { + "text": "An event you can fire to stop the databinding updates. This can be helpful when you want to change a lot of data at once. By stopping the databinding while you do that, you can greatly increase the performance of the change. Restart the databinding by calling databinding:resume
.
An event you can fire to resume the databinding updates. See databinding:pause
for more information.
SimplyEdit has support for different storage schemes. By default it will try to autodetect the scheme based on the domain name and the data-simply-endpoint
attribute. Out of the box SimplyEdit supports the following storage schemes:
default
This assumes SimplyEdit can PUT
the data.json
file at the specified endpoint, appended with data/data.json
.github
This scheme is active on all domains ending on github.io
or github.com
, or when specified with data-simply-storage=\"github\"
.beaker
Active only with data-simply-storage=\"beaker\"
.ariadne
Active only with data-simply-storage=\"ariadne\"
.But besides these, you can write your own storage scheme and plug it into SimplyEdit. Before you do that though, check out if the default storage scheme works for you as-is.
", + "data-simply-template": "text" + } + ], + "title": "Introduction" + }, + { + "contents": [ + { + "text": "By default SimplyEdit uses a very simple protocol to store and retrieve the data of the whole site. Retrieval is done by making an HTTP GET request to the data-simply-endpoint appended with data/data.json. This json file should have the following format:
", + "data-simply-template": "text" + }, + { + "code": "{\n '/': {..},\n '/subdir/': {..}\n}", + "data-simply-template": "code" + }, + { + "text": "Each page in a site is represented with a key denoting the absolute path within the sites domain and an object containing all the data for that page. The properties of this page object are defined in the page template, using the data-simply-field and data-simply-list attributes.
When you press save, SimplyEdit sends a new GET request for the data.json file and checks that it hasn't changed. If it has, SimplyEdit will try to merge the data automatically. But if that fails, SimplyEdit opens a dialog with the differences highlighted and asks the user to perform the merge by hand.
Then SimplyEdit sends a PUT request to the exact same location. The contents of the body contain the complete data.json file.
You can just write your own server-side code to handle this flow and store the contents of the data.json file however you like. You don't have to include all the sites data in the data.json either, just those parts that are needed to render the current page. However, SimplyEdit will only save what you send it in the first place, so if you go this route, it is your responsibility to retrieve and store the correct parts.
", + "data-simply-template": "text" + } + ], + "title": "The Default Storage" + }, + { + "title": "Custom Storage", + "contents": [ + { + "text": "When the default storage schemes aren't sufficient, you can just write your own and plug it into SimplyEdit. For example this storage scheme stores all content in localStorage:
", + "data-simply-template": "text" + }, + { + "code": "var myCustomStorage = {\n init : function(endpoint) {\n this.endpoint = endpoint;\n },\n save : function(data, callback) {\n localStorage.simplyData = data;\n callback();\n },\n load : function(callback) {\n if (!localStorage.simplyData) {\n localStorage.simplyData = \"{}\";\n }\n callback(localStorage.simplyData);\n },\n connect : function() {\n return true;\n },\n disconnect : function() {\n return true;\n }\n};", + "data-simply-template": "code" + }, + { + "data-simply-template": "text", + "text": "Then you must tell SimplyEdit to use this storage scheme:
" + }, + { + "data-simply-template": "code", + "code": "<script src=\"//cdn.simplyedit.io/1/simply-edit.js\"\n data-simply-storage=\"customStorage\"\n></script>" + }, + { + "data-simply-template": "text", + "text": "Any storage plugin must include the following methods:
init
Called when first initializing the storage scheme with the given endpoint.save
Called when the user presses save.load
Called after initializing and before each save.It may also include these methods:
connect
Called after init and before load. This allows you to show a login prompt for example.disconnect
Called after pressing logout. This allows you to clean up cookies for example.list
Called whenever a file or image browse dialog is updated. List is called with an endpoint URL and a callback method. It should call the callback method with an object containing three arrays: folders, files and images:For anything to be editable in SimplyEdit, it has to be defined as a 'field'. SimplyEdit comes with a list of predefined field types, like most INPUT elements, IMG, A, and a generic field type for all other HTML elements.
A field type defines how content is set and how it is retrieved. It defines a selector that tells SimplyEdit how to recognize the field type, and it defines the behaviour when SimplyEdit is turned on - or switched to editing mode.
If you want to override the default behaviour for a specific type of content, the best way is to create your own custom field type.
" + } + ], + "title": "Introduction" + }, + { + "contents": [ + { + "data-simply-template": "text", + "text": "To register a new field type you need 4 things:
editable
functionAny element in the browsers DOM can be turned into a field. Like the example above, it doesn't have to be editable. Aas long as you can get and set its values, you can use it with SimplyEdit's databinding.
Note that SimplyEdit has default methods you can re-use to make your custom field work more like the default fields in SimplyEdit. You can use these as follows:
" + }, + { + "data-simply-template": "code", + "code": "editor.field.registerType(\n '[data-readonly]', // selector\n function(field) { // getter\n return editor.field.defaultGetter(field, [\"innerHTML\"]);\n },\n function(field, data) { // setter\n editor.field.defaultSetter(field, data);\n },\n function() { // make editable\n // do nothing, this item is readonly\n }\n);" + }, + { + "data-simply-template": "text", + "text": "Or you can just redefine the parts you want to change:
" + }, + { + "data-simply-template": "code", + "code": "editor.field.registerType(\n '[data-readonly]',\n null,\n null,\n function() {\n }\n);" + }, + { + "data-simply-template": "text", + "text": "Note: make sure that the data returned by your getter has the exact same format as the data parameter in your setter! If you don't SimplyEdit won't be able to keep your data and the DOM element in sync, but it will keep trying...
" + } + ], + "title": "Register a custom field type" + } + ] + } + ], + "search-results-count": "", + "search-results": [] + }, + "/simplyview/": { + "meta title": "Reference", + "chapters": [ + { + "title": "Introduction", + "topics": [ + { + "contents": [ + { + "text": "SimplyView is a set of seperate components that allow you to rapidly build web application user interfaces. They are designed to work with modern reactive libraries, like that included in SimplyEdit.
SimplyView seperates structure - HTML - from behaviour - javascript. There is never a need to write HTML inside your javascript code. There is also never a need to write javascript - or any other kind of code- inside your HTML. This strict seperation allows for a much easier workflow between designers and developers.
This seperation also makes it possible, even easy, to re-use and upgrade existing web applications. There is no need to rewrite everthing from scratch. SimplyView works well with jQuery. In rare cases you can use the simply.activate
component to make sure your legacy javascript can react to changes in the HTML structure.
simply.app provides a simple starting point to build web applications:
var myApp = simply.app({\n routes: {
'/:section/': function(params) { ... }\n },
commands: { ... },
actions: { ... },
container: document.getElementById('myApp'),
view: {\n myVariable: 'foo'
}
});
" + }, + { + "data-simply-template": "text", + "text": "It combines simply.route, simply.command, simply.action and simply.view into a single application wrapper.
" + } + ], + "title": "Overview" + } + ] + }, + { + "topics": [ + { + "contents": [ + { + "data-simply-template": "text", + "text": "simply.view provides a simple interface to use the databinding from SimplyEdit in a web application:
var myView = {
foo: 'bar'\n};
simply.view(myApp, myView);
" + }, + { + "data-simply-template": "text", + "text": "But generally you won't use this directly, but through simply.app:
" + }, + { + "data-simply-template": "code", + "code": "var counterApp = simply.app({\n view: {\n counter: 1
}
});
" + }, + { + "data-simply-template": "text", + "text": "Any data-simply-field
you define in your apps HTML is automatically bound to the corresponding entry in the view.
A simple example - an app that can count up and down:
" + }, + { + "data-simply-template": "code", + "code": "<div id=\"counter\">\n <input type=\"text\" data-simply-field=\"counter\">\n <button data-simply-command=\"add1\">+</button>\n <button data-simply-command=\"sub1\">-</button>\n</div>
" + }, + { + "data-simply-template": "code", + "code": "var counterApp = simply.app({
container: document.getElementById('counter'),
commands: {\n add1: function() { this.app.view.counter++; },
sub1: function() { this.app.view.counter--; }
},
view: {\n counter: 0
}
};
" + } + ] + } + ], + "title": "simply.view" + }, + { + "topics": [ + { + "contents": [ + { + "data-simply-template": "text", + "text": "simply.route is a simple url routing component. It will listen to URL changes and match them against the routes you provide. If a match is found, it will call the matching function and update the address bar without reloading.
simply.route will run the first matching route handler it finds, in the order in which they were registered.
" + } + ], + "title": "Overview" + }, + { + "title": "simply.route.load", + "contents": [ + { + "data-simply-template": "code", + "code": "simply.route.load({
'/:section/:*': function(params) {
loadSection(params.section, params.remainder);\n },
'/': function() {\n loadHome();\n }\n
This allows you to trigger a route. You can also provide extra parameters for the route handler:
" + }, + { + "data-simply-template": "code", + "code": "simply.route.match(path, { foo: 'bar' });" + } + ] + }, + { + "title": "simply.route.goto", + "contents": [ + { + "data-simply-template": "text", + "text": "Updates the browsers address bar and matches the path.
" + }, + { + "data-simply-template": "code", + "code": "simply.route.goto(path);" + } + ] + }, + { + "title": "simply.route.has", + "contents": [ + { + "data-simply-template": "text", + "text": "Returns true if the route is registered.
" + }, + { + "data-simply-template": "code", + "code": "if (simply.route.has(path)) { ... }" + } + ] + } + ], + "title": "simply.route" + }, + { + "topics": [ + { + "contents": [ + { + "data-simply-template": "text", + "text": "simply.command provides a way to tie behaviour (javascript code) to HTML elements.
" + }, + { + "data-simply-template": "code", + "code": "<button data-simply-command=\"doSomething\">does something</button>" + }, + { + "data-simply-template": "text", + "text": "Commands can be set on any HTML element, but the behaviour differs based on the element type:
BUTTON
, A
Command triggers on click. Value is copied from the data-simply-value attribute.INPUT
, TEXTAREA
, SELECT
Command triggers on change. Value is copied from the input value.FORM
Command triggers on submit. Value is the set of form values.*
If a command is triggered, the default event handler is cancelled. So links aren't followed, forms aren't submitted, etc.
" + }, + { + "data-simply-template": "text", + "text": "Initialize the commands like this:
" + }, + { + "data-simply-template": "code", + "code": "var commands = simply.command(myApp, {\n myCommand: function(el, value) {
doSomething(value);\n }\n});
" + }, + { + "data-simply-template": "text", + "text": "For basic applications, commands are sufficient. But once your application gets more complex it pays to limit the code in commands to just the parts that tie into the HTML structure of your application. So searching the DOM, getting attribute values, etc. Once that is done, you should call an internal function that doesn't know anything about the exact HTML structure. simply.action is purpose build to be used in that way. The Todo example shows how you can use this.
Each command function runs with the commands object returned from simply.command as its scope. The action method is a useful shortcut to app.actions:
", + "data-simply-template": "text" + }, + { + "data-simply-template": "code", + "code": "var myApp = simply.app({\n commands: {\n addTodo: function(form, values) {\n form.elements.todo.value = '';\n this.action.call('addTodo', values.todo);\n }
},
actions: {\n addTodo: function(todo) {\n this.app.view.todos.push(todo);\n }\n }\n});
" + }, + { + "data-simply-template": "text", + "text": "The same thing can also be accomplished like this:
" + }, + { + "data-simply-template": "code", + "code": "this.app.actions.addTodo(values.todo);" + } + ] + }, + { + "title": "commands.call", + "contents": [ + { + "text": "Allows you to call a command directly:
", + "data-simply-template": "text" + }, + { + "data-simply-template": "code", + "code": "myApp.commands.call('addTodo', el, value);" + } + ] + }, + { + "title": "commands.appendHandler", + "contents": [ + { + "data-simply-template": "text", + "text": "Adds a command handler on top of the existing ones, so it gets matched first.
" + }, + { + "data-simply-template": "code", + "code": "myApp.commands.appendHandler({\n match: 'input[type=\"radio\"]',
check: function(el, evt) {\n return (evt.type=='change');\n },
get: function(el) {\n return el.dataset.simplyValue || el.value;\n }\n});
" + }, + { + "data-simply-template": "text", + "text": "Handler properties:
Adds a command handler, just like appendHandler. But it adds it first in the list, so it will be matched last. This way you can add handlers with a more generic CSS selector and append more specific handlers.
" + } + ] + } + ], + "title": "simply.command" + }, + { + "topics": [ + { + "title": "Overview", + "contents": [ + { + "data-simply-template": "text", + "text": "Actions are a standardized way to define a kind of API for your user interface. They are meant to be used together with routes and commands. In this case the routes and commands are tightly bound to your URL structure and your HTML structure respectively. Actions should be decoupled from those. An action should just be a method that updates the application state. The parameters for an action should be the logical parameters for that update.
" + }, + { + "data-simply-template": "code", + "code": "var myApp = simply.app({\n commands: {\n addTodo: function(form, values) {\n form.elements.todo.value = '';\n this.app.actions.addTodo(values.todo);\n }
},
actions: {\n addTodo: function(todo) {\n this.app.view.todos.push(todo);\n }\n }\n});
" + }, + { + "data-simply-template": "text", + "text": "By structuring your application in this way, it is easy to add different user interface modes which accomplish the same action. So you can create a route as well as a command, that both trigger the same action. Or later you can add keyboard shortcuts or gestures, without having to copy the logic of your action.
" + }, + { + "data-simply-template": "text", + "text": "You can add actions later by just defining them in the actions object:
" + }, + { + "data-simply-template": "code", + "code": "myApp.actions.anotherAction = function(...arguments) {\n ...\n};
" + } + ] + } + ], + "title": "simply.action" + }, + { + "topics": [ + { + "title": "Overview", + "contents": [ + { + "data-simply-template": "text", + "text": "simply.collect allows you to create auto updating forms, just by adding a few attributes to the form and its elements:
" + }, + { + "data-simply-template": "code", + "code": "function getAddress(elements) {
if (elements.zipcode.value && elements.housenr.value) {\n zipcodeAPI\n .getAddress(elements.zipcode.value,elements.country.value)
.then(function(address) {\n elements.street.value = address.street;
elements.city.value = address.city;\n }\n }\n}
simply.collect.addListener('address', getAddress);
<form>\n <div data-simply-collect=\"address\">\n <label>\n Zipcode: <input name=\"zipcode\" data-simply-element=\"zipcode\">\n </label>\n <label>\n House NR: <input name=\"housenumber\" data-simply-element=\"housenr\">\n </label>\n <label>\n Street: <input name=\"street\" data-simply-element=\"street\">\n </label>\n <label>\n City: <input name=\"city\" data-simply-element=\"city\">\n </label>\n </div>\n</form>
" + }, + { + "data-simply-template": "text", + "text": "The listener will get called whenever any of the elements changes. You can add as many forms and as many container elements with data-simply-collect
as you want.
Add a collect listener. See the code above in the overview.
" + } + ] + }, + { + "title": "simply.collect.removeListener", + "contents": [ + { + "data-simply-template": "text", + "text": "Removes a previously added listener. You must call removeListener with the exact same name and function as used in addListener:
" + }, + { + "data-simply-template": "code", + "code": "simply.collect.removeListener('address', getAddress);" + } + ] + }, + { + "title": "simply.collect.update", + "contents": [ + { + "data-simply-template": "text", + "text": "simply.collect only listens for the change event. So if you update an input elements value through javascript, the collect listeners won't trigger, unless you also trigger the change event. simply.collect.update does this for you:
" + }, + { + "data-simply-template": "code", + "code": "simply.collect.update(form.elements.zipcode, newZipcode);" + } + ] + } + ], + "title": "simply.collect" + }, + { + "topics": [ + { + "title": "Overview", + "contents": [ + { + "data-simply-template": "text", + "text": "simply.activate is a component to automatically initialize HTML elements with javascript as they appear in the DOM.
" + }, + { + "data-simply-template": "code", + "code": "simply.activate.addListener('autosize',function(el) {
$.autosize(el);\n});
" + }, + { + "data-simply-template": "code", + "code": "<textarea data-simply-activate=\"autosize\"></textarea>" + }, + { + "data-simply-template": "text", + "text": "Now you can use any 'legacy' component, in this case a jQuery textarea resizer, that needs to initialize HTML elements.
" + } + ] + } + ], + "title": "simply.activate" + }, + { + "topics": [ + { + "title": "Overview", + "contents": [ + { + "data-simply-template": "text", + "text": "simply.include is a component that allows you to include external HTML - with CSS and javascript - in the current HTML document. You will need to make sure you don't overwrite global variables, the javascript and css get applied to the whole document.
This component makes it easy to create microfrontends for microservices, without forcing you to use a specific framework or technology.
Start by including the simply.include script, or simply.everything.js:
" + }, + { + "data-simply-template": "code", + "code": "<script src=\"js/simply.everything.js\"></script>" + }, + { + "data-simply-template": "text", + "text": "Then add a simply-include link at the exact spot where you want to include a widget or application or just a piece of HTML:
" + }, + { + "data-simply-template": "code", + "code": "<link rel=\"simply-include\" href=\"/simplyview/widgets/my-widget/index.html\"></link>" + }, + { + "data-simply-template": "text", + "text": "Your widget may contain any HTML, CSS and javascript you like, except it shouldn't contain a HEAD. So a widget might look like this:
<script src=\"/simplyview/js/simply.everything.js\"></script>
<link rel=\"simply-include-once\" href=\"/simplyview/common/head.html\">
<link rel=\"simply-include-once\" href=\"/simplyview/common/menu.html\">
<link rel=\"stylesheet\" href=\"/simplyview/widgets/my-widget/style.css\">
<div class=\"my-widget\">\n ....
</div>
" + }, + { + "data-simply-template": "text", + "text": "\u200bThe widget includes some common HTML, but only if it wasn't included before. Assuming your pages all include the common head and menu, the widget will skip this if the widget is included in a page. However you can also call the widget as a normal page. In that case the common head and menu will be included and the widget will decorate itself with the default styling and menu.
simply.include will automatically detect <link rel=\"simply-include(-once)\">
links in the DOM, no matter when and how they appear, and replace them with the HTML fetched from the linked href.
simply.include is meant to include HTML with CSS and javascript into an existing document. So you must take care that whatever you include is what you meant to include. If you allow user input, you must make sure that it doesn't have <link rel=\"simply-include(-once)\">
tags. Or that if they do, they won't get executed.
As a baseline, always clean user input of any offending tags, or even better: clean it of all HTML. If that can't be done, make sure you use a whitelist of acceptable tags. Finally as a catchall, use Content-Security-Policy headers to only allow script execution of whitelisted URL's. Don't allow inline scripts or you will still be open to Cross Site Scripting attacks (XSS).
This component is still experimental, so use with care. simply.observe listens for changes in objects and calls callback functions when changes happen. This can be used to build reactive components, that automatically update and do stuff whenever data changes.
A very simple example shows a JSON encoded version of an object in a PRE element. It updates to reflect any change in the object:
" + }, + { + "data-simply-template": "code", + "code": "<pre id=\"json\"></pre>\n<script>
var root = {
observed: {
foo: 'bar',
list: [ 'a','b','c' ],
nested: {\n structures: 'work'
}\n }\n };
simply.observe(root, 'observed', function(value) {\n document.getElementById('json').innerHTML = JSON.stringify(value, null, 4);
});\n</script>
" + }, + { + "data-simply-template": "text", + "text": "simply.observe currently uses javascripts setter and getter functionality to listen for changes. This has the benefit of broad browser support, so IE from at least version 9 is supported. However it also means that some change operations are not supported:
delete foo.bar
is not supported, use foo.bar = null insteadThe simply.observe function will only add setters and getters where needed, so you can use as large a dataset as you like without significant performance impact. Just remember that for simply.observe to work properly, it will add setters and getters for all the parents and all the children of the path you pass as the second parameter.
" + }, + { + "data-simply-template": "code", + "code": "simply.observe(root, 'observed.nested', console.log)" + }, + { + "data-simply-template": "text", + "text": "This will add setters and getters on root
, root.observed
, root.observed.nested
and root.observed.nested.structures
, but not on root.observed.foo
or root.observed.list
.
It is important that the root itself is not reassigned. All the information about observers is tied to that object. You can however change any of its children in any way you like. In the above case, where an observer is linked to the root.observed.nested
property, you can reassign root.observed
or make it null
. If the value is no longer available, the listener will be called with the value set to undefined
. If the propert exists, the value will be its current value.
The counter app is an example to introduce the basic concepts. Here is the HTML:
" + }, + { + "data-simply-template": "code", + "code": "<div id=\"counterApp\"> | \n
<input type=\"text\" data-simply-field=\"counter\"> | \n
<button data-simply-command=\"add1\">+</button> | \n
<button data-simply-command=\"sub1\">-</button> | \n
<div>Counter is now: <span data-simply-field=\"counter\"></span></div> | \n
It uses two components of SimplyView and SimplyEdit, through data-simply-command
and data-simply-field
.
data-simply-command is handled by simply.command. Both commands are defined on buttons, so they will trigger when the button is pressed. The javascript code tied to these commands is defined with the simply.app component:
" + }, + { + "data-simply-template": "code", + "code": "var counterApp = simply.app({ | \n
container: document.getElementById('counterApp'), | \n
commands: { | \n
add1: function() { | \n
counterApp.view.counter++; | \n
}, | \n
sub1: function() { | \n
counterApp.view.counter--; | \n
} | \n
}, | \n
view: { | \n
counter: 1 | \n
} | \n
simply.app
is a wrapper that combines a number of components with a single configuration parameter. The commands section here is passed on to simply.command
.
When you press the button with data-simply-command=\"add1\"
, the command handler for this app is triggered and searches its commands for 'add1'. It then calls this javascript function and it will increase counterApp.view.counter
.
This is where the second component, which uses data-simply-field
, comes in. The counterApp.view
object is automatically tied to SimplyEdit, by simply.app
. So whenever you update a variable inside counterApp.view
, SimplyEdit will also update any HTML element which references the same variable. In this case counterApp.view.counter
is tied to the input element with data-simply-field=\"counter\"
.
SimplyEdit also does the reverse, whenever you change the input value, SimplyEdit will also change the counterApp.view.counter
value. This is called two-way databinding.
Two-way databinding is not instantanous, so whenever you change a value in javascript or in the DOM, it will take a short while for SimplyEdit to update the other side as well. There are a number of events that will tell you when the values are in sync again.
" + } + ] + }, + { + "title": "Todo", + "contents": [ + { + "data-simply-template": "text", + "text": "The TodoMVC application is a standard web application implemented in many different javascript frameworks. We've build one using SimplyEdit and SimplyView, which you can find at https://todomvc.simplyedit.io/.
The code is on github at https://github.com/simplyedit/todomvc. The Readme explains how it is build.
" + } + ] + }, + { + "title": "Hackernews PWA", + "contents": [ + { + "data-simply-template": "text", + "text": "Just like the TodoMVC application, the Hackernews PWA is also a standard web application implemented in many frameworks. You can find the SimplyEdit/SimplyView version at https://hnpwa.simplyedit.io/. The code is at https://github.com/simplyedit/hnpwa and the Readme explains how it was built.
" + } + ] + } + ] + } + ], + "search-results-count": "", + "search-results": [], + "title": "SimplyView Reference", + "mobile title": { + "href": "#", + "class": null, + "alt": null, + "title": null, + "innerHTML": "SimplyView Reference", + "name": null + } + } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..9b505c2 --- /dev/null +++ b/index.html @@ -0,0 +1,377 @@ + + + + + +Text goes here!
Text goes here!