Permalink
Browse files

New contenteditable editor added.

  • Loading branch information...
1 parent 2d3e55a commit 94c79118f837483e6a869f1bac20fe3bf2b0797c Ian Mckay committed Jul 31, 2011
Showing with 1,287 additions and 0 deletions.
  1. +1 −0 README.md
  2. +104 −0 css/ui-editor.css
  3. +181 −0 examples/editor.html
  4. +1,001 −0 js/ui-editor.js
View
@@ -17,6 +17,7 @@ Included :
* Context Menu
* Window Manager
* Tabs
+* Editor - This is an experimental contenteditable rich text editor, and is designed only for the latest browsers.
In the pipeline :
-----------------
View
@@ -0,0 +1,104 @@
+/**********************
+Editor
+**********************/
+.ep-editor { background-color: #D3E9FE; width: 400px; opacity: 0.9; filter:alpha(opacity=90); background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#D3E9FE), to(#AECFF0)); background-image: -moz-linear-gradient(top, #D3E9FE, #AECFF0);
+ -webkit-box-shadow:0 0 5px Black; -moz-box-shadow: 0 0 5px Black; box-shadow:0 0 5px Black; }
+.ep-editor, .ep-editor .inner { -moz-border-radius:4px 4px 4px 4px; -webkit-border-radius: 4px; border-radius: 4px; border: solid 1px Black; }
+.ep-editor .inner { border-color: White;}
+.ep-editor .content { padding: 5px; position: relative; height: 72px; }
+.ep-editor button { cursor: pointer; }
+
+.ep-editor .buttons, .ep-editor .dialog { position: absolute; line-height:0.8; width: 365px; border: solid 1px #5C6C7A; background-color: #E7F1FB; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F5FAFF), to(#DCE7F6)); background-image: -moz-linear-gradient(top, #F5FAFF, #DCE7F6); }
+.ep-editor .buttons { padding: 5px 0; }
+.ep-editor .buttons .buttons-inner { -moz-border-radius:0; -webkit-border-radius: 0; border-radius: 0; overflow: hidden; padding: 0 5px; }
+.ep-editor .buttons .group { display: inline-block; border-right: 1px solid #AECFF0; border-left: 1px solid White; }
+.ep-editor .buttons .group.first { border-left-width: 0; }
+.ep-editor .buttons .group.last { border-right-width: 0; }
+.ep-editor .button { float: left; cursor: pointer; padding:1px; height: 28px; }
+.ep-editor .button, .ep-editor .button .button-inner { -moz-border-radius:2px 2px 2px 2px; -webkit-border-radius: 2px; border-radius: 2px; }
+.ep-editor .button.hover { border: solid 1px #AABCD5; padding: 0; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F5FAFF), to(#C3D5EA)); background-image: -moz-linear-gradient(top, #F5FAFF, #C3D5EA); }
+.ep-editor .button .button-inner { border-color: White; display: inline-block; border: none; background-color: transparent; padding: 5px 3px;}
+.ep-editor .button .icon { width: 16px; height: 16px; background-repeat: no-repeat; }
+.ep-editor .move, .ep-editor .pin { float: right; width: 16px; height: 16px; cursor:pointer; }
+.ep-editor .move { background-image: url('../images/arrow-move.png'); cursor:move;}
+.ep-editor .pin { background-image: url('../images/pin.png');}
+.ep-editor .sidebar { margin-top: 3px; }
+.ep-editor .button .bold { background-image: url('../images/edit-bold.png'); }
+.ep-editor .button .italic { background-image: url('../images/edit-italic.png'); }
+.ep-editor .button .underline { background-image: url('../images/edit-underline.png'); }
+.ep-editor .button .list{ background-image: url('../images/edit-list.png'); }
+.ep-editor .button .orderedlist { background-image: url('../images/edit-list-order.png'); }
+.ep-editor .button .heading { background-image: url('../images/edit-heading.png'); }
+.ep-editor .button .link { background-image: url('../images/globe--arrow.png'); }
+.ep-editor .button .subscript { background-image: url('../images/edit-subscript.png'); }
+.ep-editor .button .superscript { background-image: url('../images/edit-superscript.png'); }
+.ep-editor .button .image { background-image: url('../images/picture--plus.png'); }
+.ep-editor .button .code { background-image: url('../images/edit-code.png'); }
+.ep-editor .button .align-left { background-image: url('../images/edit-alignment.png'); }
+.ep-editor .button .align-center { background-image: url('../images/edit-alignment-center.png'); }
+.ep-editor .button .align-right { background-image: url('../images/edit-alignment-right.png'); }
+.ep-editor .button .cut { background-image: url('../images/scissors-blue.png'); }
+.ep-editor .button .copy { background-image: url('../images/document-copy.png'); }
+.ep-editor .button .paste { background-image: url('../images/clipboard-paste.png'); }
+.ep-editor .button .blockquote { background-image: url('../images/balloon-quotation.png'); }
+.ep-editor .button .paragraph { background-image: url('../images/text.png'); }
+.ep-editor .button .html { background-image: url('../images/html.png'); }
+.ep-editor .button .cancel { background-image: url('../images/cross-button.png'); }
+.ep-editor .button .confirm { background-image: url('../images/tick-button.png'); }
+
+
+.ep-editor .button .menu { display: none; position: absolute; border: solid 1px #AABCD5; background-color: #E7F1FB; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F5FAFF), to(#DCE7F6)); background-image: -moz-linear-gradient(top, #F5FAFF, #DCE7F6); }
+.ep-editor .button .menu .button { font-size: 0.9em; }
+.ep-editor .button .menu .icon { width: auto; min-width: 14px; }
+.ep-editor .button .menu li { padding: 0; }
+.ep-editor .button .menu li.hover { background-color: #C3D5EA; }
+.ep-editor .button.hover .menu { display: inline-block; }
+
+
+.ep-editor .dialog input { margin: 10px 0 0 10px; float: left; font-size: 0.8em; width: 310px; border: 1px solid #AECFF0; padding: 0; }
+.ep-editor .dialog input.short { width: 149px; margin-bottom: 10px; }
+.ep-editor .dialog label { display: inline-block; font-size: 0.8em; margin-left: 10px; margin-top: 10px; padding: 3px 0; }
+.ep-editor .dialog label .checkbox { width: 10px; margin: 0 5px 0 0; }
+.ep-editor .dialog-buttons { float: right; width: 30px; padding: 5px; }
+
+/*image picker */
+.ui-imagepicker { width: 100%; height: 100%; }
+.ui-imagepicker .image-details { padding: 20px; position: relative; }
+.ui-imagepicker .image-details button { bottom: 20px; position: absolute; right: 20px; }
+.ui-imagepicker .image-list { padding: 20px 20px 0; height: 227px; position: relative; }
+.ui-imagepicker .image-panel { padding:5px; overflow-x: none; overflow-y: scroll; border: 1px solid #9E9E9E; height: 100%; box-shadow: 0 0 2px #AECFF0 inset; }
+
+.ui-imagepicker .ui-thumb { display: inline-block; margin: 3px; cursor: pointer; border: 1px solid White; -moz-border-radius:3px; -webkit-border-radius: 3px; border-radius: 3px; }
+.ui-imagepicker .ui-thumb.hover { border-color: #B8D6FB; }
+.ui-imagepicker .ui-thumb.selected { border-color: #7DA2CE; }
+.ui-imagepicker .thumb-inner { position: relative; border: 1px solid White; background-color: White; -moz-border-radius:3px; -webkit-border-radius: 3px; border-radius: 3px; }
+.ui-imagepicker .ui-thumb.hover .thumb-inner { border-color: #FCFCFE; background-color: #F3F7FD; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#F9FBFD), to(#EBF3FD)); background-image: -moz-linear-gradient(top, #F9FBFD, #EBF3FD); }
+.ui-imagepicker .ui-thumb.selected .thumb-inner { border-color: #EAF3FD; background-color: #CFE3FC; background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#DCEAFC), to(#C1DCFC)); background-image: -moz-linear-gradient(top, #DCEAFC, #C1DCFC); }
+.ui-imagepicker .thumb-frame { position: absolute; overflow: hidden; box-shadow: 1px 1px 3px #000000; top: 22%; left:5%; }
+
+.ui-imagepicker .loading-icon { background: url("../images/ajax-loader.gif") no-repeat scroll 50% 50% transparent; height: 50px; position: absolute; right: 110px; top: 290px; width: 50px; display: none; }
+.ui-imagepicker .loading .loading-icon { display: block; }
+
+/* code editor */
+.ui-codeeditor { width: 100%; height: 100%; }
+.ui-codeeditor .code-details { padding: 30px 20px 20px; position: relative; border-top: 1px solid #DDDDDD; }
+.ui-codeeditor .code-details button { bottom: 20px; position: absolute; right: 20px; }
+
+/* html editor */
+.ui-htmleditor { width: 100%; height: 100%; }
+.ui-htmleditor .html-view textarea { width: 730px; height: 355px; }
+.ui-htmleditor .html-details { padding: 20px; position: relative; border-top: 1px solid #DDDDDD; height: 50px; }
+.ui-htmleditor .html-details button { bottom: 20px; position: absolute; right: 20px; }
+
+/* link dialog */
+.ui-linkdialog { width: 100%; height: 100%; }
+.ui-linkdialog .link-details { padding: 20px; position: relative; }
+.ui-linkdialog .link-details button { bottom: 20px; position: absolute; right: 20px; }
+
+.ui-field.inline { display: inline-block; margin-right: 20px; }
+.ui-field label { color: #333333; display: block; font-size: 13px; padding: 0.8em 0; }
+.ui-field input.medium { width: 250px; }
+.ui-field input.long { width: 535px; }
+.ui-field input, .ui-field select, .ui-field textarea { border: 1px solid #9E9E9E; color: #333333;font-family: inherit;font-size: inherit;line-height: 1.4375; margin: 0; padding: 3px 5px; width: 15em;}
+.ui-field input[type='checkbox'] { width: 20px; border: none;}
+.ui-button { border: 1px solid #5F6F7D; cursor: pointer; float: right; margin-left: 10px; padding: 8px 25px; }
View
@@ -0,0 +1,181 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html>
+<head>
+ <title>Editor Demo</title>
+ <link rel="stylesheet" href="css/reset.css" type="text/css"/>
+ <link rel="stylesheet" href="css/style.css" type="text/css"/>
+
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script>
+
+ <!-- Dependencies -->
+ <script type="text/javascript" src="../lib/jquery.tmpl.js"></script>
+ <script type="text/javascript" src="../lib/knockout-1.2.1.min.js"></script>
+ <script type="text/javascript" src="../lib/rangy-core.js"></script>
+ <script type="text/javascript" src="../lib/rangy-selectionsaverestore.js"></script>
+ <script type="text/javascript" src="../lib/rangy-cssclassapplier.js"></script>
+
+ <!-- Add as many modes for codemirror as you need -->
+ <script type="text/javascript" src="../lib/codemirror/codemirror.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/clike/clike.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/css/css.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/diff/diff.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/haskell/haskell.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/htmlmixed/htmlmixed.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/javascript/javascript.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/lua/lua.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/php/php.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/plsql/plsql.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/python/python.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/rst/rst.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/scheme/scheme.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/python/python.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/smalltalk/smalltalk.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/sparql/sparql.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/stex/stex.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/xml/xml.js"></script>
+ <script type="text/javascript" src="../lib/codemirror/yaml/yaml.js"></script>
+ <link rel="stylesheet" href="../lib/codemirror/codemirror.css" type="text/css"/>
+ <link rel="stylesheet" href="../lib/codemirror/default.css" type="text/css"/>
+
+ <link rel="stylesheet" href="../css/ui-editor.css" type="text/css"/>
+ <link rel="stylesheet" href="../css/ui-window.css" type="text/css"/>
+
+ <script type="text/javascript" src="../js/ui-util.js"></script>
+ <script type="text/javascript" src="../js/ui-editor.js"></script>
+
+ <script src="../lib/beautify-html.js"></script>
+ <script type="text/javascript">
+ var the = {
+ beautify_in_progress: false
+ };
+ function beautify(source) {
+ if (the.beautify_in_progress) return;
+
+ the.beautify_in_progress = true;
+
+ var indent_size = 4;
+ var indent_char = indent_size == 1 ? '\t' : ' ';
+ var preserve_newlines = true;
+ var keep_array_indentation = false;
+ var brace_style = 'collapse';
+
+ var comment_mark = '<-' + '-';
+ var opts = {
+ indent_size: indent_size,
+ indent_char: indent_char,
+ preserve_newlines:preserve_newlines,
+ brace_style: brace_style,
+ keep_array_indentation:keep_array_indentation,
+ space_after_anon_function:true};
+
+
+ var v = style_html(source, opts)
+ the.beautify_in_progress = false;
+ return v;
+ }
+ </script>
+ <style type="text/css">
+ #demo { overflow: hidden; }
+ #result { height: 900px; width: 880px; }
+ pre { white-space: pre-wrap; }
+ .demo ul { list-style-type:disc; margin-left: 20px; }
+ .demo ol { list-style-type:decimal; margin-left: 20px; }
+ pre.code { padding: 10px 20px; background-color: #EEEEEE; font-family: monospace; margin-bottom: 20px; }
+ u { text-decoration: underline; }
+ b { font-weight: bold; }
+ sup {font-size:xx-small; vertical-align:super;}
+ sub {font-size:xx-small; vertical-align:bottom;}
+ blockquote { margin: 30px; border : 1px solid #000; padding: 20px; font-family: Georgia, serif; font-size: 1.1em; background-color: #DDDDDD; }
+ </style>
+</head>
+<body>
+ <div class="central-column">
+ <h1>Editor</h1>
+ <p>This is an experiemental rich text editor that uses contenteditable to transform any html element into an editable area. Contenteditable is slowly being standardised but there are still many inconsistencies across the browser types.</p>
+ <p>A single instance of the editor is rendered per page and the editor is positioned when you first click on an editable area.</p>
+ <p>A focus for the editor was to allow easy insertion of code samples for writing blog posts etc. For this the editor uses <a href="http://codemirror.net/">codemirror</a> by Marijn Haverbeke.
+ It also uses <a href="http://code.google.com/p/rangy/">rangy</a> by Tim Down to ensure cross browser selection works.</p>
+ <p>This is fairly basic as it stands but it works reasonably well. I hope to extend it as bugs are found and the standards converge.</p>
+ <h2>Demo (all text below here is editable)</h2>
+ <div class="demo">
+ <div id="editableArea1" data-bind="editable: editorSettings, output: updateOutput">
+ <h1>Heading 1</h1>
+ <h2>Heading 2</h2>
+ <blockquote>
+ This is an example blockquote
+ </blockquote>
+ <p>
+ An example paragraph, <u>with an underlined portion</u>. Experiment with applying different styles and check the html generated at the bottom of this page.
+ </p>
+ <p>
+ Highlight this and insert an image here
+ </p>
+ <p>
+ You can insert/edit <a href="http://knockoutjs.com/">links</a> by selecting text and clicking the link button
+ </p>
+ <ol>
+ <li>List item 1</li>
+ <li>List item 2</li>
+ <li>List item 3</li>
+ </ol>
+ <h3>Heading 3</h3>
+ <p>
+ Below is an example of a code block. This is not editable inline, try and highlight the code and click the code button to edit (there are known issues with chrome for this). The resultant markup uses an rss friendly pre element
+ to retain formatting. It also is tagged with the language mode on a data-mode attribute for highlighting when loaded in a none writable mode.
+ </p>
+ <pre class="code" data-mode="javascript" contenteditable="false">
+var someFunction = function() {
+ var boo = false;
+}</pre>
+ <ul>
+ <li>List item 1</li>
+ <li>List item 2</li>
+ <li>List item 3</li>
+ </ul>
+ </div>
+ </div>
+ <h3>Html Generated</h3>
+ <p>The below has been processed by <a href="https://github.com/einars/js-beautify">beautify js</a> to make it easier to read. The real markup can be seen by clicking the html button on the editor.</p>
+ <textarea id="result"></textarea>
+ <div class="footer">
+ <ul>
+ <li>License: <a href="http://www.opensource.org/licenses/mit-license.php">MIT http://www.opensource.org/licenses/mit-license.php</a></li>
+ <li>Project Home: <a href="https://github.com/madcapnmckay/Knockout-UI">https://github.com/madcapnmckay/Knockout-UI</a></li>
+ </ul>
+ </div>
+ </div>
+ <script type="text/javascript">
+ var updateOutput = function(contents) {
+ $('#result').val(beautify(contents));
+ }
+
+ $(function () {
+ var myModel = {};
+
+ myModel.editorSettings = new ko.editable.settings({ imagePickerHandler: function(onSuccess) {
+ // we could call a service here, for now lets fake an ajax call
+ var results = [
+ { src: "http://lol.ianloic.com/image-cache/2ff/2ff0236b5a3b9f45414457db219803a9.jpg", title: "some title 1", altText: "some alt text 1" },
+ { src: "http://lol.ianloic.com/image-cache/4e1/4e104c20507d9ac354193e66bdc32124.jpg", title: "some title 2", altText: "some alt text 2" },
+ { src: "http://lol.ianloic.com/image-cache/de0/de0fc43880d525e72d013638dbbe5e6b.jpg", title: "some title 3", altText: "some alt text 3" },
+ { src: "http://lol.ianloic.com/image-cache/b0b/b0bd4b663f7dbf0f70a7400ab97b2ce1.jpg", title: "some title 4", altText: "some alt text 4" },
+ { src: "http://lol.ianloic.com/image-cache/c21/c21de1baa6245232699d9d29d2dcbb6b.jpg", title: "some title 5", altText: "some alt text 5" },
+ { src: "http://lol.ianloic.com/image-cache/3c8/3c84a83ad0844644bab70fe24b525a3d.jpg", title: "some title 6", altText: "some alt text 6" },
+ { src: "http://lol.ianloic.com/image-cache/1a1/1a1b26c4def09bd9e09666a51ca4cdfe.jpg", title: "some title 7", altText: "some alt text 7" },
+ { src: "http://lol.ianloic.com/image-cache/407/40786684125659748cc1c92fb5bfc15f.jpg", title: "some title 8", altText: "some alt text 8" },
+ { src: "http://lol.ianloic.com/image-cache/05f/05ff574023935efded87d574234af4eb.jpg", title: "some title 9", altText: "some alt text 9" },
+ { src: "http://lol.ianloic.com/image-cache/af7/af7dbe51db361ff667188fc42bd54d13.jpg", title: "some title 10", altText: "some alt text 10" },
+ { src: "http://lol.ianloic.com/image-cache/4e4/4e46239f5ca78b9fed5f040a5f94b922.jpg", title: "some title 11", altText: "some alt text 11" },
+ { src: "http://lol.ianloic.com/image-cache/7d3/7d387414ff627bd6289129073e9b83aa.jpg", title: "some title 12", altText: "some alt text 12" },
+ { src: "http://lol.ianloic.com/image-cache/2b0/2b0dbaeba12f5abcc4158719411dc41d.jpg", title: "some title 13", altText: "some alt text 13" },
+ { src: "http://lol.ianloic.com/image-cache/edf/edfb72bf470555b200b6306676ef8765.jpg", title: "some title 14", altText: "some alt text 14" }
+ ];
+ onSuccess(results);
+ }});
+
+ ko.applyBindings(myModel);
+ });
+ </script>
+</body>
+</html>
Oops, something went wrong.

0 comments on commit 94c7911

Please sign in to comment.