From ce963d45cdf2703d2d4eedfa94394b178f86e0f1 Mon Sep 17 00:00:00 2001 From: Armen Kesablyan Date: Thu, 9 Feb 2012 17:11:38 -0800 Subject: More Text Tool Updates --- _scss/imports/scss/_Base.scss | 2 +- _scss/ninja.scss | 1 + css/ninja.css | 6 +- js/components/button.reel/button.js | 2 +- .../text-properties.reel/text-properties.css | 28 +-- .../text-properties.reel/text-properties.html | 204 +++++++++++---------- .../text-properties.reel/text-properties.js | 162 +++++++++++----- js/tools/TextTool.js | 2 + .../labs/rich-text-editor.reel/rich-text-editor.js | 166 +++++++++++------ 9 files changed, 358 insertions(+), 215 deletions(-) diff --git a/_scss/imports/scss/_Base.scss b/_scss/imports/scss/_Base.scss index 8a743174..a800610d 100644 --- a/_scss/imports/scss/_Base.scss +++ b/_scss/imports/scss/_Base.scss @@ -134,7 +134,7 @@ button.nj-skinned { cursor: pointer; text-shadow: 1px 1px 1px $color-app-shadow } -button.nj-skinned:active { +button.nj-skinned:active, button.nj-skinned.active { background-image: -webkit-linear-gradient(top, $color-formgrad-bottom 0%, $color-formgrad-top 100%); } button.nj-skinned:hover { diff --git a/_scss/ninja.scss b/_scss/ninja.scss index 11c04afb..4cc7301f 100755 --- a/_scss/ninja.scss +++ b/_scss/ninja.scss @@ -36,6 +36,7 @@ body { } + // Codemirror //@import "imports/codemirror/_codemirror"; //@import "imports/codemirror/_javascript"; diff --git a/css/ninja.css b/css/ninja.css index 8ce60a10..3776b1d5 100644 --- a/css/ninja.css +++ b/css/ninja.css @@ -36,7 +36,7 @@ input[type="search"].nj-skinned::-webkit-search-cancel-button:after { content: " button.nj-skinned { font-size: 9px; cursor: pointer; display: block; border: 0px; margin: 0px; padding: 4px; border: 1px #313131 solid; background-color: #474747; background-image: -webkit-linear-gradient(top, #505050 0%, #3c3c3c 100%); border-radius: 4px; color: white; text-transform: uppercase; cursor: pointer; text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); } -button.nj-skinned:active { background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #505050 100%); } +button.nj-skinned:active, button.nj-skinned.active { background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #505050 100%); } button.nj-skinned:hover { -webkit-box-shadow: 0px 0px 3px #b4b4b4; } @@ -212,6 +212,10 @@ body { position: absolute; margin: 0px; width: 100%; height: 100%; background-co #mainContent .CodeMirror-scroll { height: 100%; overflow: scroll; overflow-x: auto; overflow-y: auto; } +.montage-editor-frame { position: absolute; z-index: 7; top: 0; left: 0; display: none; -webkit-user-select: initial; } + +.montage-editor { padding: 0px; word-wrap: normal; } + .panelContainer { margin: 0px; padding: 0px 0px; position: relative; overflow: auto; } .panelDisclosureIcon { background-image: url("../images/panels/panelDisclosureIcon.png"); background-repeat: no-repeat; width: 16px; height: 16px; float: left; -webkit-transition-property: rotate; -webkit-transition-duration: 0.2s; -webkit-transition-timing-function: linear; padding-right: 2px; } diff --git a/js/components/button.reel/button.js b/js/components/button.reel/button.js index ce5ac1af..2d26c8b4 100644 --- a/js/components/button.reel/button.js +++ b/js/components/button.reel/button.js @@ -179,7 +179,7 @@ var Button = exports.Button = Montage.create(Component, { value: function() { if(this.isToggleButton) { - if(this._value) + if(this._value === true) { this.element.classList.remove(this.offState); this.element.classList.add(this.onState); diff --git a/js/components/tools-properties/text-properties.reel/text-properties.css b/js/components/tools-properties/text-properties.reel/text-properties.css index 2eb608d3..6aa61812 100644 --- a/js/components/tools-properties/text-properties.reel/text-properties.css +++ b/js/components/tools-properties/text-properties.reel/text-properties.css @@ -5,31 +5,33 @@ */ .optionsTextTool { - display: -webkit-box; - -webkit-box-orient:horizontal; - -webkit-box-align: stretch; - padding: 5px; + padding: 6px; } - -.optionsTextTool > * { - -webkit-box-flex:0; +.optionsTextTool .btnGroup { + padding: 0px 8px; } -.optionsTextTool .button { - width: auto; - +.optionsTextTool > *, .optionsTextTool .btnGroup > * { + float:left; } -.optionsTextTool .hottextunit { - padding-top:5px; +.optionsTextTool button { + width: auto; + padding: 4px 8px !important; + margin-left:4px; } .optionsTextTool .label, .optionsTextTool .hottextunit { - float:none; font-size:11px; } .optionsTextTool .fontSelection { width:100px; +} + +.optionsTextTool .fontColor { + width: 20px; + height: 18px; + margin: 2px 6px; } \ No newline at end of file diff --git a/js/components/tools-properties/text-properties.reel/text-properties.html b/js/components/tools-properties/text-properties.reel/text-properties.html index 14123b12..7ded1236 100644 --- a/js/components/tools-properties/text-properties.reel/text-properties.html +++ b/js/components/tools-properties/text-properties.reel/text-properties.html @@ -77,41 +77,30 @@ }, "fontSize": { - "module": "js/components/hottextunit.reel", - "name": "HotTextUnit", + "module": "js/components/combobox.reel", + "name": "Combobox", "properties": { "element": {"#": "fontSize"}, - "value": 12, "identifier": "fontSize" }, "listeners": [ { "type": "change", "listener": {"@": "owner"} - }, - { - "type": "changing", - "listener": {"@": "owner"} } ] }, - - "fontColor": { - "module" : "js/components/ui/color-chip.reel", - "name" : "ColorChip", - "properties" : { - "element" : {"#": "fontColor"}, - "mode": "chip" - } - }, + "btnBold": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "btnBold"}, - "_isToggleButton": true, - "identifier": "btnBold" + "pressedClass": "active", + "preventFocus": true, + "identifier": "btnBold", + "label": "B" }, "listeners": [ { @@ -121,12 +110,14 @@ ] }, "btnItalic": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "btnItalic"}, - "_isToggleButton": true, - "identifier": "btnItalic" + "pressedClass": "active", + "preventFocus": true, + "identifier": "btnItalic", + "label": "I" }, "listeners": [ { @@ -136,12 +127,14 @@ ] }, "btnUnderline": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "btnUnderline"}, - "_isToggleButton": true, - "identifier": "btnUnderline" + "pressedClass": "active", + "preventFocus": true, + "identifier": "btnUnderline", + "label": "U" }, "listeners": [ { @@ -151,12 +144,14 @@ ] }, "btnStrikethrough": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "btnStrikethrough"}, - "_isToggleButton": true, - "identifier": "btnStrikethrough" + "pressedClass": "active", + "preventFocus": true, + "identifier": "btnStrikethrough", + "label": "S" }, "listeners": [ { @@ -165,28 +160,16 @@ } ] }, - "txtLink": { - "module": "js/components/textfield.reel", - "name": "TextField", - "properties": { - "element": {"#": "txtLink"} - } - }, - "linkTarget": { - "module": "js/components/combobox.reel", - "name": "Combobox", - "properties": { - "element": {"#": "linkTarget"} - } - }, - + "alignLeft": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "alignLeft"}, - "_isToggleButton": true, - "identifier": "alignLeft" + "pressedClass": "active", + "preventFocus": true, + "identifier": "alignLeft", + "label": "Left" }, "listeners": [ { @@ -196,12 +179,14 @@ ] }, "alignCenter": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "alignCenter"}, - "_isToggleButton": true, - "identifier": "alignCenter" + "pressedClass": "active", + "preventFocus": true, + "identifier": "alignCenter", + "label": "Center" }, "listeners": [ { @@ -211,12 +196,14 @@ ] }, "alignRight": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "alignRight"}, - "_isToggleButton": true, - "identifier": "alignRight" + "pressedClass": "active", + "preventFocus": true, + "identifier": "alignRight", + "label": "Right" }, "listeners": [ { @@ -226,12 +213,14 @@ ] }, "alignJustify": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "alignJustify"}, - "_isToggleButton": true, - "identifier": "alignJustify" + "pressedClass": "active", + "preventFocus": true, + "identifier": "alignJustify", + "label": "Justify" }, "listeners": [ { @@ -241,26 +230,48 @@ ] }, "indent": { - "module": "js/components/button.reel", + "module": "montage/ui/button.reel", "name": "Button", "properties": { - "element": {"#": "indent"} - } + "element": {"#": "indent"}, + "pressedClass": "active", + "preventFocus": true, + "identifier": "outdent", + "label": ">>" + }, + "listeners": [ + { + "type": "action", + "listener": {"@": "owner"} + } + ] }, "outdent": { - "module": "js/components/button.reel", + "module": "montage/ui/button.reel", "name": "Button", "properties": { - "element": {"#": "outdent"} - } + "element": {"#": "outdent"}, + "pressedClass": "active", + "preventFocus": true, + "identifier": "<<", + "label": "<<" + }, + "listeners": [ + { + "type": "action", + "listener": {"@": "owner"} + } + ] }, "bulletedList": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "bulletedList"}, - "_isToggleButton": true, - "identifier": "bulletedList" + "pressedClass": "active", + "preventFocus": true, + "identifier": "bulletedList", + "label": "• • •" }, "listeners": [ { @@ -270,12 +281,14 @@ ] }, "numberedList": { - "module": "js/components/button.reel", - "name": "Button", + "module": "montage/ui/toggle-button.reel", + "name": "ToggleButton", "properties": { "element": {"#": "numberedList"}, - "_isToggleButton": true, - "identifier": "numberedList" + "pressedClass": "active", + "preventFocus": true, + "identifier": "numberedList", + "label": "1 2 3" }, "listeners": [ { @@ -301,24 +314,27 @@ - - - - - - - - -
- - - - +
+
+ + + + +
+
+ + + + +
+
+ + +
+
+ +
- - - -
diff --git a/js/components/tools-properties/text-properties.reel/text-properties.js b/js/components/tools-properties/text-properties.reel/text-properties.js index dac30da0..55274322 100644 --- a/js/components/tools-properties/text-properties.reel/text-properties.js +++ b/js/components/tools-properties/text-properties.reel/text-properties.js @@ -32,30 +32,9 @@ exports.TextProperties = Montage.create(ToolProperties, { prepareForDraw: { value: function() { - this.linkTarget.items = ["Target","_blank","_self","_parent", "_top"]; - this.fontSettings.label = "Settings"; - this.btnBold.label = "Bold"; - this.btnItalic.label = "Italic"; - this.btnUnderline.label = "Underline"; - this.btnStrikethrough.label = "Strikethrough"; - this.alignLeft.label = "Left"; - this.alignCenter.label = "Center"; - this.alignRight.label = "Right"; - this.alignJustify.label = "Justify"; - this.indent.label = "-->" - this.outdent.label = "<--"; - this.numberedList.label = "1 2 3"; - this.bulletedList.label = "• • •"; this.fontSelection.items = ["Arial", "Arial Black", "Courier New", "Garamond", "Georgia", "Open Sans", "Tahoma", "Times New Roman", "Trebuchet MS", "Verdana"]; this.tagType.items = ["div", "span", "p", "section", "article", "h1", "h2", "h3", "h4", "h5", "h6"]; - - - this.application.ninja.stage.textTool.addEventListener("editorSelect", this, false); - Object.defineBinding(this.application.ninja.stage.textTool.states, "bold", { - boundObject: this.btnBold, - boundObjectPropertyPath: "value" - }); - + this.fontSize.items = ["8pt","10pt","12pt","14pt","18pt","24pt","36pt"]; } }, @@ -65,10 +44,6 @@ exports.TextProperties = Montage.create(ToolProperties, { } }, - defaultFontSize: { - value: "12px" - }, - _subPrepare: { value: function() { //this.divElement.addEventListener("click", this, false); @@ -82,31 +57,27 @@ exports.TextProperties = Montage.create(ToolProperties, { } }, - handleFontSizeChange: { - - }, - handleBtnBoldAction: { value: function(e) { - this.application.ninja.stage.textTool.doAction("bold", true); + this.application.ninja.stage.textTool.doAction("bold"); } }, handleBtnItalicAction: { value: function(e) { - this.application.ninja.stage.textTool.doAction("italic", true); + this.application.ninja.stage.textTool.doAction("italic"); } }, handleBtnUnderlineAction: { value: function(e) { - this.application.ninja.stage.textTool.doAction("underline", true); + this.application.ninja.stage.textTool.doAction("underline"); } }, handleBtnStrikethroughAction: { value: function(e) { - this.application.ninja.stage.textTool.doAction("strikethrough", true); + this.application.ninja.stage.textTool.doAction("strikethrough"); } }, @@ -116,7 +87,7 @@ exports.TextProperties = Montage.create(ToolProperties, { this.alignCenter.value = false; this.alignRight.value = false; this.alignJustify.value = false; - this.application.ninja.stage.textTool.doAction("justifyLeft", true); + this.application.ninja.stage.textTool.doAction("justifyleft"); } }, @@ -126,7 +97,7 @@ exports.TextProperties = Montage.create(ToolProperties, { //this.alignCenter.value = false; this.alignRight.value = false; this.alignJustify.value = false; - this.application.ninja.stage.textTool.doAction("justifyCenter", true); + this.application.ninja.stage.textTool.doAction("justifycenter"); } }, @@ -136,7 +107,7 @@ exports.TextProperties = Montage.create(ToolProperties, { this.alignCenter.value = false; //this.alignRight.value = false; this.alignJustify.value = false; - this.application.ninja.stage.textTool.doAction("justifyRight", true); + this.application.ninja.stage.textTool.doAction("justifyright"); } }, @@ -146,37 +117,123 @@ exports.TextProperties = Montage.create(ToolProperties, { this.alignCenter.value = false; this.alignRight.value = false; //this.alignJustify.value = false; - this.application.ninja.stage.textTool.doAction("strikethrough", null); + this.application.ninja.stage.textTool.doAction("justifyfull"); } }, handleIndentAction: { value: function(e) { - this.application.ninja.stage.textTool.doAction("indent", null); + this.application.ninja.stage.textTool.doAction("indent"); } }, handleOutdentAction: { value: function(e) { - this.application.ninja.stage.textTool.doAction("outdent", null); + this.application.ninja.stage.textTool.doAction("outdent"); } }, handleFontSizeChange: { value: function(e) { - + //We need the index of whats selected. This is a temporary solution til we can have a variable amount for font-size. + for( var i = 0; i < this.fontSize.items.length; i++) { + if (this.fontSize.value === this.fontSize.items[i]) { + this.application.ninja.stage.textTool.doAction("fontsize", (i +1)); + break; + } + } } }, - handleFontSizeChanging: { - value: function(e) { + defineInitialProperties: { + value: function() { + if (!this.initialized) { + + //Setup Font Selection tool + this.fontColor = this.element.getElementsByClassName("fontColor")[0]; + this.fontColor.props = {side: 'top', align: 'center', wheel: true, palette: true, gradient: false, image: false, nocolor: true, offset: -80}; + this.application.ninja.colorController.addButton("chip", this.fontColor); + this.fontColor.color('rgb', {wasSetByCode: true, type: 'change', color: {r: 0, g: 0, b: 0}, css: 'rgb(0,0,0)'}); + this.fontColor.addEventListener("change",this.handleFontColorChange.bind(this),false); + + this.application.ninja.stage.textTool.addEventListener("editorSelect", this, false); + + Object.defineBinding(this.btnBold, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.bold", + boundValueMutator: this.validatePressed, + oneway: true + }); + + Object.defineBinding(this.btnItalic, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.italic", + boundValueMutator: this.validatePressed, + oneway: true + }); + + Object.defineBinding(this.btnUnderline, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.underline", + boundValueMutator: this.validatePressed, + oneway: true + }); + + Object.defineBinding(this.btnStrikethrough, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.strikethrough", + boundValueMutator: this.validatePressed, + oneway: true + }); + Object.defineBinding(this.alignLeft, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.justifyleft", + boundValueMutator: this.validatePressed, + oneway: true + }); + + Object.defineBinding(this.alignCenter, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.justifycenter", + boundValueMutator: this.validatePressed, + oneway: true + }); + + Object.defineBinding(this.alignRight, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.justifyright", + boundValueMutator: this.validatePressed, + oneway: true + }); + + Object.defineBinding(this.alignJustify, "pressed", { + boundObject: this.application.ninja.stage.textTool, + boundObjectPropertyPath: "states.justifyfull", + boundValueMutator: this.validatePressed, + oneway: true + }); + + this.initialized = true; + } + + } + }, + + validatePressed: { + value: function(val) { + if (val == "true") return true; else return false } }, + initialized: { + value: false + }, + handleFontSelectionChange: { value: function() { this.application.ninja.stage.textTool.doAction("fontname", this.fontSelection.value); + this.application.ninja.stage.textTool.element.focus(); } }, @@ -184,16 +241,29 @@ exports.TextProperties = Montage.create(ToolProperties, { value: function(e) { //this.numberedList.value = false; this.bulletedList.value = false; - this.application.ninja.stage.textTool.doAction("insertnumberedlist", true); + this.application.ninja.stage.textTool.doAction("insertorderedlist"); + this.application.ninja.stage.textTool.element.focus(); } }, - handleOrderedListAction: { + handleBulletedListAction: { value: function(e) { this.numberedList.value = false; //this.bulletedList.value = false; - this.application.ninja.stage.textTool.doAction("insertnumberedlist", true); + this.application.ninja.stage.textTool.doAction("insertunorderedlist"); + this.application.ninja.stage.textTool.element.focus(); } }, + handleFontColorChange: { + value: function(e) { + this.application.ninja.stage.textTool.element.style.color = e._event.color.css; + this.application.ninja.stage.textTool.element.focus(); + + //this.application.ninja.stage.textTool.doAction("forecolor",e._event.color.css); + + } + } + + }); \ No newline at end of file diff --git a/js/tools/TextTool.js b/js/tools/TextTool.js index 910a9eef..760af55b 100644 --- a/js/tools/TextTool.js +++ b/js/tools/TextTool.js @@ -39,6 +39,7 @@ exports.TextTool = Montage.create(DrawingTool, { HandleLeftButtonDown: { value: function(event) { + this.selectedElement = null; this.startDraw(event); } }, @@ -157,6 +158,7 @@ exports.TextTool = Montage.create(DrawingTool, { if(wasSelected) { NJevent("enableStageMove"); + this.options.defineInitialProperties(); this.application.ninja.stage.stageDeps.snapManager.setupDragPlaneFromPlane( workingPlane ); } else { this.selectedElement = null; diff --git a/node_modules/labs/rich-text-editor.reel/rich-text-editor.js b/node_modules/labs/rich-text-editor.reel/rich-text-editor.js index 3fece294..b88d5868 100644 --- a/node_modules/labs/rich-text-editor.reel/rich-text-editor.js +++ b/node_modules/labs/rich-text-editor.reel/rich-text-editor.js @@ -12,6 +12,8 @@ var Montage = require("montage/core/core").Montage, MutableEvent = require("montage/core/event/mutable-event").MutableEvent, Resizer = require("node_modules/labs/rich-text-editor.reel/rich-text-resizer").Resizer, Sanitizer = require("node_modules/labs/rich-text-editor.reel/rich-text-sanitizer").Sanitizer; + Point = require("montage/core/geometry/point").Point; + /** @class module:"montage/ui/rich-text-editor.reel".RichTextEditor @@ -148,7 +150,6 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ if (this._resizer) { this._needsHideResizer = true; } - if (this._sanitizer) { value = this._sanitizer.willSetValue(value, this._uniqueId); } @@ -296,7 +297,9 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ states: { enumerable: true, get: function() { - this.updateStates(); + if (this._statesDirty || !this._states) { + this.updateStates(); + } return this._states; } }, @@ -313,7 +316,6 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ action, states, state, - statesChanged = false, hasFocus = this._hasFocus; if (this._states == null || this._statesDirty) { @@ -339,16 +341,8 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ if (states[key] !== state) { states[key] = state; - statesChanged = true; } } - - if (statesChanged) { - this._states = states; - // As we do not use a setter, we need to manually dispatch a change event - this.dispatchEvent(MutableEvent.changeEventForKeyAndValue("states" , this._states)); - } - } } @@ -388,6 +382,10 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ enumerable: false, value: { bold: {enabled: true, needsValue:false, status: true}, + justifyleft: {enabled: true, needsValue:false, status: true}, + justifycenter: {enabled: true, needsValue:false, status: true}, + justifyright: {enabled: true, needsValue:false, status: true}, + justifyfull: {enabled: true, needsValue:false, status: true}, italic: {enabled: true, needsValue:false, status: true}, underline: {enabled: true, needsValue:false, status: true}, strikethrough: {enabled: true, needsValue:false, status: true}, @@ -536,6 +534,7 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ } this._adjustPadding(); + this._markDirty(); delete this._needsResetContent; } @@ -1011,6 +1010,12 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ event.preventDefault(); event.stopPropagation(); + // Remove the link popup + if (this._needsActiveLinkOn === false && this._activeLink) { + this._needsActiveLinkOn = null; + this.needsDraw = true; + } + // Update the caret if (event.x !== this._dragOverX || event.y !== this._dragOverY) { this._dragOverX = event.x; @@ -1365,9 +1370,11 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ thisRef._dispatchEditorEvent("editorChange"); }; - // Clear the cached value - this._dirtyValue = true; - this._dirtyTextValue = true; + if (!this._needsResetContent) { + // Clear the cached value + this._dirtyValue = true; + this._dirtyTextValue = true; + } if (!this._forceUpdateValuesTimeout) { this._forceUpdateValuesTimeout = setTimeout(updateValues, 1000); @@ -1519,60 +1526,85 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ popup, parentNode, nextSibling, - w, h, l, t, docH, docW, - maxWidth, + w, h, l, t, + left, right, leftWidth, rightWidth, style, popupExtraWidth = 53; // This is depending of the popup css + var offsetLeft, + offsetTop, + _findOffset = function(node) { + offsetLeft = node.offsetLeft; + offsetTop = node.offsetTop; + + while ((node = node.offsetParent) && node != editorElement) { + offsetLeft += node.offsetLeft; + offsetTop += node.offsetTop; + } + }; + + if (this._activeLink != element) { this._hideActiveLink(); if (element) { + + _findOffset(element); + parentNode = element.parentNode; nextSibling = element.nextSibling; - // sanity check: make sure we don't already have a popup installed for that element - if (!nextSibling || nextSibling.tagName !== "DIV" || !nextSibling.classList.contains("montage-link-popup")) { + oh = editorElement.offsetHeight; + ow = editorElement.offsetWidth; + st = editorElement.scrollTop; + sl = editorElement.scrollLeft; - oh = editorElement.offsetHeight; - ow = editorElement.offsetWidth; - st = editorElement.scrollTop; - sl = editorElement.scrollLeft; + w = element.offsetWidth -1, + h = element.offsetHeight -1, + l = offsetLeft, + t = offsetTop, - w = element.offsetWidth -1, - h = element.offsetHeight -1, - l = element.offsetLeft, - t = element.offsetTop, + style = ""; - style = ""; - if (t > 60 && t - st + h + 50 > oh) { - style = "bottom: " + (oh - t + 5) + "px;"; - } else { - style = "top: " + (t + h + 5 ) + "px;"; - } + // Should we display the popup on top or below the element? + if (t > 60 && t - st + h + 50 > oh) { + style = "bottom: " + (oh - t + 5) + "px;"; + } else { + style = "top: " + (t + h + 5 ) + "px;"; + } - var maxWidth = ow - l - popupExtraWidth + sl; - if (maxWidth < 150) { - maxWidth = 150; - } - if (l + maxWidth + popupExtraWidth - sl > ow) { - l = ow - maxWidth - popupExtraWidth + sl; + // Should we display the popup aligned on the left or right of the element? + left = sl; + right = sl + ow; + leftWidth = right - l; + rightWidth = l + w - left; + + if (leftWidth > rightWidth) { + //Let's align the popup to the left of the element or to the far left + if (leftWidth < 150) { + style += " left: " + (left + 5) + "px;"; + style += " max-width: " + (ow - 10 - popupExtraWidth) + "px;"; + } else { + style += " left: " + (left + l) + "px;"; + style += " max-width: " + (leftWidth - 5 - popupExtraWidth) + "px;"; } - if (l < 3) { - l = 3; + } else { + if (rightWidth < 150) { + style += " right: " + (left + 6) + "px;"; + style += " max-width: " + (ow - 10 - popupExtraWidth) + "px;"; + } else { + style += " right: " + (right - (left + l + w + 10)) + "px;"; + style += " max-width: " + (rightWidth - popupExtraWidth) + "px;"; } - style += " left: " + l + "px;" - style += "max-width: " + maxWidth + "px;" - + } - popup = document.createElement("DIV"); - popup.className = "montage-link-popup"; - popup.setAttribute("contentEditable", "false"); - popup.setAttribute("style", style); - popup.innerHTML = '' + element.href + ''; - parentNode.insertBefore(popup, nextSibling); + popup = document.createElement("DIV"); + popup.className = "montage-link-popup"; + popup.setAttribute("contentEditable", "false"); + popup.setAttribute("style", style); + popup.innerHTML = '' + element.href + ''; + editorElement.insertBefore(popup, null); - this._activeLink = element; - } + this._activeLink = element; } } } @@ -1642,25 +1674,41 @@ exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/ value: function(contentNode) { var result = "", textNodeContents = [], + newLines = "", + gotText = false, _walkNode = function(node) { - var child; + var nodeName = node.nodeName, + child - if (node.nodeName == "STYLE") { + if (nodeName.match(/^(TITLE|STYLE|SCRIPT)$/)) { return; } - // TODO: We need to insert newlines after block elements (and remove any newline coming from HTML) + if (gotText && nodeName.match(/^(P|DIV|BR|TR|LI)$/)) { + newLines += "\n"; + } + for (child = node.firstChild; child; child = child.nextSibling) { - if (child.nodeType == 3) { // text node - textNodeContents.push(child.nodeValue); + if (child.nodeType == 3) { // text node + textNodeContents.push(newLines + child.nodeValue); + newLines = ""; + gotText = true; } else { - _walkNode(child); + if (child.nodeName != "BR" || child.nextSibling) { + _walkNode(child); + } } } + + if (gotText && nodeName.match(/^(TABLE|UL|OL)$/)) { + newLines += "\n"; + } }; - _walkNode(contentNode); - result = textNodeContents.join(""); + if (contentNode) { + _walkNode(contentNode); + result = textNodeContents.join(""); + } return result; } -- cgit v1.2.3