-/**\r
- * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/) \r
- * Copyright (C) 2002-2005 The Nucleus Group\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
- * (see nucleus/documentation/index.html#license for more info)\r
- *\r
- * This file contains functions to allow adding items from inside the weblog.\r
- * Also contains code to avoid submitting form data twice.\r
- *\r
- * $Id: edit.js,v 1.4 2005-03-23 06:14:53 kimitake Exp $\r
- * $NucleusJP: edit.js,v 1.3 2005/03/12 06:19:04 kimitake Exp $\r
- */\r
-\r
-var nucleusConvertBreaks = true;\r
-var nucleusMediaPopupURL = '';\r
-var nucleusMediaURL = 'media/';\r
-var nucleusAuthorId = 0;\r
-\r
-function setConvertBreaks(newval) { nucleusConvertBreaks = newval; }\r
-function setMediaUrl(url) { nucleusMediaURL = url; }\r
-function setAuthorId(id) { nucleusAuthorId = id; }\r
-\r
-function preview(id, value) {\r
- elem = document.getElementById(id);\r
- if (!elem) return;\r
- \r
- var preview = nucleusConvertBreaks ? str_replace("\n","<br />",value)+" " : value+" ";\r
- \r
- // expand the media commands (without explicit collection)\r
- preview = preview.replace(/\<\%image\(([^\/\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<img src='"+nucleusMediaURL+nucleusAuthorId+"/$1' width='$2' height='$3' alt=\"$4\" />");\r
- \r
- // expand the media commands (with collection)\r
- preview = preview.replace(/\<\%image\(([^\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<img src='"+nucleusMediaURL+"$1' width='$2' height='$3' alt=\"$4\" />");\r
- preview = preview.replace(/\<\%popup\(([^\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' onclick='if (event && event.preventDefault) event.preventDefault(); alert(\"popup image\"); return false;' title='popup'>$4</a>");\r
- preview = preview.replace(/\<\%media\(([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' title='media link'>$2</a>"); \r
- \r
- elem.innerHTML = preview;\r
-}\r
-\r
-function showedit() {\r
- prevval = document.getElementById('edit').style.display;\r
- if (prevval == "block")\r
- newval = "none";\r
- else\r
- newval = "block";\r
- document.getElementById('edit').style.display = newval;\r
-\r
- if (newval == "block")\r
- updAllPreviews(); \r
-}\r
-\r
-function updAllPreviews() {\r
- updPreview('title');\r
- updPreview('body');\r
- updPreview('more');\r
-}\r
-\r
-function isEditVisible() {\r
- var editform = document.getElementById('edit');\r
- if (!editform) return true;\r
- var prevval = editform.style.display;\r
- return (prevval == "none") ? false : true;\r
-}\r
-\r
-function updPreview(id) {\r
- // don't update when preview is hidden\r
- if (!isEditVisible()) return;\r
- \r
- var inputField = document.getElementById('input' + id);\r
- if (!inputField) return;\r
- preview('prev' + id, inputField.value);\r
-}\r
-\r
-// replace a in s by b (taken from milov.nl)\r
-function str_replace(a, b, s)\r
-{\r
- if (a == b || !s.length || !a.length) return s;\r
- if ((p=s.indexOf(a)) == -1) { return s; }\r
- else { ns = s.substring(0,p) + b + s.substring(p+a.length,s.length); }\r
- return (s.indexOf(a) != -1) ? str_replace(a, b, ns) : ns;\r
-}\r
-\r
-function shortCuts() {\r
- if (!event || (event.ctrlKey != true)) return;\r
- \r
- switch (event.keyCode) {\r
- case 1:\r
- ahrefThis(); break; // ctrl-shift-a\r
- case 2:\r
- boldThis(); break; // ctrl-shift-b\r
- case 9:\r
- italicThis(); break; // ctrl-shift-i\r
- case 13:\r
- addMedia(); break; // ctrl-shift-m\r
- default: \r
- return;\r
- }\r
- return;\r
-}\r
-\r
-function cutThis() { execAndUpdate('cut'); }\r
-function copyThis() { execAndUpdate('copy'); }\r
-function pasteThis() { execAndUpdate('paste'); }\r
-function boldThis() { insertAroundCaret('<b>','</b>'); }\r
-function italicThis() { insertAroundCaret('<i>','</i>'); }\r
-function leftThis() { insertAroundCaret('<div class="leftbox">','</div>'); }\r
-function rightThis() { insertAroundCaret('<div class="rightbox">','</div>'); }\r
-function alignleftThis() { insertAroundCaret('<div style="text-align: left">','</div>'); }\r
-function alignrightThis() { insertAroundCaret('<div style="text-align: right">','</div>'); }\r
-function aligncenterThis() { insertAroundCaret('<div style="text-align: center">','</div>'); }\r
-\r
-\r
-function ahrefThis() {\r
- if (document.selection)\r
- strSelection = document.selection.createRange().text;\r
- else\r
- strSelection = '';\r
- \r
- strHref = prompt("Create a link to:","http://");\r
- if (strHref == null) return;\r
- \r
- var textpre = "<a href=\"" + strHref + "\">";\r
- insertAroundCaret(textpre, "</a>");\r
-}\r
-\r
-function execAndUpdate(action) {\r
- lastCaretPos.execCommand(action);\r
- updAllPreviews(); \r
-}\r
-\r
-\r
-var nonie_FormType = 'body';\r
-\r
-// Add media to new item\r
-function addMedia() {\r
- \r
- var mediapopup = window.open(nucleusMediaPopupURL + 'media.php','name',\r
- 'status=yes,toolbar=no,scrollbars=yes,resizable=yes,width=500,height=450,top=0,left=0');\r
-\r
- return;\r
-} \r
-\r
-\r
-function setMediaPopupURL(url) {\r
- nucleusMediaPopupURL = url;\r
-}\r
-\r
-function includeImage(collection, filename, type, width, height) {\r
- if (isCaretEmpty()) {\r
- text = prompt("Text to display ?","");\r
- } else {\r
- text = getCaretText();\r
- }\r
- \r
- // add collection name when not private collection (or editing a message that's not your)\r
- var fullName;\r
- if (isNaN(collection) || (nucleusAuthorId != collection)) {\r
- fullName = collection + '/' + filename;\r
- } else {\r
- fullName = filename;\r
- }\r
- \r
- \r
- var replaceBy;\r
- switch(type) {\r
- case 'popup':\r
- replaceBy = '<%popup(' + fullName + '|'+width+'|'+height+'|' + text +')%>';\r
- break;\r
- case 'inline':\r
- default:\r
- replaceBy = '<%image(' + fullName + '|'+width+'|'+height+'|' + text +')%>';\r
- }\r
- \r
- insertAtCaret(replaceBy);\r
- updAllPreviews(); \r
-\r
-}\r
-\r
-\r
-function includeOtherMedia(collection, filename) {\r
- if (isCaretEmpty()) {\r
- text = prompt("Text to display ?","");\r
- } else {\r
- text = getCaretText();\r
- }\r
- \r
- // add collection name when not private collection (or editing a message that's not your)\r
- var fullName;\r
- if (isNaN(collection) || (nucleusAuthorId != collection)) {\r
- fullName = collection + '/' + filename;\r
- } else {\r
- fullName = filename;\r
- } \r
- \r
- var replaceBy = '<%media(' + fullName + '|' + text +')%>';\r
- \r
- insertAtCaret(replaceBy);\r
- updAllPreviews(); \r
-}\r
-\r
-\r
-\r
-// function to prevent submitting form data twice\r
-var submitcount=0;\r
-function checkSubmit() {\r
- if (submitcount == 0) {\r
- submitcount++;\r
- return true;\r
- } else {\r
- return false;\r
- }\r
-}\r
-\r
-\r
-// code to store the caret (cursor) position of a text field/text area\r
-// taken from javascript.faqts and modified\r
-// http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130\r
-\r
-// stores the caret\r
-var lastSelected, lastCaretPos;\r
-function storeCaret (textEl) {\r
-\r
- // store caret\r
- if (textEl.createTextRange) \r
- //textEl.caretPos = document.selection.createRange().duplicate();\r
- lastCaretPos = document.selection.createRange().duplicate();\r
-\r
- // also store lastselectedelement\r
- lastSelected = textEl;\r
- \r
- nonie_FormType = textEl.name;\r
-}\r
-\r
-//var lastSelected;\r
-\r
-// inserts text at caret (overwriting selection)\r
-function insertAtCaret (text) {\r
- var textEl = lastSelected;\r
- if (textEl && textEl.createTextRange && lastCaretPos) {\r
- var caretPos = lastCaretPos;\r
- caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;\r
- } else if (!document.all && document.getElementById) {\r
- mozReplace(document.getElementById('input' + nonie_FormType), text); \r
- } else if (textEl) {\r
- textEl.value += text;\r
- } else {\r
- document.getElementById('input' + nonie_FormType).value += text; \r
- }\r
- updAllPreviews();\r
-}\r
-\r
-// inserts a tag around the selected text\r
-function insertAroundCaret (textpre, textpost) {\r
- var textEl = lastSelected;\r
- \r
- if (textEl && textEl.createTextRange && lastCaretPos) {\r
- var caretPos = lastCaretPos;\r
- caretPos.text = textpre + caretPos.text + textpost;\r
- } else if (!document.all && document.getElementById) {\r
- mozWrap(document.getElementById('input' + nonie_FormType), textpre, textpost); \r
- } else {\r
- document.getElementById('input' + nonie_FormType).value += textpre + textpost;\r
- }\r
-\r
- updAllPreviews();\r
-}\r
-\r
-/* some methods to get things working in Mozilla as well */\r
-function mozWrap(txtarea, lft, rgt) {\r
- var selLength = txtarea.textLength;\r
- var selStart = txtarea.selectionStart;\r
- var selEnd = txtarea.selectionEnd;\r
- if (selEnd==1 || selEnd==2) selEnd=selLength;\r
- var s1 = (txtarea.value).substring(0,selStart);\r
- var s2 = (txtarea.value).substring(selStart, selEnd)\r
- var s3 = (txtarea.value).substring(selEnd, selLength);\r
- txtarea.value = s1 + lft + s2 + rgt + s3;\r
-}\r
-function mozReplace(txtarea, newText) {\r
- var selLength = txtarea.textLength;\r
- var selStart = txtarea.selectionStart;\r
- var selEnd = txtarea.selectionEnd;\r
- if (selEnd==1 || selEnd==2) selEnd=selLength;\r
- var s1 = (txtarea.value).substring(0,selStart);\r
- var s2 = (txtarea.value).substring(selStart, selEnd)\r
- var s3 = (txtarea.value).substring(selEnd, selLength);\r
- txtarea.value = s1 + newText + s3;\r
-}\r
-function mozSelectedText() {\r
- var txtarea = document.getElementById('input' + nonie_FormType);\r
- var selLength = txtarea.textLength;\r
- var selStart = txtarea.selectionStart;\r
- var selEnd = txtarea.selectionEnd;\r
- if (selEnd==1 || selEnd==2) selEnd=selLength;\r
- return (txtarea.value).substring(selStart, selEnd);\r
-}\r
-\r
-function getCaretText() {\r
- if (!document.all && document.getElementById)\r
- return mozSelectedText();\r
- else\r
- return lastCaretPos.text;\r
-}\r
-\r
-function isCaretEmpty() {\r
- if (lastSelected && lastSelected.createTextRange && lastCaretPos)\r
- return (lastCaretPos.text == '');\r
- else if (!document.all && document.getElementById)\r
- return (mozSelectedText() == '');\r
- else\r
- return true;\r
-}\r
-\r
-function BtnHighlight(el) {\r
- with(el.style){\r
- borderLeft="1px solid gray";\r
- borderRight="1px solid #e9e9e9";\r
- borderTop="1px solid gray";\r
- borderBottom="1px solid #e9e9e9";\r
- }\r
-}\r
-\r
-function BtnNormal(el) {\r
- with(el.style){\r
- padding="3px";\r
- border="1px solid #dddddd";\r
- }\r
-}\r
-\r
+/**
+ * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
+ * Copyright (C) 2002-2006 The Nucleus Group
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * (see nucleus/documentation/index.html#license for more info)
+ *
+ * This file contains functions to allow adding items from inside the weblog.
+ * Also contains code to avoid submitting form data twice.
+ *
+ * $Id: edit.js,v 1.5 2006-07-12 07:11:47 kimitake Exp $
+ * $NucleusJP: edit.js,v 1.4.2.1 2005/09/27 06:58:55 kimitake Exp $
+ */
+
+var nucleusConvertBreaks = true;
+var nucleusMediaPopupURL = '';
+var nucleusMediaURL = 'media/';
+var nucleusAuthorId = 0;
+var scrollTop = -1;
+
+function setConvertBreaks(newval) { nucleusConvertBreaks = newval; }
+function setMediaUrl(url) { nucleusMediaURL = url; }
+function setAuthorId(id) { nucleusAuthorId = id; }
+
+function preview(id, value) {
+ elem = document.getElementById(id);
+ if (!elem) return;
+
+ var preview = nucleusConvertBreaks ? str_replace("\n","<br />",value)+" " : value+" ";
+
+ // expand the media commands (without explicit collection)
+ preview = preview.replace(/\<\%image\(([^\/\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<img src='"+nucleusMediaURL+nucleusAuthorId+"/$1' width='$2' height='$3' alt=\"$4\" />");
+
+ // expand the media commands (with collection)
+ preview = preview.replace(/\<\%image\(([^\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<img src='"+nucleusMediaURL+"$1' width='$2' height='$3' alt=\"$4\" />");
+ preview = preview.replace(/\<\%popup\(([^\|]*)\|([^\|]*)\|([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' onclick='if (event && event.preventDefault) event.preventDefault(); alert(\"popup image\"); return false;' title='popup'>$4</a>");
+ preview = preview.replace(/\<\%media\(([^\|]*)\|([^)]*)\)\%\>/g,"<a href='' title='media link'>$2</a>");
+
+ elem.innerHTML = preview;
+}
+
+function showedit() {
+ prevval = document.getElementById('edit').style.display;
+ if (prevval == "block")
+ newval = "none";
+ else
+ newval = "block";
+ document.getElementById('edit').style.display = newval;
+
+ if (newval == "block")
+ updAllPreviews();
+}
+
+function updAllPreviews() {
+ updPreview('title');
+ updPreview('body');
+ updPreview('more');
+}
+
+function isEditVisible() {
+ var editform = document.getElementById('edit');
+ if (!editform) return true;
+ var prevval = editform.style.display;
+ return (prevval == "none") ? false : true;
+}
+
+function updPreview(id) {
+ // don't update when preview is hidden
+ if (!isEditVisible()) return;
+
+ var inputField = document.getElementById('input' + id);
+ if (!inputField) return;
+ preview('prev' + id, inputField.value);
+}
+
+// replace a in s by b (taken from milov.nl)
+function str_replace(a, b, s)
+{
+ if (a == b || !s.length || !a.length) return s;
+ if ((p=s.indexOf(a)) == -1) { return s; }
+ else { ns = s.substring(0,p) + b + s.substring(p+a.length,s.length); }
+ return (s.indexOf(a) != -1) ? str_replace(a, b, ns) : ns;
+}
+
+function shortCuts() {
+ if (!event || (event.ctrlKey != true)) return;
+
+ switch (event.keyCode) {
+ case 1:
+ ahrefThis(); break; // ctrl-shift-a
+ case 2:
+ boldThis(); break; // ctrl-shift-b
+ case 9:
+ italicThis(); break; // ctrl-shift-i
+ case 13:
+ addMedia(); break; // ctrl-shift-m
+ default:
+ return;
+ }
+ return;
+}
+
+function cutThis() { execAndUpdate('cut'); }
+function copyThis() { execAndUpdate('copy'); }
+function pasteThis() { execAndUpdate('paste'); }
+function boldThis() { insertAroundCaret('<b>','</b>'); }
+function italicThis() { insertAroundCaret('<i>','</i>'); }
+function leftThis() { insertAroundCaret('<div class="leftbox">','</div>'); }
+function rightThis() { insertAroundCaret('<div class="rightbox">','</div>'); }
+function alignleftThis() { insertAroundCaret('<div style="text-align: left">','</div>'); }
+function alignrightThis() { insertAroundCaret('<div style="text-align: right">','</div>'); }
+function aligncenterThis() { insertAroundCaret('<div style="text-align: center">','</div>'); }
+
+
+function ahrefThis() {
+ if (document.selection)
+ strSelection = document.selection.createRange().text;
+ else
+ strSelection = '';
+
+ strHref = prompt("Create a link to:","http://");
+ if (strHref == null) return;
+
+ var textpre = "<a href=\"" + strHref.replace(/&/g,'&') + "\">";
+ insertAroundCaret(textpre, "</a>");
+}
+
+function execAndUpdate(action) {
+ lastSelected.caretPos.execCommand(action);
+ updAllPreviews();
+}
+
+
+var nonie_FormType = 'body';
+
+// Add media to new item
+function addMedia() {
+
+ var mediapopup = window.open(nucleusMediaPopupURL + 'media.php','name',
+ 'status=yes,toolbar=no,scrollbars=yes,resizable=yes,width=500,height=450,top=0,left=0');
+
+ return;
+}
+
+
+function setMediaPopupURL(url) {
+ nucleusMediaPopupURL = url;
+}
+
+function includeImage(collection, filename, type, width, height) {
+ if (isCaretEmpty()) {
+ text = prompt("Text to display ?","");
+ } else {
+ text = getCaretText();
+ }
+
+ // add collection name when not private collection (or editing a message that's not your)
+ var fullName;
+ if (isNaN(collection) || (nucleusAuthorId != collection)) {
+ fullName = collection + '/' + filename;
+ } else {
+ fullName = filename;
+ }
+
+
+ var replaceBy;
+ switch(type) {
+ case 'popup':
+ replaceBy = '<%popup(' + fullName + '|'+width+'|'+height+'|' + text +')%>';
+ break;
+ case 'inline':
+ default:
+ replaceBy = '<%image(' + fullName + '|'+width+'|'+height+'|' + text +')%>';
+ }
+
+ insertAtCaret(replaceBy);
+ updAllPreviews();
+
+}
+
+
+function includeOtherMedia(collection, filename) {
+ if (isCaretEmpty()) {
+ text = prompt("Text to display ?","");
+ } else {
+ text = getCaretText();
+ }
+
+ // add collection name when not private collection (or editing a message that's not your)
+ var fullName;
+ if (isNaN(collection) || (nucleusAuthorId != collection)) {
+ fullName = collection + '/' + filename;
+ } else {
+ fullName = filename;
+ }
+
+ var replaceBy = '<%media(' + fullName + '|' + text +')%>';
+
+ insertAtCaret(replaceBy);
+ updAllPreviews();
+}
+
+
+
+// function to prevent submitting form data twice
+var submitcount=0;
+function checkSubmit() {
+ if (submitcount == 0) {
+ submitcount++;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+// code to store the caret (cursor) position of a text field/text area
+// taken from javascript.faqts and modified
+// http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130
+
+// stores the caret
+var lastSelected, lastCaretPos;
+function storeCaret (textEl) {
+
+ // store caret
+ if (textEl.createTextRange)
+ //textEl.caretPos = document.selection.createRange().duplicate();
+ lastCaretPos = document.selection.createRange().duplicate();
+
+ // also store lastselectedelement
+ lastSelected = textEl;
+
+ nonie_FormType = textEl.name;
+
+ scrollTop = textEl.scrollTop;
+}
+
+//var lastSelected;
+
+// inserts text at caret (overwriting selection)
+function insertAtCaret (text) {
+ var textEl = lastSelected;
+ if (textEl && textEl.createTextRange && lastCaretPos) {
+ var caretPos = lastCaretPos;
+ caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? text + ' ' : text;
+ } else if (!document.all && document.getElementById) {
+ mozReplace(document.getElementById('input' + nonie_FormType), text);
+ if(scrollTop>-1) {
+ document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
+ }
+ } else if (textEl) {
+ textEl.value += text;
+ } else {
+ document.getElementById('input' + nonie_FormType).value += text;
+ if(scrollTop>-1) {
+ document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
+ }
+ }
+ updAllPreviews();
+}
+
+// inserts a tag around the selected text
+function insertAroundCaret (textpre, textpost) {
+ var textEl = lastSelected;
+
+ if (textEl && textEl.createTextRange && lastCaretPos) {
+ var caretPos = lastCaretPos;
+ caretPos.text = textpre + caretPos.text + textpost;
+ } else if (!document.all && document.getElementById) {
+ mozWrap(document.getElementById('input' + nonie_FormType), textpre, textpost);
+ if(scrollTop>-1) {
+ document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
+ }
+ } else {
+ document.getElementById('input' + nonie_FormType).value += textpre + textpost;
+ if(scrollTop>-1) {
+ document.getElementById('input' + nonie_FormType).scrollTop = scrollTop;
+ }
+ }
+
+ updAllPreviews();
+}
+
+/* some methods to get things working in Mozilla as well */
+function mozWrap(txtarea, lft, rgt) {
+ var selLength = txtarea.textLength;
+ var selStart = txtarea.selectionStart;
+ var selEnd = txtarea.selectionEnd;
+ if (selEnd==1 || selEnd==2) selEnd=selLength;
+ var s1 = (txtarea.value).substring(0,selStart);
+ var s2 = (txtarea.value).substring(selStart, selEnd)
+ var s3 = (txtarea.value).substring(selEnd, selLength);
+ txtarea.value = s1 + lft + s2 + rgt + s3;
+}
+function mozReplace(txtarea, newText) {
+ var selLength = txtarea.textLength;
+ var selStart = txtarea.selectionStart;
+ var selEnd = txtarea.selectionEnd;
+ if (selEnd==1 || selEnd==2) selEnd=selLength;
+ var s1 = (txtarea.value).substring(0,selStart);
+ var s2 = (txtarea.value).substring(selStart, selEnd)
+ var s3 = (txtarea.value).substring(selEnd, selLength);
+ txtarea.value = s1 + newText + s3;
+}
+function mozSelectedText() {
+ var txtarea = document.getElementById('input' + nonie_FormType);
+ var selLength = txtarea.textLength;
+ var selStart = txtarea.selectionStart;
+ var selEnd = txtarea.selectionEnd;
+ if (selEnd==1 || selEnd==2) selEnd=selLength;
+ return (txtarea.value).substring(selStart, selEnd);
+}
+
+function getCaretText() {
+ if (!document.all && document.getElementById)
+ return mozSelectedText();
+ else
+ return lastCaretPos.text;
+}
+
+function isCaretEmpty() {
+ if (lastSelected && lastSelected.createTextRange && lastCaretPos)
+ return (lastCaretPos.text == '');
+ else if (!document.all && document.getElementById)
+ return (mozSelectedText() == '');
+ else
+ return true;
+}
+
+function BtnHighlight(el) {
+ with(el.style){
+ borderLeft="1px solid gray";
+ borderRight="1px solid #e9e9e9";
+ borderTop="1px solid gray";
+ borderBottom="1px solid #e9e9e9";
+ }
+}
+
+function BtnNormal(el) {
+ with(el.style){
+ padding="3px";
+ border="1px solid #dddddd";
+ }
+}
+