Browse Source

Update rte module and fix input styles

pull/36/head
Artur Arseniev 10 years ago
parent
commit
05aee801a2
  1. 2
      index.html
  2. 15
      src/rich_text_editor/config/config.js
  3. 37
      src/rich_text_editor/main.js
  4. 12
      src/rich_text_editor/model/CommandButton.js
  5. 34
      src/rich_text_editor/view/CommandButtonSelectView.js
  6. 8
      src/rich_text_editor/view/CommandButtonView.js
  7. 70
      src/rich_text_editor/view/CommandButtonsView.js
  8. 41
      src/rich_text_editor/view/TextEditorView.js
  9. 2
      src/selector_manager/template/classTags.html
  10. 2
      src/selector_manager/view/ClassTagsView.js
  11. 28
      styles/css/main.css
  12. 34
      styles/scss/main.scss

2
index.html

@ -707,7 +707,7 @@
} }
.badge-header{ .badge-header{
height: 115px; height: 115px;
background-image:url("./img/bg-gr-v.png"), url("./img/work-desk.jpg"); background-image:url("http://grapesjs.com/img/bg-gr-v.png"), url("http://grapesjs.com/img/work-desk.jpg");
background-position:left top, center center; background-position:left top, center center;
background-attachment:scroll, fixed; background-attachment:scroll, fixed;
overflow: hidden; overflow: hidden;

15
src/rich_text_editor/config/config.js

@ -7,17 +7,26 @@ define(function () {
command: 'bold', command: 'bold',
title: 'Bold', title: 'Bold',
class: 'fa fa-bold', class: 'fa fa-bold',
group: 'format'
},{ },{
command: 'italic', command: 'italic',
title: 'Italic', title: 'Italic',
class: 'fa fa-italic', class: 'fa fa-italic',
group: 'format'
},{ },{
command: 'underline', command: 'underline',
title: 'Underline', title: 'Underline',
class: 'fa fa-underline', class: 'fa fa-underline',
},{
command: 'strikethrough',
title: 'Strikethrough',
class: 'fa fa-strikethrough',
group: 'format' group: 'format'
},], }/*,{
command: 'fontSize',
options: [
{name: 'Huge', value: '100px'},
{name: 'Normal', value: '14px'},
{value: '5px'}
]
}*/],
}; };
}); });

37
src/rich_text_editor/main.js

