TextEditor.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. SC.loadPackage({ 'TextEditor': {
  2. comment: 'I am the TextEditor for TextElements.',
  3. sharedProperties: {
  4. editGroupFontFamily: { initValue: '<a class="btn dropdown-toggle" title="Font"><i class="icon-font"></i><b class="caret"></b></a><ul class="dropdown-menu"></ul>' },
  5. editGroupFontSize: { initValue: '<a class="btn dropdown-toggle" title="Font Size"><i class="icon-text-height"></i>&nbsp;<b class="caret"></b></a><ul class="dropdown-menu small"></ul>' },
  6. editGroupFontStyle: { initValue: '<a class="btn" data-wysihtml5-command="bold" title="Bold"><i class="icon-bold"></i></a><a class="btn" data-wysihtml5-command="italic" title="Italic"><i class="icon-italic"></i></a><a class="btn" data-wysihtml5-command="underline" title="Underline"><i class="icon-underline"></i></a>' },
  7. editGroupFontColor: { initValue: '<a class="btn dropdown-toggle right" title="Font Color"><i class="icon-color">&nbsp;<b class="caret"></i></a><div class="sg-colorpicker-container-text"><div class="sg-colorpicker-container"></div></div>' },
  8. editGroupLists: { initValue: '<a class="btn" data-wysihtml5-command="insertUnorderedList" title="Bullet list"><i class="icon-list-ul"></i></a><a class="btn" data-wysihtml5-command="insertOrderedList" title="Number list"><i class="icon-list-ol"></i></a>' },
  9. editGroupIndention: { initValue: '<a class="btn" data-wysihtml5-command="outdent" title="Reduce indent"><i class="icon-indent-right"></i></a><a class="btn" data-wysihtml5-command="indent" title="Indent"><i class="icon-indent-left"></i></a>' },
  10. editGroupAlignment: { initValue: '<a class="btn" data-wysihtml5-command="alignLeftStyle" title="Align Left"><i class="icon-align-left"></i></a><a class="btn" data-wysihtml5-command="alignCenterStyle" title="Center"><i class="icon-align-center"></i></a><a class="btn" data-wysihtml5-command="alignRightStyle" title="Align Right"><i class="icon-align-right"></i></a><a class="btn" data-wysihtml5-command="alignJustifyStyle" title="Justify"><i class="icon-align-justify"></i></a>' },
  11. editGroupHyperlink: { initValue: '<a class="btn hyperlink" title="Hyperlink" data-wysihtml5-command="createLink"><i class="icon-link"></i></a><div class="hyperlink-dropdown input-append" data-wysihtml5-dialog="createLink" style="display: none;"><input data-wysihtml5-dialog-field="href" value="http://" class="text"><a data-wysihtml5-dialog-action="save"></a><a data-wysihtml5-command="removeLink"></a><a data-wysihtml5-dialog-action="cancel"></a></div>' },
  12. //editGroupHyperlink: { initValue: '<a class="btn dropdown-toggle hyperlink" title="Hyperlink"><i class="icon-link"></i>&nbsp;<b class="caret"></b></a><div class="dropdown-menu input-append" style="display: none;"><input value="http://" class="text"><a data-wysihtml5-command="createLink" data-wysihtml5-command-value=""></a><a data-wysihtml5-command="removeLink"></a><a data-wysihtml5-dialog-action="cancel"></a></div>' },
  13. activeEditGroups: { initValue: ['editGroupIndention', 'editGroupAlignment', 'editGroupFontSize', 'editGroupFontFamily', 'editGroupFontColor', 'editGroupHyperlink', 'editGroupFontStyle', 'editGroupLists'] },
  14. activeFonts: { initValue: ['Serif', 'Sans', 'Arial', 'Arial Black', 'Courier', 'Courier New', 'Comic Sans MS','Dosis', 'Helvetica', 'Impact', 'Lucida Grande', 'Lucida Sans', 'Montserrat', 'Tahoma', 'Times', 'Times New Roman', 'TitilliumWeb', 'Verdana'] },
  15. activeFontSizes: { initValue: ['8px', '9px', '10px', '11px', '12px', '13px', '14px', '15px', '16px', '17px', '18px', '20px', '22px', '26px', '28px', '30px', '32px', '34px', '36px', '38px', '40px', '46px', '50px', '60px', '70px'] }
  16. },
  17. properties: {
  18. originalElementNode: { comment: 'I store the original TextElement\'s DOM node.' },
  19. originalSelection: { comment: 'I store the selection to restore it on unloading of the editor.' },
  20. textEditor: { comment: 'I store the TextEditor\'s DOM node.' },
  21. textEditorContainer: { comment: 'I store the textEditorContainer\'s DOM node.' },
  22. textEditorToolbar: { comment: 'I store the textEditorToolbar\'s DOM node.' },
  23. colorpicker: { comment: 'I store a reference to my colorpicker' }
  24. },
  25. methods: {
  26. init: {
  27. comment: 'method comment',
  28. code: function(aTextElement){
  29. var self = this,
  30. originalElementNode = aTextElement.get('node'),
  31. textEditor = document.createElement('textarea'),
  32. textEditorContainer = document.createElement('div');
  33. this.set({
  34. originalElementNode: originalElementNode,
  35. originalSelection: SuperGlue.get('selection').get('elements'),
  36. textEditor: textEditor,
  37. textEditorContainer: textEditorContainer
  38. });
  39. SuperGlue.get('selection').do('clearAll');
  40. (function(elementNode){
  41. var textContent = elementNode.innerHTML;
  42. SuperGlue.get('history').do('actionHasStarted', function(){
  43. elementNode.innerHTML = textContent;
  44. })
  45. }).call(this, this.get('originalElementNode'));
  46. // Prepare textEditor's div
  47. /*
  48. textEditor.setAttribute('id', 'sg-editing-textEditor');
  49. textEditor.style.width = originalElementNode.style.width;
  50. textEditor.style.height = originalElementNode.style.height;
  51. textEditor.style.padding = originalElementNode.style.padding;
  52. textEditor.style.border = originalElementNode.style.border;
  53. textEditor.style.borderRadius = originalElementNode.style.borderRadius;
  54. */
  55. // Add textarea
  56. textEditor.setAttribute('id', 'currentEditor');
  57. textEditor.style.borderWidth = originalElementNode.style.borderWidth;
  58. textEditor.style.borderColor = originalElementNode.style.borderColor;
  59. textEditor.style.borderRadius = originalElementNode.style.borderRadius;
  60. textEditor.style.backgroundColor = originalElementNode.style.backgroundColor;
  61. textEditor.style.backgroundRepeat = originalElementNode.style.backgroundRepeat;
  62. textEditor.style.backgroundImage = originalElementNode.style.backgroundImage;
  63. textEditor.style.padding = originalElementNode.style.padding;
  64. textEditor.style.boxSizing = 'border-box';
  65. textEditor.style.borderStyle = 'solid';
  66. textEditor.style.position = 'absolute';
  67. textEditor.style.width = this.get('originalElementNode').offsetWidth + 'px';
  68. textEditor.style.height = this.get('originalElementNode').offsetHeight + 'px';
  69. textEditor.style.outline = '1px dashed rgb(255, 41, 61)';
  70. this.do('updateEditorDimensions');
  71. /*
  72. textEditor.style.top = this.get('originalElementNode').clientTop - this.get('originalElementNode').scrollTop + 'px';
  73. textEditor.style.left = this.get('originalElementNode').clientLeft - this.get('originalElementNode').scrollLeft + 'px';
  74. textEditor.style.width = this.get('originalElementNode').offsetWidth + 'px';
  75. textEditor.style.height = this.get('originalElementNode').offsetHeight + 'px';
  76. */
  77. this.get('textEditorContainer').appendChild(textEditor);
  78. window.addEventListener('resize', function(){
  79. self.do('updateEditorDimensions', textEditor)
  80. }, false);
  81. // Prepare container
  82. textEditorContainer.setAttribute('id', 'sg-editing-textEditor-container');
  83. this.do('updateContainerDimensions', textEditorContainer);
  84. window.addEventListener('resize', function(){
  85. self.do('updateContainerDimensions', textEditorContainer)
  86. }, false);
  87. textEditor.innerHTML = originalElementNode.innerHTML;
  88. originalElementNode.style.display = 'none';
  89. textEditorContainer.appendChild(textEditor);
  90. // Add eventListener on the container
  91. textEditorContainer.addEventListener('mouseover', function(evt){
  92. evt.stopPropagation();
  93. }, false);
  94. textEditorContainer.addEventListener('mouseout', function(evt){
  95. evt.stopPropagation();
  96. }, false);
  97. textEditorContainer.addEventListener('mouseup', function(evt){
  98. self.do('closeTextEditor');
  99. evt.stopPropagation();
  100. }, false);
  101. textEditorContainer.addEventListener('mousedown', function(evt){
  102. evt.stopPropagation();
  103. }, false);
  104. document.body.insertBefore(
  105. textEditorContainer,
  106. SuperGlue.get('document').get('editingContainer').nextElementSibling
  107. );
  108. // Append text editing toolbar
  109. var textShapeToolbar = document.createElement('div');
  110. textShapeToolbar.setAttribute('id', 'textShapeToolbar');
  111. textShapeToolbar.setAttribute('data-role', 'editor-toolbar');
  112. textShapeToolbar.setAttribute('data-target', '#currentEditor');
  113. textShapeToolbar.style.display = 'block';
  114. textShapeToolbar.style.top = this.get('textEditor').offsetTop - 85 + 'px';
  115. textShapeToolbar.style.left = this.get('textEditor').offsetLeft + this.get('textEditor').offsetWidth - 300 + 'px';
  116. var editGroups = this.class.get('activeEditGroups');
  117. for ( i=0; i < editGroups.length; i++ ) {
  118. var htmlString = this.class.get(editGroups[i]);
  119. var currentGroup = document.createElement('div');
  120. currentGroup.setAttribute('class', 'btn-group');
  121. currentGroup.innerHTML = htmlString;
  122. textShapeToolbar.appendChild(currentGroup);
  123. }
  124. textShapeToolbar.addEventListener('mousedown', function(evt) {
  125. evt.stopPropagation();
  126. });
  127. this.get('textEditorContainer').appendChild(textShapeToolbar);
  128. this.set({ textEditorToolbar: textShapeToolbar });
  129. this.do('initToolbarBindings');
  130. textEditor.style.display = 'none';
  131. // Initialize Editor
  132. window.editor = new wysihtml5.Editor("currentEditor", { // id of textarea element
  133. toolbar: "textShapeToolbar", // id of toolbar element
  134. style: false,
  135. useLineBreaks: false,
  136. parserRules: wysihtml5ParserRules, // defined in parser rules set
  137. cleanUp: true,
  138. stylesheets: ["../resources/css/SuperGlue.css"]
  139. }).on('load', function() {
  140. document.querySelector('.wysihtml5-sandbox').addEventListener('mouseenter', function() {
  141. // Hide open dropdown menus
  142. var dropdownMenuContainers = document.querySelectorAll('.dropdown-menu');
  143. var dropdownMenus = document.querySelectorAll('.dropdown-toggle');
  144. for (var i=0; i<dropdownMenuContainers.length; i++) {
  145. dropdownMenuContainers[i].classList.remove('active')
  146. }
  147. document.querySelector('.sg-colorpicker-container-text').classList.remove('active');
  148. for (var d=0; d<dropdownMenus.length; d++) {
  149. dropdownMenus[d].classList.remove('open');
  150. }
  151. });
  152. editor.focus();
  153. self.do('initColorpicker', {
  154. initialColor: undefined,
  155. setCallback: function(colorCode){
  156. if ( editor.composer.commands.stateValue("fontColorStyle") !== colorCode ) {
  157. editor.composer.commands.exec('fontColorStyle', colorCode );
  158. }
  159. }
  160. });
  161. }).on('blur', function() {
  162. document.querySelector('.wysihtml5-sandbox').style.display = 'block';
  163. self.get('originalElementNode').innerHTML = self.get('textEditor').value;
  164. self.get('textEditor').style.display = 'none';
  165. }).on('focus', function() {
  166. self.get('textEditor').style.display = 'none';
  167. var sandbox = document.querySelector('.wysihtml5-sandbox');
  168. sandbox.contentWindow.document.body.style.overflow = 'hidden';
  169. sandbox.style.borderWidth = self.get('textEditor').style.borderWidth;
  170. sandbox.style.borderColor = self.get('textEditor').style.borderColor;
  171. sandbox.style.borderRadius = self.get('textEditor').style.borderRadius;
  172. sandbox.style.backgroundColor = self.get('textEditor').style.backgroundColor;
  173. sandbox.style.backgroundRepeat = self.get('textEditor').style.backgroundRepeat;
  174. sandbox.style.backgroundImage = self.get('textEditor').style.backgroundImage;
  175. sandbox.style.padding = self.get('textEditor').style.padding;
  176. sandbox.style.boxSizing = self.get('textEditor').style.boxSizing;
  177. sandbox.style.outline = self.get('textEditor').style.outline;
  178. sandbox.style.borderStyle = self.get('textEditor').style.borderStyle;
  179. sandbox.style.position = 'absolute';
  180. //this.do('updateEditorDimensions', sandbox);
  181. sandbox.style.top = self.get('textEditor').style.top;
  182. sandbox.style.left = self.get('textEditor').style.left;
  183. sandbox.style.width = self.get('textEditor').style.width;
  184. sandbox.style.height = self.get('textEditor').style.height;
  185. sandbox.style.display = 'block';
  186. });
  187. self.get('textEditor').addEventListener('click', function(evt){
  188. if (editor) {
  189. window.editor.focus();
  190. }
  191. evt.stopPropagation();
  192. return;
  193. });
  194. var self = this;
  195. var tmpTextColor;
  196. document.querySelector('.wysihtml5-sandbox').contentWindow.document.body.addEventListener('selectstart', function () {
  197. var fired = false;
  198. document.querySelector('.wysihtml5-sandbox').contentWindow.addEventListener('mouseup', function(evt) {
  199. if (!fired) {
  200. if (this.getSelection().type == 'Range') {
  201. var currentFontColor = undefined;
  202. if ( editor.composer.commands.stateValue("fontColorStyle") ) {
  203. currentFontColor = editor.composer.commands.stateValue("fontColorStyle");
  204. }
  205. self.do('initColorpicker', {
  206. initialColor: currentFontColor,
  207. setCallback: function(colorCode){
  208. if ( editor.composer.commands.stateValue("fontColorStyle") !== colorCode ) {
  209. editor.composer.commands.exec('fontColorStyle', colorCode );
  210. }
  211. }
  212. });
  213. }
  214. fired = true;
  215. }
  216. });
  217. });
  218. }
  219. },
  220. closeTextEditor: {
  221. comment: '',
  222. code: function(){
  223. // close routine
  224. this.get('originalElementNode').innerHTML = this.get('textEditor').value;
  225. this.get('originalElementNode').style.display = '';
  226. document.body.removeChild(this.get('textEditorContainer'));
  227. this.get('originalSelection').forEach(function(element){
  228. SuperGlue.get('selection').do('addElement', element)
  229. });
  230. (function(elementNode){
  231. var textContent = elementNode.innerHTML;
  232. SuperGlue.get('history').do('actionHasSucceeded', function(){
  233. elementNode.innerHTML = textContent;
  234. })
  235. }).call(this, this.get('originalElementNode'));
  236. }
  237. },
  238. updateEditorDimensions: {
  239. comment: '',
  240. code: function(){
  241. var currentElement = this.get('originalElementNode'),
  242. top, left;
  243. left = (- parseInt(currentElement.style.borderWidth));
  244. left = top = isNaN(left) ? 0 : left
  245. while(currentElement){
  246. top += (currentElement.offsetTop + currentElement.clientTop );
  247. left += (currentElement.offsetLeft + currentElement.clientLeft);
  248. currentElement = currentElement.offsetParent;
  249. }
  250. this.get('textEditor').style.top = top + 'px';
  251. this.get('textEditor').style.left = left + 'px';
  252. }
  253. },
  254. updateContainerDimensions: {
  255. comment: '',
  256. code: function(textEditorContainer){
  257. var maxWidth = SuperGlue.get('document').do('getMinWidth'),
  258. maxHeight = SuperGlue.get('document').do('getMinHeight');
  259. maxWidth = maxWidth > (window.innerWidth - 20) ? maxWidth : (window.innerWidth - 20);
  260. maxHeight = maxHeight > (window.innerHeight - 20) ? maxHeight : (window.innerHeight - 20);
  261. textEditorContainer.style.width = maxWidth + 'px';
  262. textEditorContainer.style.height = maxHeight + 'px';
  263. }
  264. },
  265. initToolbarBindings: {
  266. comment: 'I initialize event bindings for the textShapeToolbar before wysihtml5 is executed.',
  267. params: {},
  268. code: function() {
  269. var self = this;
  270. var fonts = this.class.get('activeFonts');
  271. var fontTarget = document.querySelector('[title="Font"]').parentNode.querySelector('.dropdown-menu');
  272. for (var i=0; i<fonts.length; i++) {
  273. var fontName = fonts[i];
  274. var fontBtn = document.createElement('li');
  275. fontBtn.innerHTML = '<a data-wysihtml5-command="fontFamilyStyle" data-wysihtml5-command-value="' + fontName +'">'+ fontName + '</a>';
  276. fontTarget.appendChild(fontBtn);
  277. }
  278. var fontSizes = this.class.get('activeFontSizes'),
  279. fontSizeTarget = document.querySelector('[title="Font Size"]').parentNode.querySelector('.dropdown-menu');
  280. for (var s=0; s<fontSizes.length; s++) {
  281. var fontSize = fontSizes[s];
  282. var fontSizeBtn = document.createElement('li');
  283. fontSizeBtn.innerHTML = '<a data-wysihtml5-command="fontSizeStyle" data-wysihtml5-command-value="' + fontSize +'">'+ fontSize + '</a>';
  284. fontSizeTarget.appendChild(fontSizeBtn);
  285. }
  286. document.querySelector('.hyperlink-dropdown input.text').addEventListener('keyup', function (evt) {
  287. evt.stopPropagation();
  288. evt.preventDefault();
  289. });
  290. self.get('textEditorToolbar').querySelector('.hyperlink').addEventListener('click', function() {
  291. var dropdownToggleBtns = self.get('textEditorToolbar').querySelectorAll('.dropdown-toggle');
  292. for (var i=0; i<dropdownToggleBtns.length; i++) {
  293. dropdownToggleBtns[i].classList.remove('active')
  294. }
  295. var dropdownMenuContainers = self.get('textEditorToolbar').querySelectorAll('.dropdown-menu');
  296. for (var i=0; i<dropdownMenuContainers.length; i++) {
  297. dropdownMenuContainers[i].classList.remove('active')
  298. }
  299. document.querySelector('.sg-colorpicker-container-text').classList.remove('active');
  300. for (var d=0; d<dropdownMenus.length; d++) {
  301. dropdownMenus[d].classList.remove('open');
  302. }
  303. if ( this.classList.contains('wysihtml5-command-dialog-opened') ) {
  304. this.nextElementSibling.querySelector('[data-wysihtml5-dialog-action="cancel"]').click();
  305. }
  306. });
  307. var dropdownMenus = self.get('textEditorToolbar').querySelectorAll('.btn');
  308. for (var d=0; d<dropdownMenus.length; d++) {
  309. if ( dropdownMenus[d].classList.contains('dropdown-menu') ) {
  310. dropdownMenus[d].addEventListener('click', function() {
  311. var dropdownClass = 'dropdown-menu';
  312. if ( this.classList.contains('open') ) {
  313. this.nextElementSibling.classList.remove('active');
  314. this.classList.remove('open');
  315. } else {
  316. var dropdownMenuContainers = document.querySelectorAll('.dropdown-menu');
  317. for (var i=0; i<dropdownMenuContainers.length; i++) {
  318. dropdownMenuContainers[i].classList.remove('active')
  319. }
  320. document.querySelector('.sg-colorpicker-container-text').classList.remove('active');
  321. this.nextElementSibling.classList.add('active');
  322. for (var d=0; d<dropdownMenus.length; d++) {
  323. dropdownMenus[d].classList.remove('open');
  324. }
  325. this.classList.add('open');
  326. }
  327. });
  328. }
  329. dropdownMenus[d].addEventListener('mouseenter', function() {
  330. var dropdownMenuContainers = self.get('textEditorToolbar').querySelectorAll('.dropdown-menu');
  331. for (var i=0; i<dropdownMenuContainers.length; i++) {
  332. dropdownMenuContainers[i].classList.remove('active')
  333. }
  334. document.querySelector('.sg-colorpicker-container-text').classList.remove('active');
  335. for (var d=0; d<dropdownMenus.length; d++) {
  336. dropdownMenus[d].classList.remove('open');
  337. if ( dropdownMenus[d].classList.contains('wysihtml5-command-dialog-opened') ) {
  338. dropdownMenus[d].nextElementSibling.querySelector('[data-wysihtml5-dialog-action="cancel"]').click();
  339. }
  340. }
  341. if ( this.classList.contains('dropdown-toggle') ) {
  342. this.nextElementSibling.classList.add('active');
  343. this.classList.add('open');
  344. }
  345. /*
  346. if ( this.classList.contains('hyperlink') ) {
  347. if ( !this.classList.contains('open') ) {
  348. this.click();
  349. } else {
  350. //
  351. }
  352. } else {
  353. this.nextElementSibling.querySelector('a[data-wysihtml5-dialog-action="cancel"]').click();
  354. }
  355. */
  356. });
  357. }
  358. var buttons = document.querySelectorAll('.dropdown-menu li, .dropdown-menu button, .dropdown-menu.input-append a');
  359. for (var b=0; b<buttons.length; b++) {
  360. buttons[b].addEventListener('click', function() {
  361. this.parentNode.classList.remove('active');
  362. for (var d=0; d<dropdownMenus.length; d++) {
  363. dropdownMenus[d].classList.remove('open');
  364. }
  365. });
  366. }
  367. }
  368. },
  369. initColorpicker: {
  370. comment: 'I init my colorpicker. Params: initialColor, setCallback()',
  371. code: function(colorPickerConfig){
  372. var self = this;
  373. // From flexicolorPicker
  374. var colorpickerContainer = this.get('textEditorToolbar').querySelector('.sg-colorpicker-container');
  375. var colorpicker;
  376. // Inputs
  377. var colorpickerInputR,
  378. colorpickerInputB,
  379. colorpickerInputB,
  380. colorpickerInputHex;
  381. var start = function() {
  382. var colorpickerElement = document.createElement('div');
  383. colorpickerElement.classList.add('sg-colorpicker');
  384. colorpickerContainer.appendChild(colorpickerElement);
  385. var colorpickerInputContainer = document.createElement('div');
  386. colorpickerInputContainer.classList.add('sg-colorpicker-input-container');
  387. var colorPickerInputRContainer = document.createElement('div');
  388. colorPickerInputRContainer.setAttribute('data-label', 'R:');
  389. colorpickerInputR = document.createElement('input');
  390. colorpickerInputR.setAttribute('type', 'number');
  391. colorpickerInputR.addEventListener('change', function() {
  392. updatePicker(ColorPicker.rgb2hex({ r: this.value, g: colorpickerInputG.value, b: colorpickerInputB.value }));
  393. });
  394. colorPickerInputRContainer.appendChild(colorpickerInputR);
  395. colorpickerInputContainer.appendChild(colorPickerInputRContainer);
  396. var colorPickerInputGContainer = document.createElement('div');
  397. colorPickerInputGContainer.setAttribute('data-label', 'G:');
  398. colorpickerInputG = document.createElement('input');
  399. colorpickerInputG.setAttribute('type', 'number');
  400. colorpickerInputG.addEventListener('change', function() {
  401. updatePicker(ColorPicker.rgb2hex({ r: colorpickerInputR.value, g: this.value, b: colorpickerInputB.value }));
  402. });
  403. colorPickerInputGContainer.appendChild(colorpickerInputG);
  404. colorpickerInputContainer.appendChild(colorPickerInputGContainer);
  405. var colorPickerInputBContainer = document.createElement('div');
  406. colorPickerInputBContainer.setAttribute('data-label', 'B:');
  407. colorpickerInputB = document.createElement('input');
  408. colorpickerInputB.setAttribute('type', 'number');
  409. colorpickerInputB.addEventListener('change', function() {
  410. updatePicker(ColorPicker.rgb2hex({ r: colorpickerInputR.value, g: colorpickerInputG.value, b: this.value }));
  411. });
  412. colorPickerInputBContainer.appendChild(colorpickerInputB);
  413. colorpickerInputContainer.appendChild(colorPickerInputBContainer);
  414. colorpickerInputHex = document.createElement('input');
  415. colorpickerInputHex.setAttribute('type', 'text');
  416. colorpickerInputHex.addEventListener('change', function() {
  417. updatePicker(this.value);
  418. });
  419. colorpickerInputContainer.appendChild(colorpickerInputHex);
  420. colorpickerContainer.appendChild(colorpickerInputContainer);
  421. colorpicker = ColorPicker(colorpickerElement, updateColor);
  422. self.set({ colorpicker: colorpicker });
  423. //updatePicker(initialColor);
  424. var topColors = getMostUsedColors();
  425. var topColorsContainer = document.createElement('div');
  426. topColorsContainer.classList.add('sg-colorpicker-top-colors');
  427. for (var i=0; i<topColors.length; i++) {
  428. var topColorElement = document.createElement('span');
  429. topColorElement.style.backgroundColor = topColors[i].color;
  430. topColorElement.addEventListener('mousedown', function() {
  431. updatePicker(rgbString2Hex(this.style.backgroundColor));
  432. });
  433. topColorsContainer.appendChild(topColorElement);
  434. }
  435. colorpickerContainer.appendChild(topColorsContainer);
  436. var transparentElement = document.createElement('div');
  437. transparentElement.classList.add('sg-colorpicker-transparent');
  438. transparentElement.addEventListener('mousedown', function() {
  439. colorPickerConfig.setCallback.call(this, '');
  440. });
  441. colorpickerContainer.appendChild(transparentElement);
  442. }
  443. var updateColor = function(hex) {
  444. if ( hex ) {
  445. var rgb = ColorPicker.hex2rgb(hex);
  446. colorpickerInputHex.value = hex;
  447. colorpickerInputR.value = rgb.r;
  448. colorpickerInputG.value = rgb.g;
  449. colorpickerInputB.value = rgb.b;
  450. colorPickerConfig.setCallback.call(this, 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')');
  451. }
  452. }
  453. var updatePicker = function(hex) {
  454. self.get('colorpicker').setHex(hex);
  455. }
  456. var rgbString2Hex = function(rgbString) {
  457. if(rgbString === ''){
  458. return '';
  459. }
  460. if ( rgbString.search("rgb") == -1 ) {
  461. return rgbString;
  462. } else {
  463. rgbString = rgbString.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+))?\)$/);
  464. function hex(x) {
  465. return ("0" + parseInt(x).toString(16)).slice(-2);
  466. }
  467. return "#" + hex(rgbString[1]) + hex(rgbString[2]) + hex(rgbString[3]);
  468. }
  469. };
  470. var getMostUsedColors = function() {
  471. var elements = SuperGlue.get('document').get('children');
  472. var colorArray = [];
  473. for (var i=0; i<elements.length; i++) {
  474. if ( elements[i].get('node').style.backgroundColor.length ) {
  475. colorArray.push(elements[i].get('node').style.backgroundColor);
  476. }
  477. if ( elements[i].get('node').style.borderColor.length ) {
  478. colorArray.push(elements[i].get('node').style.borderColor);
  479. }
  480. }
  481. var frequencyObject = {};
  482. for( var v in colorArray ) {
  483. frequencyObject[colorArray[v]]=(frequencyObject[colorArray[v]] || 0)+1;
  484. }
  485. var frequencyArray = [];
  486. for ( var f in frequencyObject ) {
  487. var newObj = {};
  488. newObj["color"] = f;
  489. newObj["count"] = frequencyObject[f]
  490. frequencyArray.push(newObj);
  491. }
  492. function compare(a,b) {
  493. if (a.count < b.count)
  494. return 1;
  495. if (a.count > b.count)
  496. return -1;
  497. return 0;
  498. }
  499. frequencyArray.sort(compare);
  500. if ( frequencyArray.length > 5 ) {
  501. frequencyArray.slice(0, 5);
  502. }
  503. return frequencyArray;
  504. }
  505. if ( !colorpickerContainer.querySelector('.sg-colorpicker') ) {
  506. var initialColor = undefined;
  507. start();
  508. } else if ( colorPickerConfig.initialColor ) {
  509. var initialColor = rgbString2Hex(colorPickerConfig.initialColor);
  510. updatePicker(initialColor);
  511. }
  512. // End from flexicolorPicker
  513. }
  514. }
  515. }
  516. }});