/**
* @fileOverview
* 컨텐츠를 가지고 있는 편집 영역을 수정, 관리하는 Trex.Canvas 관련 Source로
* 대부분 각 panel들에게 행동들을 위임한다.
* 편집 영역 = panel = TextPanel, HtmlPanel, WysiwygPanel
*/
(function(Trex) {
var QUERY_TRIGGER_KEYCODES = new $tx.Set(13, 8, 32, 33, 34, 37, 38, 39, 40, 46);
var shouldTriggerQuery = function(keyCode) {
return QUERY_TRIGGER_KEYCODES.contains(keyCode);
};
TrexConfig.add({
"canvas": {
doctype: "auto", // edge
mode: ["text", "html", "source"],
styles: {
color: "#333333",
fontFamily: "돋움",
fontSize: "9pt",
backgroundColor: "#ffffff",
lineHeight: "1.5",
padding: "8px"
},
pMarginZero: true,
selectedMode: "html",
readonly: _FALSE,
initHeight: 400,
minHeight: 200,
ext: 'html',
param: "",
newlinepolicy: "p",
showGuideArea: _TRUE,
convertingText: _TRUE,
escapeTextModeContents: _TRUE,
removeTextModeBr: _FALSE,
respectVisibilityInDesign: _TRUE
}
}, function(root) {
var _config = TrexConfig.get('canvas', root);
var _evConfig = root.events;
_config.initializedId = root.initializedId || '';
_config.useHotKey = _evConfig.useHotKey;
var _switcher = TrexConfig.getTool('switcher', root);
if (Trex.available(_switcher, "switcher" + _config.initializedId)) {
_config.mode = _switcher.options.pluck("data");
}
var _fontfamily = TrexConfig.getTool('fontfamily', root);
if (Trex.available(_fontfamily, "fontfamily" + _config.initializedId)) {
if(_fontfamily.webfont && _fontfamily.webfont.use) {
_config.webfont = _fontfamily.webfont;
_config.webfont.options.each(function(element) {
element.url = TrexConfig.getUrl(element.url);
});
}
}
var _resizer = TrexConfig.get('resizer', root);
if (_resizer) {
_config.minHeight = _resizer.minHeight;
}
/**
* 에디터통합 버전으로 한메일 배포시에는
* 윗줄 주석해제, 아랫줄 삭제
*/
//_config.wysiwygUrl = TrexConfig.getUrl(["#host#path/pages/daumx/", "wysiwyg_", (_config.serviceWysiwyg || "" ), ((_config.doctype == "html") ? "html" : "xhtml"), ".", (_config.ext ? _config.ext : "html"), "?prefix=" + root.initializedId, "&", _config.param].join(""));
_config.wysiwygUrl = TrexConfig.getUrl([(_config.wysiwygPath || "#host#path/pages/daumx/"), "wysiwyg_", (_config.serviceWysiwyg || "" ), ((_config.doctype == "html") ? "html" : "xhtml"), ".", (_config.ext ? _config.ext : "html"), "?prefix=" + root.initializedId, "&", _config.param].join(""));
/**
* doctype 결정기준
*/
if (_config.doctype == 'auto') {
if ($tx.msie && $tx.msie_quirks) {
_config.doctype = 'quirks';
} else {
_config.doctype = 'edge';
}
}
});
TrexConfig.add({
"size": {
}
});
/**
* 컨텐츠를 가지고 있는 편집 영역을 수정, 관리하는 Trex.Canvas 객체로
* 대부분 각 panel들에게 행동들을 위임한다.
* 각각의 panel들은 해당 Processor들을 포함한다.
* 편집 영역 = panel = TextPanel, HtmlPanel, WysiwygPanel
*
* @class
* @extends Trex.I.JobObservable Trex.I.KeyObservable
* @param {Object} editor
* @param {Object} config
*/
Trex.Canvas = Trex.Class.create( /** @lends Trex.Canvas.prototype */{
/** @ignore */
$const: {
/** @name Trex.Canvas.__TEXT_MODE */
__TEXT_MODE: "text",
/** @name Trex.Canvas.__HTML_MODE */
__HTML_MODE: "source",
/** @name Trex.Canvas.__WYSIWYG_MODE */
__WYSIWYG_MODE: "html",
__WYSIWYG_PADDING: 8,
__IMAGE_PADDING: 5
},
/** @ignore */
$mixins: [Trex.I.JobObservable, Trex.I.KeyObservable, Trex.I.ElementObservable, Trex.I.MouseoverObservable],
/** Editor instance */
editor: _NULL,
/** Canvas Dom element, Generally $tx('tx_canvas') */
elContainer: _NULL,
/** Canvas Config */
config: _NULL,
/** History Instance for redo/undo */
history: _NULL,
/**
* Panels 객체
* @private
* @example
* canvas.panels['html']
* canvas.panels['source']
* canvas.panels['text']
*/
panels: _NULL,
initialize: function(editor, rootConfig) {
this.editor = editor;
var _config = this.config = TrexConfig.get('canvas', rootConfig);
var _initializedId = ((rootConfig.initializedId) ? rootConfig.initializedId : "");
this.elContainer = $tx("tx_canvas" + _initializedId);
this.wysiwygEl = $tx("tx_canvas_wysiwyg_holder" + _initializedId);
this.sourceEl = $tx("tx_canvas_source_holder" + _initializedId);
this.textEl = $tx("tx_canvas_text_holder" + _initializedId);
this.initConfig(rootConfig);
this.createPanel();
this.history = new Trex.History(this, _config);
this.setCanvasSize({
height: _config.initHeight
});
},
initConfig: function(rootConfig) {
var _config = this.config;
/**
* root config를 얻어온다.
* @private
* @returns {Object} root config
*/
this.getRootConfig = function() {
return rootConfig;
};
/**
* Canvas의 config를 가져온다.
* @returns {Object} config
*/
this.getConfig = function() {
return _config;
};
/**
* wysiwyg panel의 스타일 config를 가져온다.
* @param {String} name - 스타일명 optional
* @returns {Object} 스타일 config
* @example
* canvas.getStyleConfig();
*/
this.getStyleConfig = function(name) {
if(name) {
return _config.styles[name];
} else {
return _config.styles;
}
};
var _sizeConfig = TrexConfig.get('size', rootConfig);
this.measureWrapWidth = function() {
_sizeConfig.wrapWidth = this.getContainerWidth(); // TODO FTDUEDTR-1214
};
this.measureWrapWidth();
if(!_sizeConfig.contentWidth) {
_sizeConfig.contentWidth = _sizeConfig.wrapWidth;
}
_sizeConfig.contentPadding = _config.styles.padding.parsePx(); //15
/**
* canvas size 관련 config를 얻어온다.
* @returns {Object} size config
*/
this.getSizeConfig = function() {
return _sizeConfig;
};
},
getContainerWidth: function() {
return $tx.getDimensions(this.elContainer).width;
},
/**
* Panels 객체들을 초기화한다.
* @private
*/
createPanel: function() {
var _canvas = this;
var _config = this.config;
this.panels = {};
this.mode = _config.selectedMode || Trex.Canvas.__WYSIWYG_MODE;
if (this._isForceTextMode()) {
this.mode = Trex.Canvas.__TEXT_MODE;
}
var _panelCreater = {
"text": function(_config) {
return new Trex.Canvas.TextPanel(_canvas, _config);
},
"source": function(_config) {
return new Trex.Canvas.HtmlPanel(_canvas, _config);
},
"html": function(_config) {
return new Trex.Canvas.WysiwygPanel(_canvas, _config);
}
};
_config.mode.each(function(name) {
if (_panelCreater[name]) {
_canvas.panels[name] = _panelCreater[name](_config);
}
});
for(var _p in _canvas.panels) {
if (this.mode == _p) {
_canvas.panels[_p].show();
} else {
_canvas.panels[_p].hide();
}
}
_canvas.observeJob('canvas.panel.iframe.load', function(panelDoc) {
_canvas.fireJobs(Trex.Ev.__IFRAME_LOAD_COMPLETE, panelDoc);
});
},
_isForceTextMode: function() {
// 기존에는 아래의 조건이었으나 모바일에서의 호환은 아직 문제가 많아 제한함. 20140430
// ($tx.ios && $tx.ios_ver < 5) || ($tx.android && $tx.android_ver < 3)
return $tx.ios || $tx.android;
},
/**
* Canvas의 mode를 바꾸는것으로, 현재 활성화되어있는 panel을 변경한다.
* @param {String} newMode - 변경 할 mode에 해당하는 문자열
* @example
* editor.getCanvas().changeMode('html');
* editor.getCanvas().changeMode('source');
* editor.getCanvas().changeMode('text');
*/
changeMode: function(newMode) {
var _editor = this.editor;
var oldMode = this.mode;
if (oldMode == newMode) {
return;
}
if (this._isForceTextMode() && oldMode == Trex.Canvas.__TEXT_MODE) {
return;
}
var _oldPanel = this.panels[oldMode];
var _newPanel = this.panels[newMode];
if (!_oldPanel || !_newPanel) {
throw new Error("[Exception]Trex.Canvas : not suppored mode");
}
var _oldContent = _oldPanel.getContent();
var _content = _editor.getDocParser().getContentsAtChangingMode(_oldContent, oldMode, newMode);
if (oldMode == Trex.Canvas.__WYSIWYG_MODE) { //NOTE: #FTDUEDTR-366
if ($tx.msie_ver === 8) {
_oldPanel.hide();
} //prevent black screen from youtube iframe. #FTDUEDTR-1272
_oldPanel.setContent("");
try {
this.focusOnTop();
}catch(e){}
}
try { //#FTDUEDTR-1111
_newPanel.setContent(_content);
} catch (error) {
alert(' - Error: ' + error.message + '\n에디터 타입 변경에 실패하였습니다.\n잘못된 HTML이 있는지 확인해주세요.');
_oldPanel.setContent(_oldContent);
_oldPanel.show();
return;
}
this.mode = newMode;
this.fireJobs(Trex.Ev.__CANVAS_MODE_CHANGE, oldMode, newMode);
_newPanel.setPanelHeight(_oldPanel.getPanelHeight());
_newPanel.show();
_oldPanel.hide();
// FF2 bug:: When display is none, designMode can't be set to on
try {
if (newMode == "html" && !this.getPanel("html").designModeActivated && $tx.gecko) {
this.getPanel("html").el.contentDocument.designMode = "on";
this.getPanel("html").designModeActivated = _TRUE;
}
} catch (e) {
throw e;
}
},
/**
* 현재 panel에 포커스를 준다.
*/
focus: function() {
this.panels[this.mode].focus();
},
/**
* 본문의 처음으로 캐럿을 옮긴다. - Only Wysiwyg
*/
focusOnTop: function() {
this.getProcessor().focusOnTop();
},
/**
* 본문의 마지막으로 캐럿을 옮긴다. - Only Wysiwyg
*/
focusOnBottom: function() {
this.getProcessor().focusOnBottom();
},
/**
* canvas의 position을 가져온다.
* @returns {Object} position = { x: number, y:number }
*/
getCanvasPos: function() {
var _position = $tx.cumulativeOffset(this.elContainer);
return {
'x': _position[0],
'y': _position[1]
};
},
/**
* canvas의 height를 변경한다.
* @param {String} size (px)
* @example
* canvas.setCanvasSize({
* height: "500px"
* });
*/
setCanvasSize: function(size) {
if (this.panels[this.mode] && size.height) {
this.panels[this.mode].setPanelHeight(size.height);
} else {
throw new Error("[Exception]Trex.Canvas : argument has no property - size.height ");
}
},
/**
* @Deprecated use isWYSIWYG()
*/
canHTML: function() {
return this.isWYSIWYG();
},
isWYSIWYG: function () {
return this.mode === Trex.Canvas.__WYSIWYG_MODE;
},
/**
* panel 객체를 가져온다.
* @param {String} mode - 가져올 panel 모드명
* @returns {Object} - parameter에 해당하는 Panel
* @example
* this.getPanel('html').designModeActivated = true;
*/
getPanel: function(mode) {
if (this.panels[mode]) {
return this.panels[mode];
} else {
return _NULL;
}
},
/**
* 현재 활성화되어있는 panel 객체를 가져온다.
* @returns {Object} - 활성화되어있는 panel 객체
*/
getCurrentPanel: function() {
if (this.panels[this.mode]) {
return this.panels[this.mode];
} else {
return _NULL;
}
},
/**
* 현재 활성화되어있는 panel의 processor을 가져온다.
* @returns {Object} - 활성화되어있는 panel의 processor 객체
*/
getProcessor: function(mode) {
if ( !mode ){
return this.panels[this.mode].getProcessor();
}else{
return this.panels[mode].getProcessor();
}
},
/**
* 본문의 내용을 가져온다
* @returns {String}
*/
getContent: function() {
var _content = this.panels[this.mode].getContent();
if(_content) {
_content = _content.replace(Trex.__WORD_JOINER_REGEXP, ""); //NOTE: 서비스의 DB charset이 euc-kr 계열일 경우 문제가 있음.
}
return _content;
},
/**
* 현재 Wysiwyg 영역의 수직 스크롤 값을 얻어온다. - Only Wysiwyg
* @function
* @returns {Number} 수직 스크롤 값
* @see Trex.Canvas.WysiwygPanel#getScrollTop
*/
getScrollTop: function() {
if(!this.isWYSIWYG()) {
return 0;
}
return this.panels[this.mode].getScrollTop();
},
/**
* Wysiwyg 영역의 수직 스크롤 값을 셋팅한다. - Only Wysiwyg
* @function
* @param {Number} scrollTop - 수직 스크롤 값
* @see Trex.Canvas.WysiwygPanel#setScrollTop
*/
setScrollTop: function(scrollTop) {
if(!this.isWYSIWYG()) {
return;
}
this.panels[this.mode].setScrollTop(scrollTop);
},
/**
* 현재 활성화된 panel에 컨텐츠를 주어진 문자열로 수정한다.
* @param {String} content - 컨텐츠
*/
setContent: function(content) {
this.panels[this.mode].setContent(content);
this.includeWebfontCss(content);
},
/**
* panel에 컨텐츠를 주어진 문자열로 초기화한다.
* @param {String} content - 컨텐츠
*/
initContent: function(content) {
this.history.initHistory({
'content': content
});
this.panels[this.mode].setContent(content);
this.includeWebfontCss(content);
this.fireJobs(Trex.Ev.__CANVAS_DATA_INITIALIZE, Trex.Canvas.__WYSIWYG_MODE, _NULL);
/* //NOTE: 메일은 수정이 없음. 답장 전달의 경우에는 본문 상단에 포커싱이 가도록.
if ( $tx.gecko ){
var me = this;
setTimeout( function(){
me.focusOnBottom();
},500)
}else{
this.focusOnBottom();
}
*/
},
/**
* 컨텐츠를 파싱하여 사용되고 있는 웹폰트가 있으면, 웹폰트 css를 로딩한다. - Only Wysiwyg
* @param {string} content
* @see Trex.Canvas.WysiwygPanel#includeWebfontCss
*/
includeWebfontCss: function(content) {
if(!this.isWYSIWYG()) {
return;
}
return this.panels[this.mode].includeWebfontCss(content);
},
/**
* 본문에 사용된 웹폰트명 목록을 리턴한다. - Only Wysiwyg
* @function
* @returns {Array} 사용하고 있는 웹폰트명 목록
* @see Trex.Canvas.WysiwygPanel#getUsedWebfont
*/
getUsedWebfont: function() {
if(!this.isWYSIWYG()) {
return [];
}
return this.panels[this.mode].getUsedWebfont();
},
/**
* 자바스크립트를 동적으로 실행한다 - Only Wysiwyg
* @param {String} scripts - 자바스크립트 문자열
*/
runScript: function(scripts) {
if(!this.isWYSIWYG()) {
return [];
}
this.panels[this.mode].runScript(scripts);
},
/**
* 자바스크립트 소스를 로딩하여 동적으로 실행한다 - Only Wysiwyg
* @param {String} url - 자바스크립트 url
*/
importScript: function(url, callback) {
if(!this.isWYSIWYG()) {
return [];
}
this.panels[this.mode].importScript(url, callback);
},
/**
* 선택된 영역의 상태 값을 알기위해 주어진 함수를 실행시킨다. - Only Wysiwyg
* @param {Function} handler - 주어진 함수
* @example
* var _data = canvas.query(function(processor) {
* return processor.queryCommandState('bold');
* });
*/
query: function(handler) {
if(!this.isWYSIWYG()) {
return _NULL;
}
var _processor = this.getProcessor();
/* Block Scrolling
if($tx.msie) {
_processor.focus();
}
*/
return handler(_processor);
},
/**
* 선택된 영역에 주어진 handler를 실행시킨다.
* @param {Function} handler - 주어진 함수
* @example
* canvas.execute(function(processor) {
* processor.execCommand('bold', _NULL);
* });
*/
execute: function(handler) {
var _history = this.history;
var _processor = this.getProcessor();
if (this.isWYSIWYG()) {
this.getPanel('html').ensureFocused();
if (_processor.restoreRange) {
setTimeout(function () { //NOTE: #FTDUEDTR-435
_processor.restoreRange();
handler(_processor);
_history.saveHistory();
_processor.restore();
}, 0);
} else {
_processor.focus();
handler(_processor);
_history.saveHistory();
_processor.restore();
}
} else {
handler(_processor);
}
},
/**
* caret을 주어진 위치로 이동한다. - Only Wysiwyg
* aaa.bbb - bbb라는 클래스를 가진 aaa 노드의 다음에 커서를 이동한다.
* @param {String} scope
*/
moveCaret: function(scope) {
if(!scope) {
return;
}
if(!this.isWYSIWYG()) {
return;
}
this.getProcessor().moveCaretWith(scope);
},
/**
* 선택한 영역에 HTML 컨텐츠를 삽입한다.
* @param {String} content - 삽입하고자 하는 HTML 컨텐츠
* @param {Boolean} newline - 현재 영역에서 한줄을 띄운 후 삽입할지 여부 true/_FALSE
* @param {Object} wrapStyle - wrapper 노드에 적용할 스타일,
* newline이 true 일 경우에만 의미를 갖는다.
*/
pasteContent: function(content, newline, wrapStyle) {
newline = newline || _FALSE;
this.execute(function(processor) {
processor.pasteContent(content, newline, wrapStyle);
});
},
/**
* 선택한 영역에 노드를 삽입한다. - Only Wysiwyg
* @param {Array|Element} node - 삽입하고자 하는 노드 배열 또는 노드
* @param {Boolean} newline - 현재 영역에서 한줄을 띄운 후 삽입할지 여부 true/_FALSE
* @param {Object} wrapStyle - wrapper 노드에 적용할 스타일,
* newline이 true 일 경우에만 의미를 갖는다.
*/
pasteNode: function(node, newline, wrapStyle) {
if (!this.isWYSIWYG()) {
return;
}
newline = newline || _FALSE;
this.execute(function(processor) {
processor.pasteNode(node, newline, wrapStyle);
});
},
/**
* 현재 활성화된 panel에 스타일을 적용한다.
* @param {Object} styles - 적용할 스타일
*/
addStyle: function(styles) {
this.panels[this.mode].addStyle(styles);
},
/**
* 스타일명으로 현재 활성화된 panel의 스타일 값을 얻어온다.
* @param {String} name - 스타일명
* @returns {String} 해당 스타일 값
*/
getStyle: function(name) {
return this.panels[this.mode].getStyle(name);
},
/**
* 특정 노드의 Wysiwyg 영역에서의 상대 위치를 얻어온다. - Only Wysiwyg
* @function
* @param {Element} node - 특정 노드
* @returns {Object} position 객체 = {
* x: number,
* y: number,
* width: number,
* height: number
* }
*/
getPositionByNode: function(node) {
if(!this.isWYSIWYG()) {
return {
x: 0,
y: 0,
width: 0,
height: 0
};
}
return this.panels[this.mode].getPositionByNode(node);
},
onKeyDown: function(event) {
var p = this.getProcessor();
var doc = this.getCurrentPanel().getDocument();
function getNodeAndOffsetAtSel(){
var rng = goog.dom.Range.createFromBrowserSelection(doc.getSelection? doc.getSelection():p.getSel());
var node = rng.getStartNode();
var offset = rng.getStartOffset();
return {node: node,
offset: offset}
}
var where = getNodeAndOffsetAtSel();
this.fireJobs(Trex.Ev.__CANVAS_PANEL_KEYDOWN, event);
var prev = null;
if(event.keyCode == Trex.__KEY.BACKSPACE && p.isCollapsed() && (prev = $tom.prevNodeUntilTagName(where.node, where.offset, 'table')) && $tom.isTagName(prev, 'table')){
$tx.stop(event);
this.fireJobs(Trex.Ev.__CANVAS_PANEL_BACKSPACE_TABLE, prev);
}
if (this.config.useHotKey) {
this.fireKeys(event);
}
},
onKeyUp: function(event) {
var keyCode = event.keyCode+'';
if (shouldTriggerQuery(keyCode)) {
this.getProcessor().clearDummy();
}
this.history.saveHistoryByKeyEvent(event);
try {
this.mayAttachmentChanged = _TRUE;
this.fireJobs(Trex.Ev.__CANVAS_PANEL_KEYUP, event);
if (this.isWYSIWYG() && shouldTriggerQuery(keyCode)) {
this.triggerQueryStatus();
}
if (keyCode === Trex.__KEY.DELETE || keyCode === Trex.__KEY.BACKSPACE) { //NOTE: (Del/Backspace) keys를 눌러 본문에서 무엇인가가 삭제되었다고 생각될 경우 첨부들의 싱크를 확인한다.
this.fireJobs(Trex.Ev.__CANVAS_PANEL_DELETE_SOMETHING);
}
} catch(ignore) {
}
},
onMouseOver: function(event) {
try {
this.fireMouseover($tx.element(event));
this.fireJobs(Trex.Ev.__CANVAS_PANEL_MOUSEOVER, event);
} catch (ignore) {
}
},
onMouseMove: function(event) {
try {
this.fireJobs(Trex.Ev.__CANVAS_PANEL_MOUSEMOVE, event);
} catch (ignore) {
}
},
onMouseOut: function(event) {
try {
this.fireJobs(Trex.Ev.__CANVAS_PANEL_MOUSEOUT, event);
} catch (ignore) {
}
},
onMouseDown: function(event) {
this.getProcessor().clearDummy();
try {
this.fireElements($tx.element(event));
} catch(ignore) {
}
this.fireJobs(Trex.Ev.__CANVAS_PANEL_MOUSEDOWN, event);
var history = this.history;
history.saveHistoryIfEdited();
},
onMouseUp: function(event) {
try {
var self = this;
self.fireJobs(Trex.Ev.__CANVAS_PANEL_MOUSEUP, event);
setTimeout(function() {
var googRange = self.getProcessor().createGoogRange();
if (googRange) {
self.fireJobs(Trex.Ev.__CANVAS_PANEL_QUERY_STATUS, googRange);
}
}, 20);
} catch(ignore) {
}
},
mayAttachmentChanged: _FALSE,
onClick: function(event) {
this.fireJobs(Trex.Ev.__CANVAS_PANEL_CLICK, event);
},
onDoubleClick: function(event) {
this.fireJobs(Trex.Ev.__CANVAS_PANEL_DBLCLICK, event);
},
onScroll: function(event) {
this.fireJobs(Trex.Ev.__CANVAS_PANEL_SCROLLING, event);
},
onPaste: function(event) {
this.fireJobs(Trex.Ev.__CANVAS_PANEL_PASTE, event);
},
// TODO rename query status 라는 말 말고 다른 말 없을까?
triggerQueryStatus: function() {
this.cancelReservedQueryStatusTrigger();
this.reserveQueryStatusTrigger();
},
reserveQueryStatusTrigger: function() {
var self = this;
this.reservedQueryStatusTrigger = setTimeout(function() {
var googRange = self.getProcessor().createGoogRange();
if (googRange) {
self.fireJobs(Trex.Ev.__CANVAS_PANEL_QUERY_STATUS, googRange);
self.fireElements(self.getProcessor().getNode());
}
}, 20); // IE의 경우 canvas.execute 에서 setTimeout 처리 하기 때문에, execute 뒤에 부르는 syncProperty가 그 뒤에 실행되게 하려고 20ms 딜레이 준다....
},
cancelReservedQueryStatusTrigger: function() {
if (this.reservedQueryStatusTrigger) {
clearTimeout(this.reservedQueryStatusTrigger);
}
},
/**
* @depreacated use canvas.triggerQueryStatus();
*/
syncProperty: function() {
this.triggerQueryStatus();
}
});
})(Trex);
Trex.module("bind canvas events for close external menus",
function(editor, toolbar, sidebar, canvas/*, config*/) {
var _shouldCloseMenus = function () {
editor.fireJobs(Trex.Ev.__SHOULD_CLOSE_MENUS);
};
canvas.observeJob(Trex.Ev.__CANVAS_PANEL_CLICK, _shouldCloseMenus);
canvas.observeJob(Trex.Ev.__CANVAS_SOURCE_PANEL_CLICK, _shouldCloseMenus);
canvas.observeJob(Trex.Ev.__CANVAS_TEXT_PANEL_CLICK, _shouldCloseMenus);
}
);
Trex.module("make getter for 'iframeheight' and 'iframetop' size",
function(editor, toolbar, sidebar, canvas/*, config*/) {
var _iframeHeight = 0;
var _iframeTop = 0;
function resetIframeAttributes() {
var _wysiwygPanel = canvas.getPanel(Trex.Canvas.__WYSIWYG_MODE);
_iframeHeight = _wysiwygPanel.getPanelHeight().parsePx();
var _position = $tom.getPosition(_wysiwygPanel.el);
_iframeTop = _position.y;
}
// canvas resize
canvas.observeJob(Trex.Ev.__CANVAS_HEIGHT_CHANGE, function(height) {
resetIframeAttributes();
});
canvas.observeJob(Trex.Ev.__CANVAS_FULL_SCREEN_CHANGE, function() {
resetIframeAttributes();
});
canvas.observeJob(Trex.Ev.__CANVAS_NORMAL_SCREEN_CHANGE, function() {
resetIframeAttributes();
});
canvas.observeJob('canvas.apply.background', function() {
resetIframeAttributes();
});
canvas.observeJob('canvas.apply.letterpaper', function() {
resetIframeAttributes();
});
canvas.reserveJob(Trex.Ev.__IFRAME_LOAD_COMPLETE, function() {
resetIframeAttributes();
},300);
// attachbox change ui
var attachbox = editor.getAttachBox();
attachbox.observeJob(Trex.Ev.__ATTACHBOX_FULLSCREEN_SHOW, function() {
resetIframeAttributes();
});
attachbox.observeJob(Trex.Ev.__ATTACHBOX_FULLSCREEN_HIDE, function() {
resetIframeAttributes();
});
// window resize
$tx.observe(_WIN, 'resize', function(){
resetIframeAttributes();
});
// create interface
canvas.getIframeHeight = function(){
return _iframeHeight;
};
canvas.getIframeTop = function(){
return _iframeTop;
};
}
);
Trex.module("sync attachment data periodically", function(editor, toolbar, sidebar, canvas/*, config*/) {
setTimeout(function() {
setInterval(function() {
if (canvas.mayAttachmentChanged) {
// TODO 굳이 event 를 이용할 필요없이 바로 호출해줘도 될 것 같다.
canvas.fireJobs(Trex.Ev.__CANVAS_PANEL_DELETE_SOMETHING);
canvas.mayAttachmentChanged = _FALSE;
}
}, 3000);
}, 10000);
});
Trex.module("synchronize the font style when caret is in end of paragraph", function(editor, toolbar, sidebar, canvas/*, config*/) {
// only gecko #FTDUEDTR-1415
$tx.gecko && canvas.observeJob(Trex.Ev.__CANVAS_PANEL_MOUSEUP, function(ev){
if (canvas.isWYSIWYG()) {
var clickEl = ev.target;
var isParagraph = clickEl instanceof HTMLParagraphElement;
var isHtml = clickEl instanceof HTMLHtmlElement;
if (!isParagraph && !isHtml) {
return;
}
var processor = canvas.getProcessor();
var x = ev.pageX,
y = ev.pageY;
var caret = processor.doc.caretPositionFromPoint(x, y);
var node = caret && caret.offsetNode;
var des = node && $tom.descendants(node, '#text');
if (!des || !des.length) {
return;
}
var lastTextNode = des[des.length-1];
if (lastTextNode) {
var newRange = processor.createGoogRangeFromNodes(lastTextNode, lastTextNode.length, lastTextNode, lastTextNode.length);
newRange.select();
}
}
});
});
// FTDUEDTR-1431
Trex.module("apply respectVisibilityInDesign for old IE", function(editor, toolbar, sidebar, canvas, config) {
var isOldIE = ($tx.msie && ($tx.msie_docmode < 9));
isOldIE && canvas.observeJob(Trex.Ev.__CANVAS_MODE_CHANGE, function(oldMode, newMode){
changeVisibilityValue();
});
isOldIE && canvas.observeJob(Trex.Ev.__IFRAME_LOAD_COMPLETE, function(ev){
changeVisibilityValue();
});
var COMMAND_API = 'RespectVisibilityInDesign';
function changeVisibilityValue() {
if (canvas.isWYSIWYG()) {
var processor = canvas.getProcessor();
var state = processor.doc.queryCommandState(COMMAND_API);
var configFlag = canvas.config.respectVisibilityInDesign;
if (state != configFlag) {
processor.doc.execCommand(COMMAND_API, false, configFlag);
console.log('RespectVisibilityInDesign ', configFlag);
}
}
}
});