PageRenderTime 37ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/layout/naviforms.class.php

https://bitbucket.org/navigatecms/navigatecms
PHP | 1269 lines | 1130 code | 127 blank | 12 comment | 62 complexity | f449a4efefda17e8b1ac014f4a51cfd5 MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-2.1, BSD-3-Clause, AGPL-3.0, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. require_once(NAVIGATE_PATH.'/lib/packages/files/file.class.php');
  3. class naviforms
  4. {
  5. public function select_from_object_array($id, $data, $value_field, $title_field, $selected_value="", $style="", $remove_keys=array(), $control_replacement=true)
  6. {
  7. $out = array();
  8. $class = '';
  9. if($control_replacement)
  10. {
  11. $class = 'select2';
  12. }
  13. $out[] = '<select class="'.$class.'" name="'.$id.'" id="'.$id.'" style="'.$style.'">';
  14. if(!is_array($data)) $data = array();
  15. foreach($data as $row)
  16. {
  17. if(in_array($row->{$value_field}, $remove_keys)) continue;
  18. if($row->{$value_field}==$selected_value)
  19. $out[] = '<option value="'.$row->{$value_field}.'" selected="selected">'.$row->{$title_field}.'</option>';
  20. else
  21. $out[] = '<option value="'.$row->{$value_field}.'">'.$row->{$title_field}.'</option>';
  22. }
  23. $out[] = '</select>';
  24. return implode("\n", $out);
  25. }
  26. public function selectfield($id, $values, $texts, $selected_value="", $onChange="", $multiple=false, $titles=array(), $style="", $control_replacement=true, $allow_custom_value=false, $extra_classes="")
  27. {
  28. $class = '';
  29. if($control_replacement)
  30. $class = 'select2';
  31. $class.= ' '.$extra_classes;
  32. $out = array();
  33. if($multiple)
  34. $out[] = '<select name="'.$id.'[]" id="'.$id.'" onchange="'.$onChange.'" multiple="multiple" style=" height: 100px; '.$style.' ">';
  35. else
  36. $out[] = '<select class="'.$class.'" name="'.$id.'" id="'.$id.'" onchange="'.$onChange.'" style="'.$style.'">';
  37. for($i=0; $i < count($values); $i++)
  38. {
  39. if(!isset($titles[$i]))
  40. $titles[$i] = "";
  41. if( (is_array($selected_value) && in_array($values[$i], $selected_value)) ||
  42. ($values[$i]==$selected_value))
  43. $out[] = '<option value="'.$values[$i].'" selected="selected" title="'.$titles[$i].'">'.$texts[$i].'</option>';
  44. else
  45. $out[] = '<option value="'.$values[$i].'" title="'.$titles[$i].'">'.$texts[$i].'</option>';
  46. }
  47. $out[] = '</select>';
  48. if($allow_custom_value)
  49. {
  50. $out[] = '<a href="#" class="uibutton" data-action="create_custom_value"><i class="fa fa-plus"></i></a>';
  51. }
  52. return implode("\n", $out);
  53. }
  54. public function buttonset($name, $options, $default, $onclick="", $jqueryui_icons=array())
  55. {
  56. $buttonset = array();
  57. $buttonset[] = '<div class="buttonset">';
  58. foreach($options as $key => $val)
  59. {
  60. $buttonset[] = '<input type="radio" id="'.$name.'_'.$key.'" name="'.$name.'[]" value="'.$key.'" '.((!is_null($default) && ($default==$key))? ' checked="checked" ' : '').' />';
  61. // $buttonset[] = '<label for="'.$name.'_'.$key.'" onclick="'.$onclick.'"><span class="ui-button-icon-primary ui-icon '.$icon.'" style=" float: left; "></span> '.$val.'</label>';
  62. $buttonset[] = '<label class="unselectable" for="'.$name.'_'.$key.'" onclick="'.$onclick.'">'.$val.'</label>';
  63. }
  64. $buttonset[] = '</div>';
  65. return implode("\n", $buttonset);
  66. }
  67. public function splitbutton($id, $title, $links, $texts)
  68. {
  69. global $layout;
  70. $out = array();
  71. $out[] = '<div id="'.$id.'" class="nv-splitbutton" style="float: left;">';
  72. $out[] = '<a class="'.$id.'_splitbutton_main" href="'.$links[0].'">'.$title.'</a><a href="#">'.t(200, 'Options').'</a>';
  73. $out[] = '</div>';
  74. $out[] = '<ul id="'.$id.'_splitbutton_menu" class="nv_splitbutton_menu" style="display: none; position: absolute; ">';
  75. for($i=0; $i < count($texts); $i++)
  76. $out[] = '<li><a href="'.$links[$i].'">'.$texts[$i].'</a></li>';
  77. $out[] = '</ul>';
  78. $layout->add_script('
  79. $(".'.$id.'_splitbutton_main").splitButton();
  80. ');
  81. return implode("\n", $out);
  82. }
  83. public function hidden($name, $value)
  84. {
  85. return '<input type="hidden" id="'.$name.'" name="'.$name.'" value="'.$value.'" />';
  86. }
  87. public function checkbox($name, $checked=false)
  88. {
  89. if($checked)
  90. $out = '<input id="'.$name.'" name="'.$name.'" type="checkbox" value="1" checked="checked" /><label for="'.$name.'"></label>';
  91. else
  92. $out = '<input id="'.$name.'" name="'.$name.'" type="checkbox" value="1" /><label for="'.$name.'"></label>';
  93. return $out;
  94. }
  95. public function textarea($name, $value="", $rows=4, $cols=48, $style="")
  96. {
  97. $value = htmlspecialchars($value);
  98. $out = '<textarea name="'.$name.'" id="'.$name.'" rows="'.$rows.'" cols="'.$cols.'" style="'.$style.'">'.$value.'</textarea>';
  99. return $out;
  100. }
  101. public function textfield($name, $value="", $width="400px", $action="", $extra="")
  102. {
  103. // may happen when converting a property type from (multilanguage) text to a (single) value
  104. if(is_array($value))
  105. $value = array_pop($value);
  106. $value = htmlspecialchars($value);
  107. if(!empty($width))
  108. $extra .= ' style=" width: '.$width.';"';
  109. if(!empty($action))
  110. $extra .= ' onkeyup="'.$action.'"';
  111. $out = '<input type="text" name="'.$name.'" id="'.$name.'" value="'.$value.'" '.$extra.' />';
  112. return $out;
  113. }
  114. public function decimalfield($name, $value="", $precision=2, $decimal_separator=".", $thousands_separator="", $prefix="", $suffix="", $width="400px", $action="", $extra="")
  115. {
  116. global $layout;
  117. // may happen when converting a property type from (multilanguage) text to a (single) value
  118. if(is_array($value))
  119. $value = array_pop($value);
  120. $value = htmlspecialchars($value);
  121. if(!empty($width))
  122. $extra .= ' style=" width: '.$width.';"';
  123. if(!empty($action))
  124. $extra .= ' onkeyup="'.$action.'"';
  125. if(intval($value) == $value)
  126. $value = intval($value);
  127. $out = '<input type="text" name="'.$name.'" id="'.$name.'" value="'.$value.'" '.$extra.' />';
  128. if(!empty($prefix)) $prefix.= " ";
  129. if(!empty($suffix)) $suffix = " " . $suffix;
  130. $layout->add_script('
  131. $("#'.$name.'").inputmask(
  132. {
  133. alias: "decimal",
  134. rightAlign: false,
  135. digitsOptional: true,
  136. autoGroup: true,
  137. allowMinus: true,
  138. digits: '.$precision.',
  139. radixPoint: "'.$decimal_separator.'",
  140. groupSeparator: "'.$thousands_separator.'",
  141. suffix: "'.$suffix.'",
  142. prefix: "'.$prefix.'"
  143. }
  144. );
  145. ');
  146. return $out;
  147. }
  148. public function autocomplete($name, $value="", $source, $callback='""', $width="400px", $add_custom_value=false)
  149. {
  150. global $layout;
  151. $value = htmlspecialchars($value);
  152. $out = '<input type="text" name="'.$name.'" id="'.$name.'" value="'.$value.'" style=" width: '.$width.';" />';
  153. if(is_array($source))
  154. $source = '["'.implode('","', $source).'"]';
  155. else
  156. $source = '"'.$source.'"';
  157. $layout->add_script('
  158. $("#'.$name.'").autocomplete(
  159. {
  160. source: '.$source.',
  161. minLength: 1,
  162. select: '.$callback.'
  163. });
  164. ');
  165. if($add_custom_value)
  166. {
  167. $uid = uniqid();
  168. $out .= ' <a href="#" class="uibutton" data-action="create_custom_value" data-uid="'.$uid.'"><i class="fa fa-plus"></i></a>';
  169. $layout->add_script('
  170. var naviforms_autocomplete_'.$uid.' = [];
  171. $("a[data-action=create_custom_value][data-uid='.$uid.']").on("click", function()
  172. {
  173. var text = prompt(navigate_t(159, "Name"));
  174. text = text.trim();
  175. if(text != "")
  176. {
  177. naviforms_autocomplete_'.$uid.'.unshift(text);
  178. $("#'.$name.'").val(text);
  179. $("#'.$name.'").trigger("navigate-added-custom-value");
  180. }
  181. });
  182. $("#'.$name.'").on( "autocompleteresponse", function( event, ui )
  183. {
  184. for(i in naviforms_autocomplete_'.$uid.')
  185. ui.content.unshift({ "id": "custom-" + new Date().getTime(), "label": naviforms_autocomplete_'.$uid.'[i], "value": naviforms_autocomplete_'.$uid.'[i]});
  186. });
  187. ');
  188. }
  189. return $out;
  190. }
  191. public function datefield($name, $value="", $hour=false, $style="")
  192. {
  193. global $layout;
  194. global $user;
  195. if(!empty($value))
  196. $value = core_ts2date($value, $hour);
  197. $out = '<input type="text" class="datepicker" name="'.$name.'" id="'.$name.'" value="'.$value.'" style="'.$style.'" />
  198. <img src="img/icons/silk/calendar_delete.png" width="16" height="16" align="absmiddle"
  199. style=" cursor: pointer; " onclick=" $(this).parent().find(\'input\').val(\'\'); $(this).parent().find(\'input\').trigger(\'change\'); " />';
  200. $format = $user->date_format; // custom user date format
  201. // format to jquery ui datepicker
  202. // http://docs.jquery.com/UI/Datepicker/formatDate
  203. $format = php_date_to_jquery_ui_datepicker_format($format);
  204. $translations = '
  205. monthNames: [
  206. "'.t(101, "January").'",
  207. "'.t(102, "February").'",
  208. "'.t(103, "March").'",
  209. "'.t(104, "April").'",
  210. "'.t(105, "May").'",
  211. "'.t(106, "June").'",
  212. "'.t(107, "July").'",
  213. "'.t(108, "August").'",
  214. "'.t(109, "September").'",
  215. "'.t(110, "October").'",
  216. "'.t(111, "November").'",
  217. "'.t(112, "December").'"
  218. ],
  219. monthNamesShort: [
  220. "'.t(113, "Jan").'",
  221. "'.t(114, "Feb").'",
  222. "'.t(115, "Mar").'",
  223. "'.t(116, "Apr").'",
  224. "'.t(117, "May").'",
  225. "'.t(118, "Jun").'",
  226. "'.t(119, "Jul").'",
  227. "'.t(120, "Aug").'",
  228. "'.t(121, "Sept").'",
  229. "'.t(122, "Oct").'",
  230. "'.t(123, "Nov").'",
  231. "'.t(124, "Dec").'"
  232. ],
  233. dayNames: [
  234. "'.t(131, "Sunday").'",
  235. "'.t(125, "Monday").'",
  236. "'.t(126, "Tuesday").'",
  237. "'.t(127, "Wednesday").'",
  238. "'.t(128, "Thursday").'",
  239. "'.t(129, "Friday").'",
  240. "'.t(130, "Saturday").'"
  241. ],
  242. dayNamesShort: [
  243. "'.t(138, "Sun").'",
  244. "'.t(132, "Mon").'",
  245. "'.t(133, "Tue").'",
  246. "'.t(134, "Wed").'",
  247. "'.t(135, "Thu").'",
  248. "'.t(136, "Fri").'",
  249. "'.t(137, "Sat").'"
  250. ],
  251. dayNamesMin: [
  252. "'.t(138, "Sun").'",
  253. "'.t(132, "Mon").'",
  254. "'.t(133, "Tue").'",
  255. "'.t(134, "Wed").'",
  256. "'.t(135, "Thu").'",
  257. "'.t(136, "Fri").'",
  258. "'.t(137, "Sat").'"
  259. ],
  260. prevText: "'.t(501, "Previous").'",
  261. nextText: "'.t(502, "Next").'",
  262. closeText: "'.t(92, "Close").'",
  263. currentText: "'.t(503, "Now").'",
  264. timeText: "'.t(504, "Time").'",
  265. hourText: "'.t(93, "Hour").'",
  266. minuteText: "'.t(94, "Minute").'",
  267. secondText: "'.t(96, "Second").'",
  268. ';
  269. if(!$hour)
  270. {
  271. $format = str_replace('H:i', '', $format);
  272. $layout->add_script('
  273. $("#'.$name.'").datepicker(
  274. {
  275. '.$translations.'
  276. dateFormat: "'.trim($format).'",
  277. changeMonth: true,
  278. changeYear: true
  279. });
  280. ');
  281. }
  282. else
  283. {
  284. $format = str_replace('H:i', '', $format);
  285. $layout->add_script('
  286. navigatecms.forms.datepicker["'.$name.'"] = $("#'.$name.'").datetimepicker(
  287. {
  288. '.$translations.'
  289. dateFormat: "'.trim($format).'",
  290. timeFormat: "HH:mm",
  291. changeMonth: true,
  292. changeYear: true,
  293. timezone: null,
  294. onClose: function()
  295. {
  296. if(navigatecms.forms.datepicker["'.$name.'"].qtip_obj)
  297. {
  298. navigatecms.forms.datepicker["'.$name.'"].qtip_obj.qtip("hide");
  299. navigatecms.forms.datepicker["'.$name.'"].qtip_obj.qtip("disable");
  300. }
  301. },
  302. onChangeMonthYear: function(year, month, instance)
  303. {
  304. setTimeout(function()
  305. {
  306. if(navigatecms.forms.datepicker["'.$name.'"].qtip_obj)
  307. {
  308. navigatecms.forms.datepicker["'.$name.'"].qtip_obj.qtip("hide");
  309. navigatecms.forms.datepicker["'.$name.'"].qtip_obj.qtip("disable");
  310. }
  311. else
  312. {
  313. navigatecms.forms.datepicker["'.$name.'"].qtip_obj = $("table.ui-datepicker-calendar").qtip(
  314. {
  315. content: "'.t(609, "Click a day of the month selected to update the value", null, true).'",
  316. overwrite: true,
  317. show: true,
  318. hide:
  319. {
  320. event: "unfocus"
  321. },
  322. style:
  323. {
  324. tip: true,
  325. width: 200,
  326. classes: "qtip-cream"
  327. },
  328. position:
  329. {
  330. at: "center right",
  331. my: "bottom left"
  332. }
  333. });
  334. }
  335. }, 100);
  336. }
  337. });
  338. ');
  339. }
  340. return $out;
  341. }
  342. public function colorfield($name, $value="#ffffff", $swatches=array(), $onchange='')
  343. {
  344. global $layout;
  345. global $user;
  346. $out = '<input type="text" class="naviforms-colorpicker-text" name="'.$name.'" id="'.$name.'" value="'.$value.'" data-previous="'.$value.'" />
  347. <div id="'.$name.'-selector" class="naviforms-colorpicker-selector ui-corner-all"><div style="background: '.$value.'; "></div></div>';
  348. if(!is_array($swatches) || empty($swatches))
  349. $swatches = array();
  350. $swatches = array_map(function($c) { return hex2rgb($c); }, $swatches);
  351. $swatches_js = "{";
  352. for($s=0; $s < count($swatches); $s++)
  353. {
  354. $swatches_js .= '"'.$s.'": {r:'.($swatches[$s]['r']/255).', g:'.($swatches[$s]['g']/255).', b:'.($swatches[$s]['b']/255).'},';
  355. }
  356. $swatches_js.= "}";
  357. if($swatches_js == "{}")
  358. $swatches_js = "null";
  359. $layout->add_script('
  360. $("input[name=\"'.$name.'\"]").colorpicker({
  361. altField: $("input[name=\"'.$name.'\"]").next().find("> div"),
  362. altOnChange: true,
  363. regional: "'.$user->language.'",
  364. colorFormat: ["#HEX"],
  365. draggable: true,
  366. parts: ["header", "map", "bar", "hex", "hsv", "rgb", "preview", "swatches", "footer"],
  367. //layout: { "memory": [6,0,1,5] },
  368. alpha: false,
  369. showNoneButton: false,
  370. position: {
  371. my: "left top",
  372. at: "right+8 top",
  373. of: $("input[name=\"'.$name.'\"]").next()
  374. },
  375. okOnEnter: true,
  376. revert: true,
  377. swatches: '.$swatches_js.',
  378. swatchesWidth: 80,
  379. open: function(event, color)
  380. {
  381. if($(".ui-colorpicker-dialog").position().top + $(".ui-colorpicker-dialog").height() > $(window).height())
  382. $(".ui-colorpicker-dialog").css("top", $(window).height() - $(".ui-colorpicker-dialog").height() - 8);
  383. $("input[name=\"'.$name.'\"]").data("previous", $("input[name=\"'.$name.'\"]").val());
  384. $("input[name=\"'.$name.'\"]").next().children().css("backgroundColor", $("input[name=\"'.$name.'\"]").data("previous"));
  385. $("input[name=\"'.$name.'\"]").colorpicker("setColor", $("input[name=\"'.$name.'\"]").data("previous"));
  386. },
  387. select: function(event, color)
  388. {
  389. '.(!empty($onchange)? $onchange.'($("input[name=\"'.$name.'\"]"))' : '').'
  390. },
  391. cancel: function(event, color)
  392. {
  393. $("input[name=\"'.$name.'\"]").val($("input[name=\"'.$name.'\"]").data("previous"));
  394. $("input[name=\"'.$name.'\"]").next().children().css("backgroundColor", $("input[name=\"'.$name.'\"]").data("previous"));
  395. }
  396. });
  397. ');
  398. return $out;
  399. }
  400. public function scriptarea($name, $value, $syntax="js", $style= " width: 75%; height: 250px; ")
  401. {
  402. global $layout;
  403. $out = '<textarea name="'.$name.'" id="'.$name.'" style=" '.$style.' " rows="10">'.$value.'</textarea>';
  404. $layout->add_script('
  405. $(window).on("load", function()
  406. {
  407. var cm = CodeMirror.fromTextArea(
  408. document.getElementById("'.$name.'"),
  409. {
  410. mode: "text/html",
  411. tabMode: "indent",
  412. lineNumbers: true,
  413. styleActiveLine: true,
  414. matchBrackets: true,
  415. autoCloseTags: true,
  416. extraKeys: {"Ctrl-Space": "autocomplete"}
  417. }
  418. );
  419. CodeMirror.commands.autocomplete = function(cm) {
  420. CodeMirror.showHint(cm, CodeMirror.htmlHint);
  421. }
  422. navigate_codemirror_instances.push(cm);
  423. $("#'.$name.'").next().attr("style", "'.$style.'");
  424. $(".CodeMirror-scroll").css({ width: "100%", height: "100%"});
  425. cm.refresh();
  426. });
  427. ');
  428. return $out;
  429. }
  430. public function editorfield($name, $value, $width="80%", $lang="es", $website_id=NULL)
  431. {
  432. global $layout;
  433. global $website;
  434. global $user;
  435. $height = 400;
  436. $ws = $website;
  437. if(!empty($website_id) && $website_id!=$website->id)
  438. {
  439. $ws = new website();
  440. $ws->load($website_id);
  441. }
  442. $text = htmlentities($value, ENT_HTML5 | ENT_NOQUOTES, 'UTF-8', true);
  443. // remove unneeded new lines (to fix a problem of extra spaces in pre/code tags)
  444. $text = str_replace('&NewLine;', '', $text);
  445. $out = '<textarea name="'.$name.'" id="'.$name.'" style=" width: '.$width.'; height: '.$height.'px; ">'.$text.'</textarea>';
  446. $content_css = $ws->content_stylesheets('tinymce', 'content');
  447. // note, a file in the "content_selectable" property must also be in the "content" property for TinyMCE to work as expected
  448. $content_css_selectable = $ws->content_stylesheets('tinymce', 'content_selectable');
  449. $tinymce_language = $user->language;
  450. $layout->add_script('
  451. tinyMCE.baseURL = "'.NAVIGATE_URL.'/lib/external/tinymce4";
  452. $("#'.$name.'").tinymce(
  453. {
  454. language: "'.$tinymce_language.'",
  455. width: ($("#'.$name.'").width()) + "px",
  456. height: $("#'.$name.'").height() + "px",
  457. resize: "both",
  458. menubar: false,
  459. theme: "modern",
  460. skin: "navigatecms-cupertino",
  461. plugins: [
  462. "compat3x noneditable",
  463. "advlist autolink nv_link image lists charmap print preview hr anchor pagebreak",
  464. "searchreplace wordcount visualblocks visualchars fullscreen media nonbreaking",
  465. "table directionality template textcolor paste textcolor colorpicker textpattern",
  466. "codesample codemirror importcss imagetools paste magicline fontawesome nv_rollups" // add fullpage to edit full HTML code with head and body tags
  467. ],
  468. external_plugins: {
  469. "loremipsum": "'.NAVIGATE_URL.'/lib/external/tinymce4/plugins/loremipsum/editor_plugin.js",
  470. "imgmap": "'.NAVIGATE_URL.'/lib/external/tinymce4/plugins/imgmap/editor_plugin.js",
  471. "style": "'.NAVIGATE_URL.'/lib/external/tinymce4/plugins/style/editor_plugin.js",
  472. "xhtmlxtras": "'.NAVIGATE_URL.'/lib/external/tinymce4/plugins/xhtmlxtras/editor_plugin.js"
  473. },
  474. toolbar: [
  475. "formatselect fontselect fontsizeselect | forecolor | backcolor | removeformat | searchreplace code",
  476. "bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | outdent indent blockquote | bullist numlist | nv_rollup_special_char",
  477. "styleselect | styleprops attribs | table | nv_rollup_links | image imgmap media codesample | magicline | undo redo"
  478. ],
  479. toolbar_items_size: "small",
  480. // forced fix to avoid tinymce adding <p> element on non block elements (span, i, etc)
  481. // needed mainly for Codemirror plugin, but force_p_newlines is deprecated by the TinyMCE team
  482. forced_root_block: "",
  483. force_br_newlines : true,
  484. force_p_newlines : true,
  485. browser_spellcheck: true,
  486. spellchecker_language: "'.$lang.'",
  487. noneditable_noneditable_class: "fa", // without this, TinyMCE removes the Font Awesome icons when editing the content
  488. media_live_embeds: false, // disable iframe loading (like videos) to allow resizing
  489. magicline_color: "#0070a3",
  490. magicline_targetedItems: ["DIV", "IMG", "IFRAME", "PRE", "TABLE", "ARTICLE", "UL", "OL", "BLOCKQUOTE", "TR"],
  491. magicline_triggerMargin: 24,
  492. codemirror: {
  493. path: "'.NAVIGATE_URL.'/lib/external/codemirror",
  494. indentOnInit: true,
  495. config: {
  496. mode: "htmlmixed",
  497. lineNumbers: true
  498. },
  499. jsFiles: [
  500. "mode/htmlmixed/htmlmixed.js"
  501. ]
  502. },
  503. image_advtab: true,
  504. automatic_uploads: true,
  505. paste_data_images: true,
  506. images_upload_url: "navigate_upload.php?engine=tinymce&session_id='.session_id().'&debug",
  507. fontsize_formats: "8px 9px 10px 11px 12px 13px 14px 15px 16px 17px 18px 20px 24px 26px 28px 30px 32px 36px 42px 48px 56px 64px",
  508. content_css: "'.$content_css.'",
  509. style_formats_merge: true,
  510. importcss_append: false,
  511. importcss_file_filter: function(value)
  512. {
  513. var files = "'.$content_css_selectable.'";
  514. if(files.indexOf(",") > -1)
  515. {
  516. files = files.split(",");
  517. for(var i=0; i < files.length; i++)
  518. {
  519. if(value.indexOf(files[i]) !== -1)
  520. {
  521. return true;
  522. }
  523. }
  524. return false;
  525. }
  526. else
  527. {
  528. return (value==files);
  529. }
  530. },
  531. // https://www.tinymce.com/docs/configure/url-handling
  532. convert_urls: false,
  533. relative_urls: true,
  534. remove_script_host: false,
  535. // https://www.tinymce.com/docs/configure/content-filtering/
  536. valid_elements: "*[*],+a[*],+p[*],#i",
  537. custom_elements: "nv,code,pre,nvlist,nvlist_conditional,figure,article,header,footer,post,nav",
  538. extended_valid_elements: "+nv[*],+pre[*],+code[*],+nvlist[*],+nvlist_conditional[*],+figure[*],+article[*],+nav[*],+i[*],+span[*],+em[*],+b[*],*[*]",
  539. valid_children: "+a[div|p|li],+body[style|script|nv|nvlist|nvlist_conditional],+code[nv|nvlist|nvlist_conditional]",
  540. paste_as_text: true,
  541. // https://www.tinymce.com/docs/configure/content-filtering/#allow_html_in_named_anchor
  542. allow_html_in_named_anchor: true,
  543. // events
  544. handle_event_callback : "navigate_tinymce_event",
  545. // before rendering this tinymce
  546. setup: function(editor)
  547. {
  548. editor.on("init", function()
  549. {
  550. $(editor.getWin()).on("scroll blur focus", function(e)
  551. {
  552. navigate_tinymce_event(e, "'.$name.'");
  553. });
  554. // restore last known iframe scroll position
  555. navigate_tinymce_event({type: "focus"}, "'.$name.'", true);
  556. setTimeout(function()
  557. {
  558. navigate_tinymce_event({type: "focus"}, "'.$name.'", true);
  559. }, 25);
  560. });
  561. },
  562. // just after rendering this tinymce
  563. init_instance_callback: function(editor)
  564. {
  565. // find missing images
  566. $("#'.$name.'").parent().find("iframe").contents().find("img").each(function()
  567. {
  568. if( (typeof this.naturalWidth != "undefined" && this.naturalWidth == 0 )
  569. || this.readyState == "uninitialized" )
  570. {
  571. $(this).addClass("nomagicline");
  572. }
  573. });
  574. $("#'.$name.'").parent().find("iframe").droppable(
  575. {
  576. drop: function(event, ui)
  577. {
  578. if(!$(ui.draggable).attr("id")) // not a file!
  579. {
  580. $("#'.$name.'_tbl").css("opacity", 1);
  581. return;
  582. }
  583. var file_id = $(ui.draggable).attr("id").substring(5);
  584. if(!file_id || file_id=="" || file_id==0) return;
  585. var media = $(ui.draggable).attr("mediatype");
  586. var mime = $(ui.draggable).attr("mimetype");
  587. var web_id = "'.$ws->id.'";
  588. navigate_tinymce_add_content($("#'.$name.':tinymce").attr("id"), file_id, media, mime, web_id, ui.draggable);
  589. $("#'.$name.'").parent().find("> .mce-tinymce").css("opacity", 1);
  590. },
  591. over: function(event, ui)
  592. {
  593. if(!$(ui.draggable).attr("id")) // not a file!
  594. return;
  595. $("#'.$name.'").parent().find("> .mce-tinymce").css("opacity", 0.75);
  596. },
  597. out: function(event, ui)
  598. {
  599. $("#'.$name.'").parent().find("> .mce-tinymce").css("opacity", 1);
  600. }
  601. });
  602. // deprecated, but the only way we found to activate the button on init
  603. tinyMCE.get("'.$name.'").controlManager.setActive("magicline", true);
  604. // user warning to avoid losing unsaved changes
  605. editor.on("change", function()
  606. {
  607. navigate_beforeunload_register();
  608. });
  609. // workaround for TinyMCE 4.6.2 fontsize selector bug
  610. var fontsize_button = $("#'.$name.'").prev().find(".mce-toolbar-grp button").eq(2);
  611. if( $(fontsize_button).find(".mce-txt").length == 0)
  612. $(fontsize_button).append("<span class=\"mce-txt\">12px</span>");
  613. }
  614. });
  615. ');
  616. $layout->navigate_editorfield_link_dialog();
  617. return $out;
  618. }
  619. public function dropbox($name, $value=0, $media="", $disabled=false, $default_value=null, $options=array(), $website_id=null)
  620. {
  621. global $layout;
  622. global $website;
  623. global $theme;
  624. if(empty($website_id))
  625. $website_id = $website->id;
  626. $out = array();
  627. $out[] = '<div id="'.$name.'-droppable-wrapper" class="navigate-droppable-wrapper">';
  628. $out[] = '<input type="hidden" id="'.$name.'" name="'.$name.'" value="'.$value.'" />';
  629. $out[] = '<div id="'.$name.'-droppable" class="navigate-droppable ui-corner-all" data-media="'.$media.'">';
  630. if(!empty($value))
  631. {
  632. if($media=='image')
  633. {
  634. $f = new file();
  635. $f->load($value);
  636. $out[] = '<img title="'.$f->name.'" src="'.NAVIGATE_DOWNLOAD.'?wid='.$website_id.'&id='.$f->id.'&amp;disposition=inline&amp;width=75&amp;height=75"
  637. data-src-original="'.NAVIGATE_DOWNLOAD.'?wid='.$website_id.'&id='.$f->id.'&amp;disposition=inline" />';
  638. }
  639. else if($media=='video')
  640. {
  641. $layout->add_script('
  642. $(window).load(function() { navigate_dropbox_load_video("'.$name.'", "'.$value.'"); });
  643. ');
  644. $out[] = '<figure class="navigatecms_loader"></figure>';
  645. }
  646. else
  647. {
  648. $f = new file();
  649. $f->load($value);
  650. $out[] = '<img title="'.$f->name.'" src="'.(navibrowse::mimeIcon($f->mime, $f->type)).'" width="50" height="50" /><br />'.$f->name;
  651. }
  652. }
  653. else
  654. {
  655. $out[] = ' <img src="img/icons/misc/dropbox.png" vspace="18" />';
  656. }
  657. $out[] = '</div>';
  658. // set parent row as overflow:visible to let the whole contextmenu appear
  659. $layout->add_script('
  660. $(".navigate-droppable-wrapper").parent().css("overflow", "visible");
  661. ');
  662. $contextmenu = false;
  663. if(!$disabled)
  664. {
  665. $out[] = '<div class="navigate-droppable-cancel"><img src="img/icons/silk/cancel.png" /></div>';
  666. if($media=='image')
  667. {
  668. if($options == 'a:0:{}')
  669. $options = array();
  670. if(empty($options) && !empty($default_value))
  671. $options = array($default_value => t(199, "Default value"));
  672. else
  673. $options = (array)$options;
  674. if(!empty($options))
  675. {
  676. $out[] = '
  677. <div class="navigate-droppable-create">
  678. <img src="img/icons/silk/add.png" />
  679. </div>
  680. ';
  681. // "create" context menu actions (image picker)
  682. $ws = new website();
  683. if($website_id==$website->id)
  684. $ws = $website;
  685. else
  686. $ws->load($website_id);
  687. $ws_theme = new theme();
  688. if($website_id==$website->id)
  689. $ws_theme = $theme;
  690. else
  691. $ws_theme->load($ws->theme);
  692. $layout->add_content('
  693. <ul id="'.$name.'-image_picker" class="navigate-image-picker navi-ui-widget-shadow">
  694. '.implode("\n", array_map(
  695. function($k, $v) use ($website_id, $ws_theme)
  696. {
  697. if(!empty($ws_theme))
  698. $v = $ws_theme->t($v);
  699. return '
  700. <li data-value="'.$k.'" data-src="'.NAVIGATE_DOWNLOAD.'?wid='.$website_id.'&id='.$k.'&amp;disposition=inline&amp;width=75&amp;height=75">
  701. <a href="#">
  702. <img title="'.$v.'" src="'.NAVIGATE_DOWNLOAD.'?wid='.$website_id.'&id='.$k.'&amp;disposition=inline&amp;width=48&amp;height=48" />
  703. <span>'.$v.'</span>
  704. </a>
  705. </li>
  706. ';
  707. },
  708. array_keys($options),
  709. array_values($options)
  710. )).'
  711. </ul>
  712. ');
  713. $layout->add_script('
  714. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").on(
  715. "click",
  716. function(ev)
  717. {
  718. navigate_hide_context_menus();
  719. setTimeout(function()
  720. {
  721. $("#'.$name.'-image_picker").menu();
  722. $("#'.$name.'-image_picker").css({left: ev.pageX, top: ev.pageY});
  723. $("#'.$name.'-image_picker").show();
  724. if($("#'.$name.'-image_picker").position().top + $("#'.$name.'-image_picker").height() > $(window).height())
  725. $("#'.$name.'-image_picker").css("top", $(window).height() - $("#'.$name.'-image_picker").height() - 8);
  726. $("#'.$name.'-image_picker li").off().on("click", function()
  727. {
  728. $("#'.$name.'").val($(this).data("value"));
  729. $("#'.$name.'-droppable").html("<img src=\"" + $(this).data("src") + "\" />");
  730. $("#'.$name.'-droppable").parent().find(".navigate-droppable-cancel").show();
  731. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").hide();
  732. });
  733. }, 100);
  734. });
  735. ');
  736. $contextmenu = true;
  737. }
  738. // images: add context menu over the image itself to define focal point, description and title...
  739. $out[] = '
  740. <ul class="navigate-droppable-edit-contextmenu" style="display: none;">
  741. <li action="permissions"><a href="#"><span class="ui-icon ui-icon-key"></span>'.t(17, "Permissions").'</a></li>
  742. <li action="focalpoint"><a href="#"><span class="ui-icon ui-icon-image"></span>'.t(540, "Focal point").'</a></li>
  743. <li action="description"><a href="#"><span class="ui-icon ui-icon-comment"></span>'.t(334, 'Description').'</a></li>
  744. <li action="preview"><a href="#"><span class="ui-icon ui-icon-zoomin"></span>'.t(274, 'Preview').'</a></li>
  745. </ul>
  746. ';
  747. $layout->add_script('
  748. $("#'.$name.'-droppable").on("contextmenu", function(ev)
  749. {
  750. ev.preventDefault();
  751. navigate_hide_context_menus();
  752. var file_id = $("#'.$name.'").val();
  753. if(!file_id || file_id=="" || file_id==0) return;
  754. setTimeout(function()
  755. {
  756. var menu_el = $("#'.$name.'-droppable").parent().find(".navigate-droppable-edit-contextmenu");
  757. var menu_el_clone = menu_el.clone();
  758. menu_el_clone.appendTo("body");
  759. menu_el_clone.menu();
  760. menu_el_clone.css({
  761. "z-index": 100000,
  762. "position": "absolute",
  763. "left": ev.clientX,
  764. "top": ev.clientY
  765. }).addClass("navi-ui-widget-shadow").show();
  766. menu_el_clone.find("a").on("click", function(ev)
  767. {
  768. ev.preventDefault();
  769. var action = $(this).parent().attr("action");
  770. var file_id = $("#'.$name.'").val();
  771. switch(action)
  772. {
  773. case "permissions":
  774. navigate_contextmenu_permissions_dialog(file_id);
  775. break;
  776. case "focalpoint":
  777. navigate_media_browser_focalpoint(file_id);
  778. break;
  779. case "description":
  780. $.get(
  781. NAVIGATE_APP + "?fid=files&act=json&op=description&id=" + file_id,
  782. function(data)
  783. {
  784. data = $.parseJSON(data);
  785. navigate_contextmenu_description_dialog(file_id, $("#'.$name.'-droppable"), data.title, data.description);
  786. }
  787. );
  788. break;
  789. case "preview":
  790. $("#'.$name.'-droppable img[data-src-original]").trigger("dblclick");
  791. break;
  792. }
  793. });
  794. }, 100);
  795. });
  796. ');
  797. }
  798. else if($media=='video')
  799. {
  800. $out[] = '
  801. <div class="navigate-droppable-create">
  802. <img src="img/icons/silk/add.png" />
  803. <ul class="navigate-droppable-create-contextmenu" data-field-id="'.$name.'">
  804. <li action="default" value="'.$default_value.'"><a href="#"><span class="fa fa-lg fa-eraser"></span> '.t(199, "Default value").'</a></li>
  805. <li action="youtube_url"><a href="#"><span class="fa fa-lg fa-youtube-square fa-align-center"></span> Youtube URL</a></li>
  806. <li action="vimeo_url"><a href="#"><span class="fa fa-lg fa-vimeo-square fa-align-center"></span> Vimeo URL</a></li>
  807. </ul>
  808. </div>
  809. ';
  810. // context menu actions
  811. $layout->add_script('
  812. if('.(empty($default_value)? 'true' : 'false').')
  813. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create-contextmenu li[action=default]").remove();
  814. $("#'.$name.'-droppable").parent()
  815. .find(".navigate-droppable-create")
  816. .find(".navigate-droppable-create-contextmenu li")
  817. .on("click", function()
  818. {
  819. setTimeout(function() { navigate_hide_context_menus(); }, 100);
  820. switch($(this).attr("action"))
  821. {
  822. case "default":
  823. $("#'.$name.'-droppable").html(\'<figure class="navigatecms_loader"></figure>\');
  824. navigate_dropbox_load_video("'.$name.'", "'.$default_value.'");
  825. break;
  826. case "youtube_url":
  827. $("<div><form action=\"#\" onsubmit=\"return false;\"><input type=\"text\" name=\"url\" value=\"\" style=\"width: 100%;\" /></form></div>").dialog({
  828. "title": "Youtube URL",
  829. "modal": true,
  830. "width": 500,
  831. "height": 120,
  832. "buttons": {
  833. "'.t(190, "Ok").'": function(e, ui)
  834. {
  835. var reference = navigate_youtube_reference_from_url($(this).find("input").val());
  836. if(reference && reference!="")
  837. {
  838. $("#'.$name.'-droppable").html(\'<figure class="navigatecms_loader"></figure>\');
  839. navigate_dropbox_load_video("'.$name.'", "youtube#" + reference);
  840. }
  841. $(this).dialog("close");
  842. },
  843. "'.t(58, "Cancel").'": function() { $(this).dialog("close"); }
  844. }
  845. });
  846. break;
  847. case "vimeo_url":
  848. $("<div><form action=\"#\" onsubmit=\"return false;\"><input type=\"text\" name=\"url\" value=\"\" style=\"width: 100%;\" /></form></div>").dialog({
  849. "title": "Vimeo URL",
  850. "modal": true,
  851. "width": 500,
  852. "height": 120,
  853. "buttons": {
  854. "'.t(190, "Ok").'": function(e, ui)
  855. {
  856. var reference = navigate_vimeo_reference_from_url($(this).find("input").val());
  857. if(reference && reference!="")
  858. {
  859. $("#'.$name.'-droppable").html(\'<figure class="navigatecms_loader"></figure>\');
  860. navigate_dropbox_load_video("'.$name.'", "vimeo#" + reference);
  861. }
  862. $(this).dialog("close");
  863. },
  864. "'.t(58, "Cancel").'": function() { $(this).dialog("close"); }
  865. }
  866. });
  867. break;
  868. }
  869. }
  870. );
  871. ');
  872. $contextmenu = true;
  873. }
  874. $layout->add_script('
  875. $("#'.$name.'-droppable").parent().find(".navigate-droppable-cancel").on("click", function()
  876. {
  877. $("#'.$name.'").val("0");
  878. $("#'.$name.'-droppable").html(\'<img src="img/icons/misc/dropbox.png" vspace="18" />\');
  879. $("#'.$name.'-droppable").parent().find(".navigate-droppable-cancel").hide();
  880. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").show();
  881. $("#'.$name.'-droppable-info").children().html("");
  882. navigate_media_browser_refresh_files_used();
  883. });
  884. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").on("click", function(ev)
  885. {
  886. navigate_hide_context_menus();
  887. $("ul[data-context-menu-temporary-clone=true]").remove();
  888. setTimeout(function()
  889. {
  890. var menu_el = $("#'.$name.'-droppable").parent().find(".navigate-droppable-create-contextmenu");
  891. menu_el.menu();
  892. menu_el.css({
  893. "z-index": 100000,
  894. "position": "absolute"
  895. }).addClass("navi-ui-widget-shadow").show();
  896. }, 100);
  897. });
  898. ');
  899. if(!empty($media))
  900. $accept = 'accept: ".draggable-'.$media.'",';
  901. $layout->add_script('
  902. $("#'.$name.'-droppable").droppable(
  903. {
  904. '.$accept.'
  905. hoverClass: "navigate-droppable-hover",
  906. drop: function(event, ui)
  907. {
  908. var file_id = $(ui.draggable).attr("id").substring(5);
  909. $("#'.$name.'").val(file_id);
  910. var draggable_content = $(ui.draggable);
  911. if($(draggable_content).find(".file-image-wrapper").length > 0)
  912. {
  913. draggable_content = $(draggable_content).find(".file-image-wrapper").html();
  914. }
  915. else
  916. {
  917. draggable_content = $(ui.draggable).html();
  918. }
  919. $(this).html(draggable_content);
  920. $(this).find("div.file-access-icons").remove();
  921. $("#'.$name.'-droppable").parent().find(".navigate-droppable-cancel").show();
  922. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").hide();
  923. $("#'.$name.'-droppable-info").find(".navigate-droppable-info-title").html("");
  924. $("#'.$name.'-droppable-info").find(".navigate-droppable-info-provider").html("");
  925. $("#'.$name.'-droppable-info").find(".navigate-droppable-info-extra").html("");
  926. }
  927. });
  928. ');
  929. if(empty($value) && $contextmenu)
  930. {
  931. $layout->add_script('
  932. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").show();
  933. $("#'.$name.'-droppable").parent().find(".navigate-droppable-cancel").hide();
  934. ');
  935. }
  936. else if(!empty($value))
  937. {
  938. $layout->add_script('
  939. $("#'.$name.'-droppable").parent().find(".navigate-droppable-cancel").show();
  940. $("#'.$name.'-droppable").parent().find(".navigate-droppable-create").hide();
  941. ');
  942. }
  943. }
  944. $out[] = '<div id="'.$name.'-droppable-info" class="navigate-droppable-info">';
  945. $out[] = ' <div class="navigate-droppable-info-title"></div>';
  946. $out[] = ' <div class="navigate-droppable-info-extra"></div>';
  947. $out[] = ' <div class="navigate-droppable-info-provider"></div>';
  948. $out[] = '</div>';
  949. $out[] = '</div>'; // close droppable wrapper
  950. return implode("\n", $out);
  951. }
  952. public function dropdown_tree($id, $tree, $selected_value="", $on_change="")
  953. {
  954. global $layout;
  955. $out = array();
  956. // TODO: check available dropdown_tree extensions or just use the default
  957. $out[] = '<input type="hidden" id="'.$id.'" name="'.$id.'" value="'.$selected_value.'" />';
  958. $path = "";
  959. $out[] = '<input type="text" id="tree_path_'.$id.'" value="'.$path.'" readonly="true" />';
  960. $out[] = '<img src="img/icons/silk/erase.png" width="16" height="16" align="absmiddle"'.
  961. 'style=" cursor: pointer; " onclick=" tree_wrapper_'.md5($id).'_reset(); " />';
  962. if(!empty($on_change))
  963. $on_change .= '(value);';
  964. if(empty($tree))
  965. $tree = '<ul><li value="0">&nbsp;</li></ul>';
  966. $out[] = '<div style="float: left;" id="tree_wrapper_'.$id.'">'.$tree.'</div>';
  967. $layout->add_script('
  968. $("#tree_wrapper_'.$id.' span").wrap("<a>").css("cursor", "pointer");
  969. $("#tree_wrapper_'.$id.' ul:first").menu({
  970. select: function(event, ui)
  971. {
  972. var value = $(ui.item).attr("value");
  973. if($(ui.item).find("div:first").hasClass("ui-state-disabled"))
  974. value = $("#'.$id.'").val();
  975. $("#'.$id.'").val(value);
  976. tree_wrapper_'.md5($id).'_path(val

Large files files are truncated, but you can click here to view the full file