Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added specs for editor closing

fixed some regression bugs
ignore empty select option
cleanup TODO
fixed some specs in firefox
replaced getParagraphs with the more general getSelection method in wysiwyg
update gems
join strips comments and logs
  • Loading branch information...
commit bd9363acdb16655ad4d229d8b62a800a55b041dd 1 parent 0c62624
@johnny authored
View
33 Gemfile.lock
@@ -1,17 +1,17 @@
GEM
remote: http://rubygems.org/
specs:
- activesupport (3.1.1)
+ activesupport (3.1.3)
multi_json (~> 1.0)
addressable (2.2.6)
- childprocess (0.2.2)
+ childprocess (0.2.3)
ffi (~> 1.0.6)
chunky_png (1.2.5)
closure-compiler (1.1.4)
coffee-script (2.2.0)
coffee-script-source
execjs
- coffee-script-source (1.1.2)
+ coffee-script-source (1.1.3)
compass (0.11.5)
chunky_png (~> 1.2)
fssm (>= 0.2.7)
@@ -22,9 +22,9 @@ GEM
addressable (>= 2.1.1)
eventmachine (>= 0.12.9)
eventmachine (0.12.10)
- execjs (1.2.9)
+ execjs (1.2.11)
multi_json (~> 1.0)
- ffi (1.0.9)
+ ffi (1.0.11)
fssm (0.2.7)
guard (0.6.3)
thor (~> 0.14.6)
@@ -32,18 +32,17 @@ GEM
em-websocket (>= 0.2.0)
guard (>= 0.4.0)
multi_json (~> 1.0.3)
- haml (3.1.3)
+ haml (3.1.4)
hike (1.2.1)
- hpricot (0.8.4)
+ hpricot (0.8.5)
http_router (0.10.2)
rack (>= 1.0.0)
url_mount (~> 0.2.1)
i18n (0.6.0)
- json_pure (1.6.1)
- libv8 (3.3.10.2)
+ libv8 (3.3.10.4)
maruku (0.6.0)
syntax (>= 1.0.0)
- middleman (2.0.13.1)
+ middleman (2.0.14)
coffee-script (~> 2.2.0)
compass (~> 0.11.3)
execjs (~> 1.2.7)
@@ -65,7 +64,7 @@ GEM
uglifier (~> 1.0.0)
middleman-livereload (0.2.1)
guard-livereload (~> 0.3.1)
- multi_json (1.0.3)
+ multi_json (1.0.4)
padrino-core (0.10.5)
activesupport (~> 3.1.0)
http_router (~> 0.10.2)
@@ -88,12 +87,12 @@ GEM
rspec-expectations (2.7.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.7.0)
- rubyzip (0.9.4)
- sass (3.1.10)
- selenium-webdriver (2.10.0)
+ rubyzip (0.9.5)
+ sass (3.1.11)
+ selenium-webdriver (2.14.0)
childprocess (>= 0.2.1)
- ffi (= 1.0.9)
- json_pure
+ ffi (~> 1.0.9)
+ multi_json (~> 1.0.4)
rubyzip
sinatra (1.3.1)
rack (~> 1.3, >= 1.3.4)
@@ -108,7 +107,7 @@ GEM
tilt (~> 1.1, != 1.3.0)
syntax (1.0.0)
temple (0.3.4)
- therubyracer (0.9.8)
+ therubyracer (0.9.9)
libv8 (~> 3.3.10)
thin (1.2.11)
daemons (>= 1.0.9)
View
182 TODO
@@ -1,9 +1,14 @@
-* [35/42] Further improvements
- - [ ] spec closing of editors
- - [ ] should work with external select
+* [1/10] Further improvements
+ - [-] fix specs in Firefox
+ - [ ] general specs
+ - [X] general wysiwyg specs
+ - [X] list specs
+ - [X] config.current error (Border find error)
+ - [ ] fix specs in chrome again
+ - [ ] update docs
- [ ] better editor loading
- [ ] handle multiple init gracefully. Currently it stacks two editors on top of each other
- - [ ] loading from textarea with an unknown mode, that is inside a textarea, should work
+ - [ ] loading from textarea with an unknown mode, that is a select option, should work
- [ ] flexible toolbar, which stays on top
- [ ] wysiwyg
- [ ] checkIfDeleteAll should work with holding a neutral key combined with a destructive action
@@ -18,6 +23,10 @@
- [ ] in list
- [ ] pressing enter on empty list item should remove the list item and add a paragraph
- [ ] in heading
+ - [ ] at the end
+ - [ ] in the middle
+ - [ ] also in textile
+ - [ ] at the beginning of a list should not add a *#
- [ ] spec press shift enter
- [ ] in list
- [ ] spec press entf
@@ -30,173 +39,24 @@
- [ ] double click on bold word should select just the bold tag
- [ ] spec checkIfDeleteAll
- [ ] normal keys
- - [ ] keycombos
+ - [ ] keycombos (most should not delete the selection)
+ - [ ] spec keycombos
+ - [ ] strg-r should work
- [ ] show window in different awesome tab
- [ ] use existing window (not supported in ruby bindings)
- [ ] fire native events (not supported in awesome, try in kde or windows)
- [ ] clean and parse pasted html
- [ ] handle blocktags within lists
- - [X] split up markupEditor.js
- - [X] look how ender handles the extensability
- perhaps (... ME.Mode = Mode;})(ME, jQuery) is an option
- - [X] split it up
- - [X] update docs
- - [X] wysiwyg
- - [X] Firefox: fix checkState for one bold word
- - [X] Firefox: keycombos delete selection
- - [X] expand selection to word boundaries, just as in textile
- - [X] pressing enter on empty list item should remove the list item and add a paragraph
+ - [ ] h1. * item1
+ does not compile right
+ - [X] join should strip log lines (and comments)
- - [X] join lists on backspace/entf between lists
- - [X] Toolbar should work only if there is a range inside the preview
- (also the state checking)
- - [X] handle delete key
- - [X] selecting all and pressing bold should bolden each (part of a) paragraph in turn
- - [X] ignore special keyCodes on deletion
- - [X] on keyup check if the content is still in a valid block tag
- - [X] chrome problems
- - [X] return at the end of a heading
- - [X] backspace into another paragraph
- this will keep the style of the backspaced paragraph with span tags
- - [X] firefox problems
- - [X] selecting all and deleting/overwriting it
- overwriting with normal keys won't work
- - [X] respect the top blockformat on overwriting
- - [X] return at the end of a heading
- - [X] enter in the middle of a heading does not move the rest of the heading down
- - [X] selecting all by hand and deleting it leaves empty tags
- this is a result of the current implementation of checkIfDeletedAll
- - [X] Improve dialog
- - [X] merge tipsy and isValid
- - [X] Better Dialogs (for inspiration see gollum)
- - [X] display errors as tooltips
- - [X] add tooltips
- - [X] reset errors on open
- - [X] enhancedTextfield: type, click clear, type again (no button), click cancel (button appears and button click did not work)
- - [X] style clearButton + autocomplete
- - [X] use errors
- - [X] autocomplete select should trigger change (file bug)
- - [X] support prompts in textfields
- - [X] add a clear button to text fields
- - [X] dialogs should be created on the fly
- - [X] values for the selects should be defined by a method call if functions are defined
- - [X] fields should share the combobox
- - [X] localization
- - [X] fix multiple.html
- - [X] textile: fix align with single caret
- - [X] fix wysiwyg specs. probably an error in initFromHTMLDiv
- - [X] provide support for external mode select
- - [X] basics
- - [X] hide select if it has just one option
- - [X] handle and spec different edgecases
- - [X] toHTML/toText
- - [X] getText or similar
- - [X] loadFromDiv in case mode has no toText/getText
- - [X] Support haml in preview mode
- - [X] basics
- - [X] handle asynchronus update
- - [X] fix spec
- - [X] should block all other actions until mode change is finished
- - [X] should block all other actions if a dialog is open
- - [X] fix enter in lists
- - [X] doesn't add #*
- - [X] at the beginning of the line it should not add tags
- - [X] list trace at the end of a line does not work
- - [X] textileCompiler
- - [X] "* item1":src should compile as a link
- - [X] Decouple mode and editor
- - [X] fix all specs
- - [X] add link error: place cursor at the end of a word and click link -> add uri -> ok -> link is after word
- - [X] remove mode param in textileMode / wysiwygMode
- - [X] holdShift should live on a global object
- - [X] fix selection on link creation. currently it selects the whole paragraph
- - [X] click in blank area should not raise error
- - [X] add close editor
- - [X] basics
- - [X] show only if configured
- - [X] reopen should be possible
- - [X] textile
- - [X] replace this.tag
- - [X] decouple preview and data-modes
- - [X] publish project
- - [X] documentation
- - [X] better static files handling:
- - [X] package files
- - [X] join and compress js files
- - [X] push to github
- - [X] list functionality
- - [X] wysiwyg
- - [X] button click
- - [X] own
- - [X] on
- - [X] off
- - [X] off in the middle should seperate the list
- - [X] align
- - [X] bold/italic
- - [X] conversion to textile should handle linebreaks
- - [X] link
- - [X] image
- - [X] paragraph
- - [X] backspace out of list (also at the beginning of the div) should remove list
- and replace it with a paragraph
- - [X] ensure <br> only inside block tags (this is now handled during conversion.
- this way html import is easier)
- - [X] shift + enter throws error
- - [X] enter in list (by default)
- - [X] fix conversion
- - [X] refactor selection api to mode
- - [X] fix textile compiler
- - [X] textile
- - [X] shift enter in list
- - [X] enter in list
- - [X] button click
- - [X] own
- - [X] align
- - [X] bold/italic
- - [X] link
- - [X] image
- - [X] paragraph (ignore it)
- - [X] create own selenium view template
- - [X] load firebug into selenium window
- - [X] fix selection on end of textfield
- - [X] should not catch strg-r
- - [X] fix joined file
- - [X] generalize spec helpers
- - [X] load editor from any html element
- - [X] optimize hiding and showing. use least possible dom calls
- - [X] dynamically change the toolbar. Each mode should define the
- visible fields. If save is visible is defined by the
- presence of the save setting. The order is defined in markupEditor and not
- changeable. It would confuse the user otherwise
- - [X] spec
- - [X] add save button which calls a submit callback
- - [X] basics
- - [X] keep styles from the original html element
- - [X] different toolbars for different modes.
- - [X] Fix bugs in textileCompiler
- - [X] get specs running in Firefox
- - [X] W: check if selection is in preview before calculating states
- and doing things: Firefox select text -> h1 -> p -> all gone
- - [X] formatBlock should select multiple paragraphs
- - [X] refactor to use prototypes
- - [X] abstract getStates
- - [X] update preview periodically (and track changes)
- - [X] prevent link click follow
- - [X] preview div should always have a p-tag inside
- - [X] on mode change clear selection (select something in ta
- -> preview -> ta selection should be gone)
- - [X] fix rare bug: updating preview in preview mode should not write textile into preview
- reproduce: load dev.html -> press any key -> wait
-
-* [1/3] Bugs
- - [X] pressing enter at the end of a heading sets the cursor outside
- any paragraph
- - [ ] h1. * item1
- does not compile right
+* [0/1] Bugs
- [ ] set cursor between _a and click italic two times -> not the
same situation as before. Such two clicks should be idempotent
* [0/6] Consider
+ - [ ] should only setup sync between editors, that are initialized in the same collection
- [ ] Partial list change should either
change the whole list (currently wysiwyg)
change part off the list (currently textile and the norm)
View
4 config.ru
@@ -0,0 +1,4 @@
+require 'rubygems'
+require 'middleman'
+
+run Middleman.server
View
4 join
@@ -17,9 +17,11 @@ File.open('source/javascripts/joined.js','w') do |file|
\/ # Closing delimiter.
| # Or
$\s*\/\/.* # One line comments
+ |
+ $\s*console\..*
)/x
- file.puts File.open('source/javascripts/' + filename + '.js').read #.gsub(regexp, '')
+ file.puts File.open('source/javascripts/' + filename + '.js').read.gsub(regexp, '')
end
end
View
2  source/javascripts/core/jqueryHook.js
@@ -119,7 +119,7 @@
editor.changeMode('wysiwyg');
} else {
editor.currentMode.activate(editor, function(){
- editor.currentMode.afterActivation();
+ editor.currentMode.afterActivation(editor);
});
}
View
2  source/javascripts/core/toolbar.js
@@ -134,7 +134,7 @@
toolbarDiv.html(getToolbarHTML());
- if(select){
+ if(select && select[0]){
useExternalChangeDataModeSelect(select, toolbarDiv, editor.id);
}
View
139 source/javascripts/modes/wysiwygMode.js
@@ -10,41 +10,30 @@
function endNode(){
return jQuery(selection.getRangeAt(0).endContainer);
}
-
- function lastParentBeforePreview(node){
- if(node.parent().is(".preview")){
- return node;
- } else {
- return node.parentsUntil(".preview").last();
- }
- }
-
- function getParagraphs() {
- var anchor, focus, paragraphs, matchIndex = -1;
- anchor = lastParentBeforePreview(startNode());
- focus = lastParentBeforePreview(endNode())[0];
-
- if(anchor[0] !== focus){
- paragraphs = anchor.nextAll().filter(function(i){
- if(this == focus){
- matchIndex = i;
- }
- if(matchIndex === -1 || matchIndex === i){
- return true;
- }
- }).add(anchor);
- } else {
- paragraphs = anchor;
+ function replaceEachParagraph(editor, functor){
+ var paragraph, children, i, l,
+ newParagraphs = $(),
+ contents = wysiwygMode.getSelection(editor);
+
+ if(!/h\d|p|(o|u)l/i.test(contents.childNodes[0].nodeName)){
+ contents = contents.firstChild;
}
+ children = contents.childNodes;
+ l = children.length;
- return paragraphs;
+ for(i = 0; i < l ; i++){
+ newParagraphs = newParagraphs.add(functor(children[i]));
+ }
+ wysiwygMode.replaceSelection(editor, newParagraphs);
}
-
- function align(direction) {
- getParagraphs().removeClass("left")
- .removeClass("right").removeClass("center")
- .addClass(direction);
+
+ function align(editor, direction) {
+ replaceEachParagraph(editor, function(paragraph){
+ return $(paragraph).removeClass("left")
+ .removeClass("right").removeClass("center")
+ .addClass(direction);
+ });
}
function selectNodes(nodes,collapse){
@@ -122,16 +111,33 @@
*/
function Border(node, borderType, nextProperty){
this.nextProperty = nextProperty;
+
+ if(node.is('.preview')){ // select all (even selection of all
+ // nodes within preview) in firefox does select the whole preview div
+ if(nextProperty === 'nextSibling'){
+ node = $(node[0].lastChild);
+ } else {
+ node = $(node[0].firstChild);
+ }
+ }
+
this.ancestors = node.parentsUntil(".preview");
this.block = this.ancestors[this.ancestors.length - 1] || node[0];
- this.borderNode = this.ancestors[this.ancestors.length -2] || node[0];
+
+ var depth = borderType ? 2 : 1;
+ this.borderNode = this.ancestors[this.ancestors.length -depth] || node[0];
+
while(this.borderNode){
this.node = this.borderNode;
- if(!borderType || this.borderNode.nodeName.toLowerCase() === borderType){
+ if(this.borderNode.nodeName.toLowerCase() === borderType){
+ break;
+ } else if (/preview/.test(this.node.parentNode.className)){
+ this.borderNode = null;
break;
}
this.borderNode = this.borderNode[nextProperty];
}
+
this.safeBlock = this.borderNode ? this.block : this.block[nextProperty];
}
@@ -182,7 +188,7 @@
*/
function joinAdjacentList(border, list){
var children;
- if(border.safeBlock && /ul/i.test(border.safeBlock.nodeName)){
+ if(border.safeBlock && border.safeBlock.nodeName === list[0].nodeName){
next = border.safeBlock[border.nextProperty];
children = $(border.safeBlock).remove().children();
@@ -571,18 +577,18 @@
tag: 'i'
},
alignLeft: {
- clicked: function(){
- align('left');
+ clicked: function(editor){
+ align(editor, 'left');
}
},
alignRight: {
- clicked: function(){
- align('right');
+ clicked: function(editor){
+ align(editor, 'right');
}
},
alignCenter: {
- clicked: function(){
- align('center');
+ clicked: function(editor){
+ align(editor, 'center');
}
},
unorderedList: {
@@ -705,23 +711,14 @@
},
formatBlock: {
clicked: function(editor, target) {
- var paragraph, newParagraphs = [], tag;
-
- getParagraphs().replaceWith(function(){
-
- if(/(u|o)l/i.test(this.nodeName)){ // ignore lists
- // TODO update jquery and try returning the list. File
- // bug when it won't work
- tag = this.nodeName;
- } else {
- tag = target.value;
+ replaceEachParagraph(editor, function(paragraph){
+ if(!/(u|o)l/i.test(paragraph.nodeName)){ // ignore lists
+ paragraph = $('<' + target.value + '>')
+ .addClass(paragraph.className).append(paragraph.childNodes);
}
- paragraph = $('<' + tag + '>')
- .addClass(this.className).append(this.childNodes);
- newParagraphs.push(paragraph[0]);
return paragraph;
});
- selectNodes(newParagraphs);
+
}
}
},
@@ -735,13 +732,29 @@
* @returns {HTMLFragment} The selected nodes
*/
getSelection: function(editor, nodeType){
- var range = selection.getRangeAt(0);
+ var range = selection.getRangeAt(0),
+ start = startNode(),
+ end = endNode();
editor.collapsed = range.collapsed;
- editor.leftBorder = new Border(startNode(), nodeType, 'previousSibling');
- editor.rightBorder = new Border(endNode(), nodeType, 'nextSibling');
+ // Fix firefox bug: a focused element that is contentEditable
+ // does not place the cursor inside an inner tag, but just
+ // selects the whole node
+ if(start.is('.preview')){
+ start = $(start[0].firstChild);
+ }
+ if(end.is('.preview')){
+ if(editor.collapsed){
+ end = start;
+ } else {
+ end = $(end[0].lastChild);
+ }
+ }
+ editor.leftBorder = new Border(start, nodeType, 'previousSibling');
+ editor.rightBorder = new Border(end, nodeType, 'nextSibling');
+
range.setStartBefore(editor.leftBorder.node);
range.setEndAfter(editor.rightBorder.node);
@@ -752,14 +765,14 @@
.insertAfter(editor.rightBorder.block);
}
- return range.extractContents();
+ return range.extractContents();
},
/**
* Insert the given nodes into the DOM tree at the place where
* getSelection extracted the nodes
*
* @param {Editor} editor The editor to work on
- * @param {HTMLFragment} nodes The nodes which will be inserted
+ * @param {jQuery} nodes The nodes which will be inserted
*/
replaceSelection: function(editor, nodes){
if(editor.leftBorder.safeBlock){
@@ -825,12 +838,12 @@
return node.parentsUntil(".preview").add(node);
}
-
+
var nodes = [], startNodes, endNodes,
- content = selection.getRangeAt(0).cloneContents().firstChild;
+ contents = selection.getRangeAt(0).cloneContents();
- startNodes = getParents(startNode(), content);
- endNodes = getParents(endNode(), content);
+ startNodes = getParents(startNode(), contents.firstChild);
+ endNodes = getParents(endNode(), contents.lastChild);
if(/(u|o)l/i.test(startNodes[0].nodeName) && startNodes[0].nodeName !== endNodes[0].nodeName){
nodes = startNodes.toArray();
View
7 source/javascripts/site.js
@@ -10,11 +10,16 @@ $(document).ready(function(){
select: $("#externalSelect2 select")
});
+ $("#wrongExternalSelect textarea").markupEditor({
+ select: $("#wrongExternalSelect select")
+ });
+
$(".markupClick").markupEditor("prepare",{
save: function(editor){
console.log(editor);
console.log(editor.textArea.val());
- }
+ },
+ select: $("#externalSelect select.availableModes")
});
ME.setOptions({uri: ['www.google.com','www.example.com','index.html']});
View
23 source/javascripts/test/markupEditor.js
@@ -46,13 +46,13 @@ $(function(){
async(function(){
start();
ok(!previewButton.is('.on'), 'preview off');
- ok(changeMode.val() === 'haml', 'The datamode should stay the same');
+ ok(changeMode.val() === 'haml', 'The datamode should stay the same, was ' + changeMode.val());
previewButton.mouseup();
async(function(){
start();
ok(previewButton.is('.on'), 'preview on');
- ok(changeMode.val() === 'haml', 'The datamode should stay the same');
+ ok(changeMode.val() === 'haml', 'The datamode should stay the same, was ' + changeMode.val());
});
});
});
@@ -77,7 +77,8 @@ $(function(){
ok(div.attr('contentEditable') === 'false', 'content should no longer be editable');
div.click();
ok(div.attr('contentEditable') === 'true', 'editor should be reopened');
- ok(div.parent().find("a.save").is(":visible"), "settings should be remembered");
+ ok(div.parent().find("a.save").is(":visible"), "save settings should be remembered");
+ ok(div.parent().find("select.changeDataMode option[value='unknown']")[0], "select settings should be remembered");
});
var externalSelect = $('select.availableModes'),
@@ -95,8 +96,19 @@ $(function(){
ok(externalSelect.is(':hidden'), 'external select should be hidden');
});
+ test('should ignore non existant select', function(){
+ var select = $('#wrongExternalSelect .changeDataMode');
+ ok(select.is(':visible'), 'select should be visible');
+ ok(select.find('option').length > 0, 'select should contain items');
+ });
+
test('should sync the different select boxes', function(){
var newVal = 'completeSyncMode';
+
+ if(editor1.find('.wysiwyg').is('.on')){
+ helper1.click('.wysiwyg');
+ }
+
changeMode1.val(newVal).change();
ok(externalSelect.val() === newVal, 'change in one editor should change external select');
ok(changeMode2.val() === newVal, 'change in one editor should change select in other editor');
@@ -106,7 +118,10 @@ $(function(){
ok(changeMode1.val() === newVal, 'change in external select should change editor 1');
ok(changeMode2.val() === newVal, 'change in external select should change editor 2');
- helper1.click('.wysiwyg');
+ helper1.off('wysiwyg')
+ .click('.wysiwyg')
+ .on('wysiwyg');
+
ok(editor2.find('.wysiwyg').is('.on'), 'preview mode change should sync');
newVal = 'completeSyncMode';
View
2  source/javascripts/test/support/testHelper.js
@@ -185,7 +185,7 @@ WysiwygHelper.prototype = (function(){
} else {
node = identifier;
}
-
+ this.preview.focus();
if(node.is("img")){
this.range.selectNode(node[0]);
} else {
View
28 source/javascripts/test/wysiwygMode.js
@@ -29,14 +29,20 @@ $(document).ready(function(){
selection: selection,
range: range
});
+
+ w2.set('othertext\n\nsecond paragraph');
w.set('text')
.select('p');
w2.click('.bold');
- w.notMatch('b');
+ w.notMatch('b')
+ .match('p');
w.set('text')
.select('p');
w2.change(".formatBlock", "h1");
- w.notMatch('h1');
+ w.notMatch('h1')
+ .match('p');
+ w2.match('p')
+ .match('h1');
});
test("default paragraph", function(){
@@ -249,6 +255,24 @@ $(document).ready(function(){
.on(listType);
});
+ test("List " + listType + " do not join adjacent lists of different type", function(){
+ var otherBullet = bullet == '*' ? '#' : '*',
+ otherTag = tag == 'ul' ? 'ol' : 'ul',
+ otherListType = listType == 'orderedList' ? 'unorderedList' : 'orderedList';
+
+ w.set(otherBullet + " firstList\n\ntest\n\n" + otherBullet + " secondList")
+ .select("p")
+ .off(listType)
+ .off(otherListType)
+ .click("."+listType)
+ .match(tag,1)
+ .match(tag + " :first-child:contains(test)")
+ .match("li",3)
+ .match(otherTag,2)
+ .notMatch('p')
+ .on(listType);
+ });
+
test("List " + listType + " toggle", function(){
w.set(bullet + " list")
.select(tag)
View
5 source/test_runner.html.haml
@@ -37,6 +37,11 @@
%div.markupClick.unknown2{ :src => 'api/markup/get?file=unknown'}
= erb :"textareas/html"
+%form#wrongExternalSelect
+ %textarea.textile
+
+%div.markupWithWrongSelect.textile
+
%div.markupClick.haml{ :src => 'api/markup/get?file=haml'}
= erb :"textareas/html"
Please sign in to comment.
Something went wrong with that request. Please try again.