Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

added translation capabilities

added tooltips to the toolbar

added error messages in dialogs
  • Loading branch information...
commit d27e7d733785199cb80c9f74a5ccc2933169aa16 1 parent 1182780
@johnny authored
View
32 TODO
@@ -1,4 +1,4 @@
-* [30/40] Further improvements
+* [33/41] Further improvements
- [-] wysiwyg
- [ ] Firefox: fix checkState for one bold word
- [ ] br tags should be top level, because Border expects that
@@ -8,6 +8,7 @@
be the same)
- [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
+
- [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)
@@ -27,19 +28,6 @@
- [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
- - [-] Better Dialogs (for inspiration see gollum)
- - [ ] display errors as 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
- - [ ] localization
- [ ] split up markupEditor.js
- [ ] look how ender handles the extensability
perhaps (... ME.Mode = Mode;})(ME, jQuery) is an option
@@ -67,6 +55,22 @@
- [ ] fire native events (not supported in awesome, try in kde or windows)
- [ ] clean and parse pasted html
- [ ] handle blocktags within lists
+ - [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
View
2  join
@@ -1,6 +1,6 @@
#!/usr/bin/ruby
-files = %w{plugins/isValid markupEditor util plugins/enhanceTextfield plugins/combobox dialog modes/textile/textileMode modes/textile/bruteForceCompiler modes/wysiwygMode}
+files = %w{vendor/jquery.tipsy init plugins/t10n locale/en plugins/isValid markupEditor util plugins/enhanceTextfield plugins/combobox dialog modes/textile/textileMode modes/textile/bruteForceCompiler modes/wysiwygMode modes/hamlMode}
File.open('source/javascripts/joined.js','w') do |file|
files.each do |filename|
View
25 source/javascripts/dialog.js
@@ -1,15 +1,5 @@
-(function($){
- var callback,
- t10n = {
- noticeTitle: 'Notice',
- linkTitle: 'Link',
- insertImageTitle: 'Image',
- uri: 'Link',
- uriPrompt: 'Enter or select link',
- title: 'Title',
- titlePrompt: 'Enter title',
- imageUri: 'Image Source'
- };
+(function($, _){
+ var callback;
$.fn.isValid.init();
@@ -97,6 +87,7 @@
width: 600,
modal: true,
close: function() {
+ $form.isValid('reset');
if(callback.close){
callback.close();
}
@@ -111,7 +102,6 @@
fields[i].change();
}
fields[0][0].setSelectionRange(0,0);
- $form.isValid('reset');
}
});
@@ -138,11 +128,13 @@
jQueryFunctions = fieldDefinitions[i][1];
$form.append(
- '<label for=\"' + fieldName + '\">'+ t10n[fieldName] + '</label>'
+ '<label for=\"' + fieldName + '\">'+ _(fieldName) + '</label>'
);
fields[i] = $('<input type=\"text\" class=\"' + fieldName + '\" name=\"' + fieldName + "\">")
.appendTo($form);
+ fields[i].enhanceTextfield({prompt: _(fieldName+"Prompt")});
+
if(jQueryFunctions){
for(method in jQueryFunctions){
if(jQueryFunctions.hasOwnProperty(method)){
@@ -151,7 +143,6 @@
}
}
}
- fields[i].enhanceTextfield({prompt: t10n[fieldName+"Prompt"]});
}
return fields;
}
@@ -160,7 +151,7 @@
var $dialogNode, proxy;
$dialogNode = $('<div id=\"'+ name + '-dialog\" title=\"' +
- t10n[name + "Title"] + '\">');
+ _(name + "Title") + '\">');
if(fieldDefinitions){
proxy = initFormDialog($dialogNode, fieldDefinitions);
@@ -197,4 +188,4 @@
]),
notice: createDialog('notice')
};
-})(jQuery);
+})(jQuery, ME.t10n);
View
1  source/javascripts/init.js
@@ -0,0 +1 @@
+ME = {};
View
33 source/javascripts/locale/en.js
@@ -0,0 +1,33 @@
+ME.t10n.load({
+ noticeTitle: 'Notice',
+ noticeMissingToHTML: 'The old mode could not convert to HTML. You will have to convert the markup manually.',
+ noticeMissingToText: 'This mode can not convert HTML to your markup. You will have to convert the markup manually',
+ noticeMissingDatamode: 'Datamode not found. Please specify a valid datamode',
+ linkTitle: 'Link',
+ insertImageTitle: 'Image',
+ uri: 'Link',
+ uriPrompt: 'Enter or select link',
+ title: 'Title',
+ titlePrompt: 'Enter title',
+ imageUri: 'Image Source',
+ p: "Paragraph",
+ h1: "Heading 1",
+ h2: "Heading 2",
+ h3: "Heading 3",
+ bold: 'Bold',
+ italic: 'Italic',
+ alignLeft: 'align left',
+ alignCenter: 'align center',
+ alignRight: 'align right',
+ unorderedList: 'unordered list',
+ orderedList: 'ordered list',
+ link: 'link',
+ insertImage: 'image',
+ save: 'save',
+ wysiwyg: 'edit preview directly',
+ close: 'close',
+ changeDataMode: 'change the markup format',
+ formatBlock: 'change paragraph format',
+ errorText: '{label} is a required field.',
+ emailErrorText: 'Please enter a valid {label}'
+});
View
28 source/javascripts/markupEditor.js
@@ -1,4 +1,4 @@
-(function ($) {
+(function ($, _) {
var globalSettings = {}, availableModes = {}, toolbarItems = {}, toolbarHTML = "",
availableItems = ['bold','italic','alignLeft','alignCenter','alignRight','unorderedList','orderedList','link','insertImage','save','wysiwyg','close','changeDataMode','formatBlock'],
globalItems = [],
@@ -416,7 +416,7 @@
* @returns {String} A html string of the button
*/
getButton: function() {
- return '<a href="#" class=\"'+ this.name +'" ><span>'+ this.name +'</span></a>';
+ return '<a href="#" class=\"'+ this.name +'\" title="' + _(this.name) + '"><span>'+ this.name +'</span></a>';
}
};
@@ -442,7 +442,7 @@
* @returns {String} A html string of the button
*/
getButton: function() {
- var select = "<select class=\"" + this.name + "\">",
+ var select = "<select class=\"" + this.name + '\" title="' + _(this.name) + '">',
optionsLength = this.options.length,
i;
@@ -782,11 +782,11 @@
} else {
// TODO use i18n shortcut here
if(nextMode.toText){
- text = 'The old mode could not convert to HTML. You will have to convert the markup manually.';
+ text = 'noticeMissingToHTML';
} else {
- text = 'This mode can not convert HTML to your markup. You will have to convert the markup manually';
+ text = 'noticeMissingToText';
}
- dialogProxy = ME.dialog.notice(['Ok', 'Cancel'], text);
+ dialogProxy = ME.dialog.notice(['Ok', 'Cancel'], _(text));
dialogProxy.dialog('open', {
submit: function(){
if(callback){
@@ -936,7 +936,7 @@
/**
* @namespace Holds all public methods
*/
- ME = {
+ $.extend(ME, {
/**
* Add a mode
*
@@ -1017,7 +1017,7 @@
setOptions: function(options){
this.options = options;
}
- };
+ });
toolbarItems.changeDataMode = new ToolbarSelect("changeDataMode", [], function(editor, target) {
editor.changeDataMode(target.value);
@@ -1027,10 +1027,10 @@
});
toolbarItems.formatBlock = new ToolbarSelect("formatBlock",[
- ["p", "Paragraph"],
- ["h1", "Heading 1"],
- ["h2", "Heading 2"],
- ["h3", "Heading 3"]
+ ["p", _("p")],
+ ["h1", _("h1")],
+ ["h2", _("h2")],
+ ["h3", _("h3")]
]);
toolbarItems.save = new ToolbarButton("save", function(editor){
@@ -1114,7 +1114,7 @@
function isValidDatatype(cssClass, changeDatamodeSelect){
if(!Editor.extractDataType(cssClass, changeDatamodeSelect)){
- ME.dialog.notice(['Ok'],'Datamode not found. Please specify a valid datamode')
+ ME.dialog.notice(['Ok'], _('noticeMissingDatamode'))
.dialog('open');
} else {
return true;
@@ -1186,4 +1186,4 @@
return editor;
}
-}(jQuery));
+}(jQuery, ME.t10n));
View
7 source/javascripts/plugins/combobox.js
@@ -47,7 +47,7 @@
input.val(ui.item.value).change();
}
})
- .addClass( "ui-corner-left" );
+ .addClass( "ui-corner-right short" );
input.data( "autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
@@ -59,14 +59,12 @@
this.button = $( "<button type='button'>&nbsp;</button>" )
.attr( "tabIndex", -1 )
.attr( "title", "Show All Items" )
- .insertAfter( input )
.button({
icons: {
primary: "ui-icon-triangle-1-s"
},
text: false
})
- .removeClass( "ui-corner-all" )
.addClass( "ui-corner-right ui-button-icon" )
.click(function() {
// close if already visible
@@ -81,7 +79,8 @@
input.autocomplete( "search", "" );
input.focus();
}
- });
+ })
+ .appendTo( input.parent() );
},
destroy: function() {
View
6 source/javascripts/plugins/enhanceTextfield.js
@@ -76,11 +76,7 @@
}
})
.parent().append($btn);
- if($t.hasClass("ui-corner-left")){
- $p.addClass("ui-corner-left");
- } else {
- $p.addClass("ui-corner-all");
- }
+ $p.addClass("ui-corner-all");
}
});
};
View
154 source/javascripts/plugins/isValid.js
@@ -1,72 +1,162 @@
-(function($) {
- // TODO cache fields
- var opts, errorMsgType, initialized,
- methods = {
- check: function(options) {
- var $this = this, valid = true;
- //Hide any errors that are already showing
- $this.find(opts.errorElement + '.' + opts.errorClass).remove();
- $this.find(':input.' + opts.inputErrorClass).removeClass(opts.inputErrorClass);
+/**
+ * Validate a given Form and display errors as tips, if formfields are
+ * invalid.
+ *
+ * inspired by tipsy
+ */
+(function($, _) {
+ var opts, errorMsgType, initialized;
- //Get all the required inputs
- $this.find(':input.required').each(function() {
+ function Validator($form){
+ this.$form = $form;
+
+ //Get all the required inputs
+ this.inputs = $form.find(':input.required');
+ }
+
+ Validator.prototype = {
+ check: function() {
+ var valid = true;
+
+ this.reset(true);
+
+ this.inputs.each(function() {
var $input = $(this),
fieldValue = $.trim($input.val()),
- labelText = $input.siblings('label').text().replace(opts.removeLabelChar, ''),
- errorMsg = '';
+ labelText = $input.parent().prev().text(),
+ errorMsg;
//Check if it's empty or an invalid email
if(fieldValue === '') {
- errorMsg = hasLabelPlaceholder ? errorMsg = opts.errorText.replace('{label}',labelText) : errorMsg = opts.errorText;
+ errorMsg = _('errorText') || opts.errorText;
valid = false;
} else if($input.hasClass('email')) {
if(!(/^([_a-z0-9-]+)(\.[_a-z0-9-]+)*@([a-z0-9-]+)(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/.test(fieldValue))) {
- errorMsg = hasLabelPlaceholder ? errorMsg = opts.emailErrorText.replace('{label}',labelText) : errorMsg = opts.emailErrorText;
+ errorMsg = _('emailErrorText') || opts.emailErrorText;
valid = false;
}
}
//If there is an error, display it
- if(errorMsg !== '') {
- $input.parent().addClass(opts.errorClass);
- //$input.addClass(opts.inputErrorClass).after('<'+opts.errorElement+' class="'+opts.errorClass+'">' + errorMsg + '</'+opts.errorElement+'>');
+ if(errorMsg) {
+ errorMsg = errorMsg.replace('{label}',labelText);
+ $input.parent()
+ .addClass(opts.errorClass)
+ .error('show', errorMsg);
}
});
return valid;
},
- reset: function(){
- return this.find(':input.required').each(function(){
- $(this).parent().removeClass(opts.errorClass);
+ reset: function(fadeOut){
+ return this.inputs.each(function(){
+ $(this).parent()
+ .removeClass(opts.errorClass)
+ .error('hide', fadeOut);
});
}
};
+ function get($element, constructor, dataField){
+ var data = $element.data(dataField);
+ if (!data) {
+ data = new constructor($element);
+ $element.data(dataField, data);
+ }
+ return data;
+ }
/**
* Validates forms
*
* @memberOf jQuery.prototype
*
- * @param {String} [method="init"] The method to call
+ * @param {String} [method="check"] The method to call
*/
- $.fn.isValid = function(method) {
- if (!methods[method]) {
- method = 'check';
- }
- return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ $.fn.isValid = function(method, options) {
+ var valid = true;
+
+ this.each(function(){
+ var validator = get( $(this), Validator, 'isValid');
+
+ if (!validator[method]) {
+ method = 'check';
+ }
+
+ valid = validator[method](options) ? valid : false;
+ });
+
+ return valid;
};
$.fn.isValid.init = function(options){
opts = $.extend({}, $.fn.isValid.defaults, options);
- hasLabelPlaceholder = opts.errorText.indexOf("{label}") > -1;
};
// default options
$.fn.isValid.defaults = {
errorClass: 'error',
errorText: '{label} is a required field.',
- emailErrorText: 'Please enter a valid {label}',
- errorElement: 'strong',
- removeLabelChar: '*'
+ emailErrorText: 'Please enter a valid {label}'
+ };
+
+ function Error($element) {
+ this.$element = $element;
+ this.$tip = $('<div class="error-tip"></div>')
+ .html('<div class="arrow"></div><div class="inner"></div>')
+ .prependTo(document.body);
+ }
+
+ Error.prototype = {
+ opacity: 0.8,
+ show: function(message) {
+ var $tip = this.$tip;
+ this.hidden = false;
+
+ $tip.find('.inner').text(message);
+ $tip.css({top: 0, left: 0, visibility: 'hidden', display: 'block'});
+
+ var pos = $.extend({}, this.$element.offset(), {
+ width: this.$element[0].offsetWidth,
+ height: this.$element[0].offsetHeight
+ });
+
+ var actualHeight = $tip[0].offsetHeight;
+
+ $tip.css({
+ top: pos.top + pos.height / 2 - actualHeight / 2,
+ left: pos.left + pos.width
+ });
+
+ $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'})
+ .animate({opacity: this.opacity});
+ },
+
+ hide: function(fadeOut) {
+ var that = this;
+ if(this.hidden){
+ return;
+ }
+ if (fadeOut) {
+ this.$tip.stop().fadeOut(function() { that.hidden = true; });
+ } else {
+ this.$tip.hide();
+ this.hidden = true;
+ }
+ }
+ };
+
+ function getError($ele) {
+ var error = $ele.data('error');
+ if (!error) {
+ error = new Error($ele);
+ $ele.data('error', error);
+ }
+ return error;
+ }
+
+ $.fn.error = function(method, options) {
+ return this.each(function(){
+ get( $(this), Error, 'error' )[method](options);
+ });
};
-})(jQuery);
+})(jQuery, ME.t10n);
View
12 source/javascripts/plugins/t10n.js
@@ -0,0 +1,12 @@
+!function(){
+ var currentDefinition = {};
+
+ ME.t10n = function(id){
+ return currentDefinition[id];
+ };
+
+ ME.t10n.load = function(definition){
+ currentDefinition = definition;
+ };
+}();
+
View
4 source/layout.haml
@@ -14,8 +14,8 @@
= yield
- = javascript_include_tag "vendor/jquery", "vendor/jquery-ui", "plugins/isValid.js"
- = javascript_include_tag "markupEditor", "util"
+ = javascript_include_tag "vendor/jquery", "vendor/jquery-ui", 'vendor/jquery.tipsy'
+ = javascript_include_tag 'init', "plugins/t10n", 'locale/en', "plugins/isValid.js", "markupEditor", "util"
= javascript_include_tag "plugins/combobox", "plugins/enhanceTextfield", "dialog"
= javascript_include_tag "modes/textile/textileMode", "modes/textile/bruteForceCompiler"
// = javascript_include_tag "modes/htmlMode"
View
56 source/stylesheets/markupEditor.css.sass
@@ -3,6 +3,9 @@
$overlay: rgba(255, 255, 255, .5)
$transparent: rgba(255, 255, 255, .8)
$width: 20px
+$error: #ff0000
+$tip-color: #000
+$tip-background: $error
@mixin editorElement
background: none repeat scroll 0 0 #F9F9F9
@@ -164,26 +167,25 @@ $width: 20px
span.clearButton
display: block
float: left
- width: 300px
+ width: 342px
margin: 0 0 0.4em
border: 1px solid #d3d3d3
&.focus
border: 1px solid #eec77c
&.error
color: #666666
- border: 1px solid #ff0000
- &.ui-corner-all
- width: 342px
- input
- width: 312px
+ border: 1px solid $error
input
- width: 270px
+ width: 312px
border: none
padding: 0.49em 0
margin: 0 0.4em
&:focus
border: none
outline: none
+ &.short
+ width: 270px
+
span
width: 10px
cursor: pointer
@@ -194,7 +196,43 @@ $width: 20px
.ui-button
margin: 0
- margin-left: -1px
- float: left
+ float: right
+ border: none
+ border-left: 1px
+ .ui-icon
+ margin-left: -6px
+ .ui-icon-triangle-1-s
+ background-position: -66px -16px
.ui-button-icon-only .ui-button-text
padding: 0.36em
+
+
+
+.error-tip
+ font-size: 0.9em
+ position: absolute
+ padding: 5px
+ z-index: 100000
+
+ .inner
+ background-color: $tip-background
+ color: $tip-color
+ max-width: 200px
+ padding: 5px 8px 4px 8px
+ text-align: center
+ border-radius: 3px
+ -moz-border-radius: 3px
+ -webkit-border-radius: 3px
+
+ /* Rounded corners
+
+ .arrow
+ position: absolute
+ width: 0
+ height: 0
+ border: 5px solid transparent
+ border-right-color: $error
+ top: 50%
+ margin-top: -5px
+ left: 0
+ border-left: none
Please sign in to comment.
Something went wrong with that request. Please try again.