@ -4,13 +4,22 @@
* * [getAll](#getall) * * [getAll](#getall)
* * [remove](#remove) * * [remove](#remove)
* *
* This module allows to customize the toolbar of the Rich Text Editor *
* styleWithCSS
* removeFormat
*
*
* This module allows to customize the toolbar of the Rich Text Editor. It's highly recommended
* to keep this toolbar as small as possible, especially from styling commands (eg. 'fontSize')
* and leave this task to the Style Manager.
*
* Before using methods you should get first the module from the editor instance, in this way: * Before using methods you should get first the module from the editor instance, in this way:
* *
* ```js * ```js
* var rte = editor.RichTextEditor; * var rte = editor.RichTextEditor;
* ``` * ```
* Complete list of commands * Complete list of commands
* https://developer.mozilla.org/it/docs/Web/API/Document/execCommand
* http://www.quirksmode.org/dom/execCommand.html * http://www.quirksmode.org/dom/execCommand.html
* @module RichTextEditor * @module RichTextEditor
*/ */
@ -59,9 +68,10 @@ define(function(require) {
}, },
/** /**
* Add new command to the toolbar * Add a new command to the toolbar
* @param {string} command Command name
* @param {string} command Command name * @param {string} command Command name
* @param {Object} opts Command options
* @return {Model} Added command
* @example * @example
* var cm = rte.add('bold', { * var cm = rte.add('bold', {
* title: 'Make bold', * title: 'Make bold',
@ -70,7 +80,7 @@ define(function(require) {
* // With arguments * // With arguments
* var cm = rte.add('fontSize', { * var cm = rte.add('fontSize', {
* title: 'Font size', * title: 'Font size',
* arguments: [ * options: [
* {name: 'Big', value: 5}, * {name: 'Big', value: 5},
* {name: 'Normal', value: 3}, * {name: 'Normal', value: 3},
* {name: 'Small', value: 1} * {name: 'Small', value: 1}
@ -83,6 +93,25 @@ define(function(require) {
return commands.add(obj); return commands.add(obj);
}, },
/**
* Get the command by its name
* @param {string} command Command name
* @return {Model}
* @example
* var cm = rte.get('fontSize');
*/
get: function(command) {
return commands.where({command: command})[0];
},
/**
* Returns the collection of commands
* @return {Collection}
*/
getAll: function(){
return commands;
},
/** /**
* Triggered when the offset of the editro is changed * Triggered when the offset of the editro is changed
* @private * @private

12
src/rich_text_editor/model/CommandButton.js

@ -2,12 +2,20 @@ define(['backbone'],
function (Backbone) { function (Backbone) {
return Backbone.Model.extend({ return Backbone.Model.extend({
idAttribute: 'command',
defaults: { defaults: {
command: '', command: '',
type: '',
title: '', title: '',
class: '', class: '',
group: '', options: [],
arguments: [], },
initialize: function() {
var opts = this.get('options');
if(opts.length)
this.set('type', 'select');
}, },
}); });

34
src/rich_text_editor/view/CommandButtonSelectView.js

@ -0,0 +1,34 @@
define(['backbone'],
function (Backbone) {
return Backbone.View.extend({
initialize: function(o, config){
this.config = config || {};
this.className = this.config.stylePrefix + 'btn ' + this.model.get('class');
},
getInput: function(){
var m = this.model;
if(!this.input){
var cmd = m.get('command');
var input = '<select data-edit="' + cmd +'">';
var opts = m.get('options');
for(var i = 0, len = opts.length; i < len; i++){
var opt = opts[i];
var value = opt.value;
var name = opt.name || value;
input += '<option value="' + value + '">' + name + '</option>';
}
input += '</select>';
this.input = $(input);
}
return this.input;
},
render: function() {
this.$el.addClass(this.className);
this.$el.html(this.getInput());
return this;
}
});
});

8
src/rich_text_editor/view/CommandButtonView.js

@ -4,13 +4,13 @@ define(['backbone'],
tagName: 'a', tagName: 'a',
initialize: function(o){ initialize: function(o, config){
this.config = o.config || {}; this.config = config || {};
this.className = this.config.stylePrefix + 'btn ' + this.model.get('class'); this.className = this.config.stylePrefix + 'btn ' + this.model.get('class');
}, },
render: function() { render: function() {
this.$el.attr('class', _.result( this, 'className' ) ); this.$el.addClass(this.className);
return this; return this;
} }
}); });

70
src/rich_text_editor/view/CommandButtonsView.js

@ -1,5 +1,5 @@
define(['backbone','./CommandButtonView'], define(['backbone','./CommandButtonView', './CommandButtonSelectView'],
function (Backbone, CommandButtonView) { function (Backbone, CommandButtonView, CommandButtonSelectView) {
return Backbone.View.extend({ return Backbone.View.extend({
attributes : { attributes : {
@ -8,27 +8,63 @@ define(['backbone','./CommandButtonView'],
initialize: function(o){ initialize: function(o){
this.config = o.config || {}; this.config = o.config || {};
this.id = this.config.stylePrefix + this.config.toolbarId; var pfx = this.config.stylePrefix || '';
this.id = pfx + this.config.toolbarId;
this.listenTo(this.collection, 'add', this.addTo);
this.$el.data('helper', 1); this.$el.data('helper', 1);
}, },
/**
* Add new model to the collection
* @param {Model} model
* @private
* */
addTo: function(model){
this.add(model);
},
/**
* Render new model inside the view
* @param {Model} model
* @param {Object} fragment Fragment collection
* @private
* */
add: function(model, fragment) {
var frag = fragment || null;
var viewObj = CommandButtonView;
switch (model.get('type')) {
case 'select':
viewObj = CommandButtonSelectView;
break;
}
var view = new viewObj({
model: model,
attributes: {
'title': model.get('title'),
'data-edit': model.get('command'),
},
}, this.config);
var rendered = view.render().el;
if(frag)
frag.appendChild(rendered);
else
this.$el.append(rendered);
},
render: function() { render: function() {
var fragment = document.createDocumentFragment(); var frag = document.createDocumentFragment();
this.$el.empty(); this.$el.empty();
this.collection.each(function(item){ this.collection.each(function(model){
var view = new CommandButtonView({ this.add(model, frag);
model: item, }, this);
config: this.config,
attributes: { this.$el.append(frag);
'title': item.get('title'), this.$el.attr('id', this.id );
'data-edit': item.get('command'),
},
});
fragment.appendChild(view.render().el);
},this);
this.$el.append(fragment);
this.$el.attr('id', _.result( this, 'id' ) );
return this; return this;
} }

41
src/rich_text_editor/view/TextEditorView.js

@ -23,13 +23,16 @@ define(['jquery'],
options, options,
toolbarBtnSelector, toolbarBtnSelector,
updateToolbar = function () { updateToolbar = function () {
if (options.activeToolbarClass) { var actCls = options.activeToolbarClass;
if (actCls) {
$(options.toolbarSelector).find(toolbarBtnSelector).each(function () { $(options.toolbarSelector).find(toolbarBtnSelector).each(function () {
var command = $(this).data(options.commandRole); var el = $(this);
if (document.queryCommandState(command)) { var command = el.data(options.commandRole);
$(this).addClass(options.activeToolbarClass); var doc = editor.get(0).ownerDocument;
if (doc.queryCommandState(command)) {
el.addClass(actCls);
} else { } else {
$(this).removeClass(options.activeToolbarClass); el.removeClass(actCls);
} }
}); });
} }
@ -38,7 +41,9 @@ define(['jquery'],
var commandArr = commandWithArgs.split(' '), var commandArr = commandWithArgs.split(' '),
command = commandArr.shift(), command = commandArr.shift(),
args = commandArr.join(' ') + (valueArg || ''); args = commandArr.join(' ') + (valueArg || '');
document.execCommand(command, 0, args); //document.execCommand("insertHTML", false, "<span class='own-class'>"+ document.getSelection()+"</span>");
editor.get(0).ownerDocument.execCommand("styleWithCSS", false, true);
editor.get(0).ownerDocument.execCommand(command, 0, args);
updateToolbar(); updateToolbar();
}, },
/* /*
@ -106,13 +111,24 @@ define(['jquery'],
bindToolbar = function (toolbar, options) { bindToolbar = function (toolbar, options) {
toolbar.find(toolbarBtnSelector).unbind().click(function () { toolbar.find(toolbarBtnSelector).unbind().click(function () {
restoreSelection(); restoreSelection();
editor.focus(); //editor.focus(); // cause defocus on selects
editor.get(0).ownerDocument.execCommand($(this).data(options.commandRole)); editor.get(0).ownerDocument.execCommand($(this).data(options.commandRole));
saveSelection(); saveSelection();
}); });
toolbar.find('[data-toggle=dropdown]').click(restoreSelection); toolbar.find('[data-toggle=dropdown]').click(restoreSelection);
var dName = '[data-' + options.commandRole + ']';
toolbar.find('input[type=text][data-' + options.commandRole + ']').on('webkitspeechchange change', function () { toolbar.find('select'+dName).on('webkitspeechchange change', function(){
var newValue = this.value;
restoreSelection();
if (newValue) {
editor.focus();
execCommand($(this).data(options.commandRole), newValue);
}
console.log('change isolated2 ', newValue);
saveSelection();
});
toolbar.find('input[type=text]'+dName,', select'+dName).on('webkitspeechchange change', function () {
console.log('on changed ', newValue);
var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */ var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */
this.value = ''; this.value = '';
restoreSelection(); restoreSelection();
@ -122,8 +138,10 @@ define(['jquery'],
} }
saveSelection(); saveSelection();
}).on('focus', function () { }).on('focus', function () {
console.log('on focus ');
var input = $(this); var input = $(this);
if (!input.data(options.selectionMarker)) { if (!input.data(options.selectionMarker)) {
console.log('i have no ', options.selectionMarker);
markSelection(input, options.selectionColor); markSelection(input, options.selectionColor);
input.focus(); input.focus();
} }
@ -161,7 +179,8 @@ define(['jquery'],
return this; return this;
} }
options = $.extend({}, $.fn.wysiwyg.defaults, userOptions); options = $.extend({}, $.fn.wysiwyg.defaults, userOptions);
toolbarBtnSelector = 'a[data-' + options.commandRole + '],button[data-' + options.commandRole + '],input[type=button][data-' + options.commandRole + ']'; var dName = '[data-' + options.commandRole + ']';
toolbarBtnSelector = 'a'+dName+',button'+dName+',input[type=button]'+dName+', select'+dName;
//bindHotkeys(options.hotKeys); //bindHotkeys(options.hotKeys);
if (options.dragAndDropImages) { if (options.dragAndDropImages) {
initFileDrops(); initFileDrops();
@ -183,6 +202,7 @@ define(['jquery'],
return this; return this;
}; };
$.fn.wysiwyg.defaults = { $.fn.wysiwyg.defaults = {
/*
hotKeys: { hotKeys: {
'ctrl+b meta+b': 'bold', 'ctrl+b meta+b': 'bold',
'ctrl+i meta+i': 'italic', 'ctrl+i meta+i': 'italic',
@ -196,6 +216,7 @@ define(['jquery'],
'shift+tab': 'outdent', 'shift+tab': 'outdent',
'tab': 'indent' 'tab': 'indent'
}, },
*/
toolbarSelector: '[data-role=editor-toolbar]', toolbarSelector: '[data-role=editor-toolbar]',
commandRole: 'edit', commandRole: 'edit',
activeToolbarClass: 'btn-info', activeToolbarClass: 'btn-info',

2
src/selector_manager/template/classTags.html

@ -2,7 +2,7 @@
<div id="<%= pfx %>label"><%= label %></div> <div id="<%= pfx %>label"><%= label %></div>
<div id="<%= pfx %>status-c"> <div id="<%= pfx %>status-c">
<span id="<%= pfx %>input-c"> <span id="<%= pfx %>input-c">
<div class="<%= pfx %>field <%= pfx %>select"> <div class="<%= pfx %>field <%= ppfx %>select">
<span id="<%= pfx %>input-holder"> <span id="<%= pfx %>input-holder">
<select id="<%= pfx %>states"> <select id="<%= pfx %>states">
<option value=""><%= statesLabel %></option> <option value=""><%= statesLabel %></option>

2
src/selector_manager/view/ClassTagsView.js

@ -12,6 +12,7 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
initialize: function(o) { initialize: function(o) {
this.config = o.config || {}; this.config = o.config || {};
this.pfx = this.config.stylePrefix || ''; this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || '';
this.className = this.pfx + 'tags'; this.className = this.pfx + 'tags';
this.addBtnId = this.pfx + 'add-tag'; this.addBtnId = this.pfx + 'add-tag';
this.newInputId = this.pfx + 'new'; this.newInputId = this.pfx + 'new';
@ -264,6 +265,7 @@ define(['backbone', 'text!./../template/classTags.html', './ClassTagView'],
label: this.config.label, label: this.config.label,
statesLabel: this.config.statesLabel, statesLabel: this.config.statesLabel,
pfx: this.pfx, pfx: this.pfx,
ppfx: this.ppfx
})); }));
this.$input = this.$el.find('input#' + this.newInputId); this.$input = this.$el.find('input#' + this.newInputId);
this.$addBtn = this.$el.find('#' + this.addBtnId); this.$addBtn = this.$el.find('#' + this.addBtnId);

28
styles/css/main.css

@ -2687,7 +2687,7 @@ $fontColorActive: #4f8ef7;
.gjs-btn-prim:active { .gjs-btn-prim:active {
background-color: rgba(255, 255, 255, 0.1); } background-color: rgba(255, 255, 255, 0.1); }
.gjs-input { .gjs-input, .gjs-select {
background-color: rgba(0, 0, 0, 0.3); background-color: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(0, 0, 0, 0.1); border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 2px; border-radius: 2px;
@ -2696,6 +2696,21 @@ $fontColorActive: #4f8ef7;
color: #ddd; color: #ddd;
padding: 0.5em 1em; } padding: 0.5em 1em; }
div.gjs-select {
padding: 0; }
.gjs-select:-moz-focusring,
.gjs-select select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 rgba(255, 255, 255, 0.7); }
.gjs-input:focus, .gjs-select:focus,
.gjs-button:focus,
.gjs-btn-prim:focus,
.gjs-select:focus,
.gjs-select select:focus {
outline: none; }
/************* CANVAS ****************/ /************* CANVAS ****************/
.gjs-cv-canvas { .gjs-cv-canvas {
background-color: rgba(0, 0, 0, 0.15); background-color: rgba(0, 0, 0, 0.15);
@ -3202,10 +3217,8 @@ ol.example li.placeholder:before {
background: none; background: none;
border: none; border: none;
color: rgba(255, 255, 255, 0.7); color: rgba(255, 255, 255, 0.7);
color: transparent;
width: 100%; width: 100%;
padding: 2px 10px 2px 0; padding: 2px 10px 2px 2px;
text-shadow: 0 0 0 rgba(255, 255, 255, 0.7);
position: relative; position: relative;
z-index: 1; z-index: 1;
-webkit-appearance: none; -webkit-appearance: none;
@ -3213,6 +3226,11 @@ ol.example li.placeholder:before {
appearance: none; } appearance: none; }
.gjs-sm-sector .gjs-sm-field select::-ms-expand, .gjs-clm-tags .gjs-sm-field select::-ms-expand, .gjs-sm-sector .gjs-clm-field select::-ms-expand, .gjs-clm-tags .gjs-clm-field select::-ms-expand { .gjs-sm-sector .gjs-sm-field select::-ms-expand, .gjs-clm-tags .gjs-sm-field select::-ms-expand, .gjs-sm-sector .gjs-clm-field select::-ms-expand, .gjs-clm-tags .gjs-clm-field select::-ms-expand {
display: none; } display: none; }
.gjs-sm-sector .gjs-sm-field select:-moz-focusring, .gjs-clm-tags .gjs-sm-field select:-moz-focusring, .gjs-sm-sector .gjs-clm-field select:-moz-focusring, .gjs-clm-tags .gjs-clm-field select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 rgba(255, 255, 255, 0.7); }
.gjs-sm-sector .gjs-sm-field select:focus, .gjs-clm-tags .gjs-sm-field select:focus, .gjs-sm-sector .gjs-clm-field select:focus, .gjs-clm-tags .gjs-clm-field select:focus, .gjs-sm-sector .gjs-sm-field input:focus, .gjs-clm-tags .gjs-sm-field input:focus, .gjs-sm-sector .gjs-clm-field input:focus, .gjs-clm-tags .gjs-clm-field input:focus {
outline: none; }
.gjs-sm-sector .gjs-sm-field .gjs-sm-unit, .gjs-clm-tags .gjs-sm-field .gjs-sm-unit, .gjs-sm-sector .gjs-clm-field .gjs-sm-unit, .gjs-clm-tags .gjs-clm-field .gjs-sm-unit { .gjs-sm-sector .gjs-sm-field .gjs-sm-unit, .gjs-clm-tags .gjs-sm-field .gjs-sm-unit, .gjs-sm-sector .gjs-clm-field .gjs-sm-unit, .gjs-clm-tags .gjs-clm-field .gjs-sm-unit {
position: absolute; position: absolute;
right: 10px; right: 10px;
@ -3729,7 +3747,7 @@ ol.example li.placeholder:before {
z-index: 5; } z-index: 5; }
#gjs-rte-toolbar .gjs-rte-btn { #gjs-rte-toolbar .gjs-rte-btn {
padding: 5px; padding: 5px;
width: 25px; min-width: 25px;
border-right: 1px solid rgba(0, 0, 0, 0.3); border-right: 1px solid rgba(0, 0, 0, 0.3);
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;

34
styles/scss/main.scss

@ -188,7 +188,25 @@ $fontV: 5;//random(1000)
color: $fontColor; color: $fontColor;
padding: 0.5em 1em; padding: 0.5em 1em;
} }
.#{$app-prefix}select{
@extend .#{$app-prefix}input;
}
div.#{$app-prefix}select{
padding: 0;
}
.#{$app-prefix}select:-moz-focusring,
.#{$app-prefix}select select:-moz-focusring{
color: transparent;
text-shadow: 0 0 0 $mainLhlColor;
}
.#{$app-prefix}input:focus,
.#{$app-prefix}button:focus,
.#{$app-prefix}btn-prim:focus,
.#{$app-prefix}select:focus,
.#{$app-prefix}select select:focus {
outline: none;
}
/************* CANVAS ****************/ /************* CANVAS ****************/
.#{$cv-prefix}canvas { .#{$cv-prefix}canvas {
background-color: rgba(0, 0, 0, 0.15); background-color: rgba(0, 0, 0, 0.15);
@ -746,9 +764,8 @@ $arrowColor: $mainLhlColor; /*b1b1b1*/
select { select {
background: none; border: none; background: none; border: none;
color: $inputFontColor; color: $inputFontColor;
color: transparent; width: 100%;
width: 100%; padding: 2px 10px 2px 0; padding: 2px 10px 2px 2px;
text-shadow: 0 0 0 $inputFontColor;
position: relative; position: relative;
z-index:1; z-index:1;
@include appearance(none); @include appearance(none);
@ -756,6 +773,15 @@ $arrowColor: $mainLhlColor; /*b1b1b1*/
&::-ms-expand { display: none;} &::-ms-expand { display: none;}
} }
select:-moz-focusring{
color: transparent;
text-shadow: 0 0 0 $inputFontColor;
}
select:focus, input:focus{
outline: none;
}
.#{$sm-prefix}unit { .#{$sm-prefix}unit {
position: absolute; position: absolute;
right: 10px; top: 3px; right: 10px; top: 3px;
@ -1390,7 +1416,7 @@ $uploadPadding: 150px 10px;
.#{$rte-prefix}btn { .#{$rte-prefix}btn {
@extend .#{$app-prefix}color-main; @extend .#{$app-prefix}color-main;
padding: 5px; padding: 5px;
width: 25px; min-width: 25px;
border-right: 1px solid $mainDkColor; border-right: 1px solid $mainDkColor;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;

Loading…
Cancel
Save