plugin.php 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. <?php
  2. // PLUGIN INFORMATION
  3. $GLOBALS['plugins'][]['Bookmark'] = array( // Plugin Name
  4. 'name' => 'Bookmark', // Plugin Name
  5. 'author' => 'leet1994', // Who wrote the plugin
  6. 'category' => 'Utilities', // One to Two Word Description
  7. 'link' => '', // Link to plugin info
  8. 'license' => 'personal,business', // License Type use , for multiple
  9. 'idPrefix' => 'BOOKMARK', // html element id prefix
  10. 'configPrefix' => 'BOOKMARK', // config file prefix for array items without the hypen
  11. 'dbPrefix' => 'BOOKMARK', // db prefix
  12. 'version' => '0.1.0', // SemVer of plugin
  13. 'image' => 'api/plugins/bookmark/logo.png', // 1:1 non transparent image for plugin
  14. 'settings' => true, // does plugin need a settings modal?
  15. 'bind' => true, // use default bind to make settings page - true or false
  16. 'api' => 'api/v2/plugins/bookmark/settings', // api route for settings page
  17. 'homepage' => false // Is plugin for use on homepage? true or false
  18. );
  19. // Logo image under Public Domain from https://openclipart.org/detail/182527/open-book
  20. class Bookmark extends Organizr
  21. {
  22. public function writeLog($type = 'error', $message = null, $username = null)
  23. {
  24. parent::writeLog($type, "Plugin 'Bookmark': " . $message, $username);
  25. }
  26. public function _bookmarkGetOrganizrTabInfo()
  27. {
  28. $response = [
  29. array(
  30. 'function' => 'fetch',
  31. 'query' => array(
  32. 'SELECT * FROM tabs',
  33. 'WHERE url = ?',
  34. 'api/v2/plugins/bookmark/page'
  35. )
  36. ),
  37. ];
  38. return $this->processQueries($response);
  39. }
  40. public function _bookmarkGetOrganizrTabGroupId()
  41. {
  42. $tab = $this->_bookmarkGetOrganizrTabInfo();
  43. if ($tab) {
  44. return $tab['group_id'];
  45. } else {
  46. return 999;
  47. }
  48. }
  49. public function _checkRequest($request)
  50. {
  51. $result = false;
  52. if ($this->config['BOOKMARK-enabled'] && $this->hasDB()) {
  53. if (!$this->_checkDatabaseTablesExist()) {
  54. $this->_createDatabaseTables();
  55. }
  56. $result = true;
  57. }
  58. return $result;
  59. }
  60. protected function _checkDatabaseTablesExist()
  61. {
  62. $response = [
  63. array(
  64. 'function' => 'fetchSingle',
  65. 'query' => array(
  66. "SELECT `name` FROM `sqlite_master` WHERE `type` = 'table' AND `name` = 'BOOKMARK-categories'"
  67. ),
  68. 'key' => 'BOOKMARK-categories'
  69. ),
  70. array(
  71. 'function' => 'fetchSingle',
  72. 'query' => array(
  73. "SELECT `name` FROM `sqlite_master` WHERE `type` = 'table' AND `name` = 'BOOKMARK-tabs'"
  74. ),
  75. 'key' => 'BOOKMARK-tabs'
  76. ),
  77. ];
  78. $data = $this->processQueries($response);
  79. return ($data["BOOKMARK-categories"] != false && $data["BOOKMARK-tabs"] != false);
  80. }
  81. protected function _createDatabaseTables()
  82. {
  83. $response = [
  84. array(
  85. 'function' => 'query',
  86. 'query' => 'CREATE TABLE `BOOKMARK-categories` (
  87. `id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
  88. `order` INTEGER,
  89. `category` TEXT UNIQUE,
  90. `category_id` INTEGER,
  91. `default` INTEGER
  92. );'
  93. ),
  94. array(
  95. 'function' => 'query',
  96. 'query' => 'CREATE TABLE `BOOKMARK-tabs` (
  97. `id` INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
  98. `order` INTEGER,
  99. `category_id` INTEGER,
  100. `name` TEXT,
  101. `url` TEXT,
  102. `enabled` INTEGER,
  103. `group_id` INTEGER,
  104. `image` TEXT,
  105. `background_color` TEXT,
  106. `text_color` TEXT
  107. );'
  108. )
  109. ];
  110. $this->processQueries($response);
  111. }
  112. public function _getSettings()
  113. {
  114. return array(
  115. 'custom' => '
  116. <div class="row">
  117. <div class="col-lg-6 col-sm-12 col-md-6">
  118. <div class="white-box">
  119. <h3 class="box-title" lang="en">Automatic Setup Tasks</h3>
  120. <ul class="feeds">
  121. <li class="bookmark-check-tab">
  122. <div class="bg-info">
  123. <i class="sticon ti-layout-tab-v text-white"></i>
  124. </div>
  125. <small lang="en">Checking for Bookmark tab...</small>
  126. <span class="text-muted result"><i class="fa fa-spin fa-refresh"></i></span>
  127. </li>
  128. <li class="bookmark-check-category">
  129. <div class="bg-success">
  130. <i class="ti-layout-list-thumb text-white"></i>
  131. </div>
  132. <small lang="en">Checking for bookmark default category...</small>
  133. <span class="text-muted result"><i class="fa fa-spin fa-refresh"></i></span>
  134. </li>
  135. </ul>
  136. </div>
  137. </div>
  138. <div class="col-lg-6 col-sm-12 col-md-6">
  139. <div class="panel panel-info">
  140. <div class="panel-heading">
  141. <span lang="en">Notice</span>
  142. </div>
  143. <div class="panel-wrapper collapse in" aria-expanded="true">
  144. <div class="panel-body">
  145. <ul class="list-icons">
  146. <li><i class="fa fa-chevron-right text-info"></i> <span lang="en">Add tab that points to <i>api/v2/plugins/bookmark/page</i> and set it\'s type to <i>Organizr</i>.</span></li>
  147. <li><i class="fa fa-chevron-right text-info"></i> <span lang="en">Create Bookmark categories in the new area in <i>Tab Editor</i>.</span></li>
  148. <li><i class="fa fa-chevron-right text-info"></i> <span lang="en">Create Bookmark tabs in the new area in <i>Tab Editor</i>.</span></li>
  149. <li><i class="fa fa-chevron-right text-info"></i> <span lang="en">Open your custom Bookmark page via menu.</span></li>
  150. </ul>
  151. </div>
  152. </div>
  153. </div>
  154. </div>
  155. </div>
  156. '
  157. );
  158. }
  159. public function _getPage()
  160. {
  161. $bookmarks = '<div id="BOOKMARK-wrapper">';
  162. foreach ($this->_getAllCategories() as $category) {
  163. $tabs = $this->_getRelevantTabsForCategory($category['category_id']);
  164. if (count($tabs) == 0) continue;
  165. $bookmarks .= '<div class="BOOKMARK-category">
  166. <div class="BOOKMARK-category-title">
  167. ' . $category['category'] . '
  168. </div>
  169. <div class="BOOKMARK-category-content">';
  170. foreach ($tabs as $tab) {
  171. $bookmarks .= '<a href="' . $tab['url'] . '" target="_SELF">
  172. <div class="BOOKMARK-tab"
  173. style="border-color: ' . $this->adjustBrightness($tab['background_color'], 0.3) . '; background: linear-gradient(90deg, ' . $this->adjustBrightness($tab['background_color'], -0.3) . ' 0%, ' . $tab['background_color'] . ' 70%, ' . $this->adjustBrightness($tab['background_color'], 0.1) . ' 100%);">
  174. <span class="BOOKMARK-tab-image">' . $this->_iconPrefix($tab['image']) . '</span>
  175. <span class="BOOKMARK-tab-title" style="color: ' . $tab['text_color'] . ';">' . $tab['name'] . '</span>
  176. </div>
  177. </a>';
  178. }
  179. $bookmarks .= '</div></div>';
  180. }
  181. $bookmarks .= '</div>';
  182. return $bookmarks;
  183. }
  184. protected function _iconPrefix($source)
  185. {
  186. $tabIcon = explode("::", $source);
  187. $icons = array(
  188. "materialize" => "mdi mdi-",
  189. "fontawesome" => "fa fa-",
  190. "themify" => "ti-",
  191. "simpleline" => "icon-",
  192. "weathericon" => "wi wi-",
  193. "alphanumeric" => "fa-fw",
  194. );
  195. if (is_array($tabIcon) && count($tabIcon) == 2) {
  196. if ($tabIcon[0] !== 'url' && $tabIcon[0] !== 'alphanumeric') {
  197. return '<i class="' . $icons[$tabIcon[0]] . $tabIcon[1] . '"></i>';
  198. } else if ($tabIcon[0] == 'alphanumeric') {
  199. return '<i>' . $tabIcon[1] . '</i>';
  200. } else {
  201. return '<img src="' . $tabIcon[1] . '" alt="tabIcon" />';
  202. }
  203. } else {
  204. return '<img src="' . $source . '" alt="tabIcon" />';
  205. }
  206. }
  207. protected function _getAllCategories()
  208. {
  209. $response = [
  210. array(
  211. 'function' => 'fetchAll',
  212. 'query' => 'SELECT * FROM `BOOKMARK-categories` ORDER BY `order` ASC'
  213. )
  214. ];
  215. return $this->processQueries($response);
  216. }
  217. protected function _getRelevantTabsForCategory($category_id)
  218. {
  219. $response = [
  220. array(
  221. 'function' => 'fetchAll',
  222. 'query' => array(
  223. "SELECT * FROM `BOOKMARK-tabs` WHERE `enabled`='1' AND `category_id`=? AND `group_id`>=? ORDER BY `order` ASC",
  224. $category_id,
  225. $this->getUserLevel()
  226. )
  227. )
  228. ];
  229. return $this->processQueries($response);
  230. }
  231. public function _getTabs()
  232. {
  233. $response = [
  234. array(
  235. 'function' => 'fetchAll',
  236. 'query' => 'SELECT * FROM `BOOKMARK-tabs` ORDER BY `order` ASC',
  237. 'key' => 'tabs'
  238. ),
  239. array(
  240. 'function' => 'fetchAll',
  241. 'query' => 'SELECT * FROM `BOOKMARK-categories` ORDER BY `order` ASC',
  242. 'key' => 'categories'
  243. ),
  244. array(
  245. 'function' => 'fetchAll',
  246. 'query' => 'SELECT * FROM `groups` ORDER BY `group_id` ASC',
  247. 'key' => 'groups'
  248. )
  249. ];
  250. return $this->processQueries($response);
  251. }
  252. // Tabs
  253. public function _getSettingsTabEditorBookmarkTabsPage()
  254. {
  255. $iconSelectors = '
  256. $(".bookmarkTabIconIconList").select2({
  257. ajax: {
  258. url: \'api/v2/icon\',
  259. data: function (params) {
  260. var query = {
  261. search: params.term,
  262. page: params.page || 1
  263. }
  264. return query;
  265. },
  266. processResults: function (data, params) {
  267. params.page = params.page || 1;
  268. return {
  269. results: data.response.data.results,
  270. pagination: {
  271. more: (params.page * 20) < data.response.data.total
  272. }
  273. };
  274. },
  275. //cache: true
  276. },
  277. placeholder: \'Search for an icon\',
  278. templateResult: formatIcon,
  279. templateSelection: formatIcon
  280. });
  281. $(".bookmarkTabIconImageList").select2({
  282. ajax: {
  283. url: \'api/v2/image/select\',
  284. data: function (params) {
  285. var query = {
  286. search: params.term,
  287. page: params.page || 1
  288. }
  289. return query;
  290. },
  291. processResults: function (data, params) {
  292. params.page = params.page || 1;
  293. return {
  294. results: data.response.data.results,
  295. pagination: {
  296. more: (params.page * 20) < data.response.data.total
  297. }
  298. };
  299. },
  300. //cache: true
  301. },
  302. placeholder: \'Search for an image\',
  303. templateResult: formatImage,
  304. templateSelection: formatImage
  305. });
  306. ';
  307. return '
  308. <script>
  309. buildBookmarkTabEditor();
  310. !function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);
  311. $( \'#bookmarkTabEditorTable\' ).sortable({
  312. stop: function () {
  313. $(\'input.order\').each(function(idx) {
  314. $(this).val(idx + 1);
  315. });
  316. var newTabs = $( "#submit-bookmark-tabs-form" ).serializeToJSON();
  317. newBookmarkTabsGlobal = newTabs;
  318. $(\'.saveBookmarkTabOrderButton\').removeClass(\'hidden\');
  319. //submitTabOrder(newTabs);
  320. }
  321. });
  322. $( \'#bookmarkTabEditorTable\' ).disableSelection();
  323. ' . $iconSelectors . '
  324. </script>
  325. <div class="panel bg-org panel-info">
  326. <div class="panel-heading">
  327. <span lang="en">Bookmark Tab Editor</span>
  328. <button type="button" class="btn btn-info btn-circle pull-right popup-with-form m-r-5" href="#new-bookmark-tab-form" onclick="newBookmarkTabForm()" data-effect="mfp-3d-unfold"><i class="fa fa-plus"></i> </button>
  329. <button onclick="submitBookmarkTabOrder(newBookmarkTabsGlobal)" class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right animated loop-animation rubberBand m-r-20 saveBookmarkTabOrderButton hidden" type="button"><span class="btn-label"><i class="fa fa-save"></i></span><span lang="en">Save Tab Order</span></button>
  330. </div>
  331. <div class="table-responsive">
  332. <form id="submit-bookmark-tabs-form" onsubmit="return false;">
  333. <table class="table table-hover manage-u-table">
  334. <thead>
  335. <tr>
  336. <th width="70" class="text-center">#</th>
  337. <th lang="en">NAME</th>
  338. <th lang="en">CATEGORY</th>
  339. <th lang="en">GROUP</th>
  340. <th lang="en" style="text-align:center">ACTIVE</th>
  341. <th lang="en" style="text-align:center">EDIT</th>
  342. <th lang="en" style="text-align:center">DELETE</th>
  343. </tr>
  344. </thead>
  345. <tbody id="bookmarkTabEditorTable">
  346. <td class="text-center" colspan="12"><i class="fa fa-spin fa-spinner"></i></td>
  347. </tbody>
  348. </table>
  349. </form>
  350. </div>
  351. </div>
  352. <form id="new-bookmark-tab-form" class="mfp-hide white-popup-block mfp-with-anim">
  353. <h1 lang="en">Add New Tab</h1>
  354. <fieldset style="border:0;">
  355. <div class="form-group">
  356. <label class="control-label" for="new-bookmark-tab-form-inputName" lang="en">Tab Name</label>
  357. <input type="text" class="form-control" id="new-bookmark-tab-form-inputName" name="name" required="" autofocus>
  358. </div>
  359. <div class="form-group">
  360. <label class="control-label" for="new-bookmark-tab-form-inputURL" lang="en">Tab URL</label>
  361. <input type="text" class="form-control" id="new-bookmark-tab-form-inputURL" name="url" required="">
  362. </div>
  363. <div class="row">
  364. <div class="form-group col-lg-4">
  365. <label class="control-label" for="new-bookmark-tab-form-chooseImage" lang="en">Choose Image</label>
  366. <select class="form-control bookmarkTabIconImageList" id="new-bookmark-tab-form-chooseImage" name="chooseImage"><option lang="en">Select or type Image</option></select>
  367. </div>
  368. <div class="form-group col-lg-4">
  369. <label class="control-label" for="new-bookmark-tab-form-chooseIcon" lang="en">Choose Icon</label>
  370. <select class="form-control bookmarkTabIconIconList" id="new-bookmark-tab-form-chooseIcon" name="chooseIcon"><option lang="en">Select or type Icon</option></select>
  371. </div>
  372. <div class="form-group col-lg-4">
  373. <label class="control-label" for="new-bookmark-tab-form-chooseBlackberry" lang="en">Choose Blackberry Theme Icon</label>
  374. <button id="new-bookmark-tab-form-chooseBlackberry" class="btn btn-xs btn-primary waves-effect waves-light form-control" onclick="showBlackberryThemes(\'new-bookmark-tab-form-inputImageNew\');" type="button">
  375. <i class="fa fa-search"></i>&nbsp; <span lang="en">Choose</span>
  376. </button>
  377. </div>
  378. </div>
  379. <div class="form-group">
  380. <label class="control-label" for="new-bookmark-tab-form-inputImage" lang="en">Tab Image</label>
  381. <input type="text" class="form-control" id="new-bookmark-tab-form-inputImage" name="image" required="">
  382. </div>
  383. <div class="row">
  384. <div class="form-group col-lg-4">
  385. <label class="control-label" for="new-bookmark-tab-form-inputBackgroundColor" lang="en">Background Color</label>
  386. <input type="text" class="form-control bookmark-pick-a-color" id="new-bookmark-tab-form-inputBackgroundColor" name="background_color" required="" value="#fff">
  387. </div>
  388. <div class="form-group col-lg-4">
  389. <label class="control-label" for="new-bookmark-tab-form-inputTextColor" lang="en">Text Color</label>
  390. <input type="text" class="form-control bookmark-pick-a-color" id="new-bookmark-tab-form-inputTextColor" name="text_color" required="" value="#000">
  391. </div>
  392. <div class="form-group col-lg-4">
  393. <label class="control-label" for="new-bookmark-preview" lang="en">Preview</label>
  394. <div id="new-bookmark-preview"></div>
  395. </div>
  396. </div>
  397. </fieldset>
  398. <button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none addNewBookmarkTab" type="button"><span class="btn-label"><i class="fa fa-plus"></i></span><span lang="en">Add Tab</span></button>
  399. <div class="clearfix"></div>
  400. </form>
  401. <form id="edit-bookmark-tab-form" class="mfp-hide white-popup-block mfp-with-anim">
  402. <input type="hidden" name="id" value="x">
  403. <span class="hidden" id="originalBookmarkTabName"></span>
  404. <h1 lang="en">Edit Tab</h1>
  405. <fieldset style="border:0;">
  406. <div class="form-group">
  407. <label class="control-label" for="edit-bookmark-tab-form-inputName" lang="en">Tab Name</label>
  408. <input type="text" class="form-control" id="edit-bookmark-tab-form-inputName" name="name" required="" autofocus>
  409. </div>
  410. <div class="form-group">
  411. <label class="control-label" for="edit-bookmark-tab-form-inputURL" lang="en">Tab URL</label>
  412. <input type="text" class="form-control" id="edit-bookmark-tab-form-inputURL" name="url" required="">
  413. </div>
  414. <div class="row">
  415. <div class="form-group col-lg-4">
  416. <label class="control-label" for="edit-bookmark-tab-form-chooseImage" lang="en">Choose Image</label>
  417. <select class="form-control bookmarkTabIconImageList" id="edit-bookmark-tab-form-chooseImage" name="chooseImage"><option lang="en">Select or type Image</option></select>
  418. </div>
  419. <div class="form-group col-lg-4">
  420. <label class="control-label" for="edit-bookmark-tab-form-chooseIcon" lang="en">Choose Icon</label>
  421. <select class="form-control bookmarkTabIconIconList" id="edit-bookmark-tab-form-chooseIcon" name="chooseIcon"><option lang="en">Select or type Icon</option></select>
  422. </div>
  423. <div class="form-group col-lg-4">
  424. <label class="control-label" for="edit-bookmark-tab-form-chooseBlackberry" lang="en">Choose Blackberry Theme Icon</label>
  425. <button id="edit-bookmark-tab-form-chooseBlackberry" class="btn btn-xs btn-primary waves-effect waves-light form-control" onclick="showBlackberryThemes(\'edit-bookmark-tab-form-inputImage\');" type="button">
  426. <i class="fa fa-search"></i>&nbsp; <span lang="en">Choose</span>
  427. </button>
  428. </div>
  429. </div>
  430. <div class="form-group">
  431. <label class="control-label" for="edit-bookmark-tab-form-inputImage" lang="en">Tab Image</label>
  432. <input type="text" class="form-control" id="edit-bookmark-tab-form-inputImage" name="image" required="">
  433. </div>
  434. <div class="row">
  435. <div class="form-group col-lg-4">
  436. <label class="control-label" for="edit-bookmark-tab-form-inputBackgroundColor" lang="en">Background Color</label>
  437. <input type="text" class="form-control bookmark-pick-a-color" id="edit-bookmark-tab-form-inputBackgroundColor" name="background_color" required="">
  438. </div>
  439. <div class="form-group col-lg-4">
  440. <label class="control-label" for="edit-bookmark-tab-form-inputTextColor" lang="en">Text Color</label>
  441. <input type="text" class="form-control bookmark-pick-a-color" id="edit-bookmark-tab-form-inputTextColor" name="text_color" required="">
  442. </div>
  443. <div class="form-group col-lg-4">
  444. <label class="control-label" for="edit-bookmark-preview" lang="en">Preview</label>
  445. <div id="edit-bookmark-preview"></div>
  446. </div>
  447. </div>
  448. </fieldset>
  449. <button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none editBookmarkTab" type="button"><span class="btn-label"><i class="fa fa-check"></i></span><span lang="en">Edit Tab</span></button>
  450. <div class="clearfix"></div>
  451. </form>
  452. ';
  453. }
  454. public function _isBookmarkTabNameTaken($name, $id = null)
  455. {
  456. if ($id) {
  457. $response = [
  458. array(
  459. 'function' => 'fetchAll',
  460. 'query' => array(
  461. 'SELECT * FROM `BOOKMARK-tabs` WHERE `name` LIKE ? AND `id` != ?',
  462. $name,
  463. $id
  464. )
  465. ),
  466. ];
  467. } else {
  468. $response = [
  469. array(
  470. 'function' => 'fetchAll',
  471. 'query' => array(
  472. 'SELECT * FROM `BOOKMARK-tabs` WHERE `name` LIKE ?',
  473. $name
  474. )
  475. ),
  476. ];
  477. }
  478. return $this->processQueries($response);
  479. }
  480. public function _getNextBookmarkTabOrder()
  481. {
  482. $response = [
  483. array(
  484. 'function' => 'fetchSingle',
  485. 'query' => array(
  486. 'SELECT `order` from `BOOKMARK-tabs` ORDER BY `order` DESC'
  487. )
  488. ),
  489. ];
  490. return $this->processQueries($response);
  491. }
  492. public function _getBookmarkTabById($id)
  493. {
  494. $response = [
  495. array(
  496. 'function' => 'fetch',
  497. 'query' => array(
  498. 'SELECT * FROM `BOOKMARK-tabs` WHERE `id` = ?',
  499. $id
  500. )
  501. ),
  502. ];
  503. return $this->processQueries($response);
  504. }
  505. public function _getTabByIdCheckUser($id)
  506. {
  507. $tabInfo = $this->_getBookmarkTabById($id);
  508. if ($tabInfo) {
  509. if ($this->qualifyRequest($tabInfo['group_id'], true)) {
  510. return $tabInfo;
  511. }
  512. } else {
  513. $this->setAPIResponse('error', 'id not found', 404);
  514. return false;
  515. }
  516. }
  517. public function _deleteTab($id)
  518. {
  519. $response = [
  520. array(
  521. 'function' => 'query',
  522. 'query' => array(
  523. 'DELETE FROM `BOOKMARK-tabs` WHERE id = ?',
  524. $id
  525. )
  526. ),
  527. ];
  528. $tabInfo = $this->_getBookmarkTabById($id);
  529. if ($tabInfo) {
  530. $this->writeLog('success', 'Tab Delete Function - Deleted Tab [' . $tabInfo['name'] . ']', $this->user['username']);
  531. $this->setAPIResponse('success', 'Tab deleted', 204);
  532. return $this->processQueries($response);
  533. } else {
  534. $this->setAPIResponse('error', 'id not found', 404);
  535. return false;
  536. }
  537. }
  538. public function _addTab($array)
  539. {
  540. if (!$array) {
  541. $this->setAPIResponse('error', 'no data was sent', 422);
  542. return null;
  543. }
  544. $array = $this->checkKeys($this->getTableColumnsFormatted('BOOKMARK-tabs'), $array);
  545. $array['group_id'] = ($array['group_id']) ?? $this->getDefaultGroupId();
  546. $array['category_id'] = ($array['category_id']) ?? $this->_getDefaultBookmarkCategoryId();
  547. $array['enabled'] = ($array['enabled']) ?? 0;
  548. $array['order'] = ($array['order']) ?? $this->_getNextBookmarkTabOrder() + 1;
  549. if (array_key_exists('name', $array)) {
  550. if ($this->_isBookmarkTabNameTaken($array['name'])) {
  551. $this->setAPIResponse('error', 'Tab name: ' . $array['name'] . ' is already taken', 409);
  552. return false;
  553. }
  554. } else {
  555. $this->setAPIResponse('error', 'Tab name was not supplied', 422);
  556. return false;
  557. }
  558. if (!array_key_exists('url', $array)) {
  559. $this->setAPIResponse('error', 'Tab url was not supplied', 422);
  560. return false;
  561. }
  562. if (!array_key_exists('image', $array)) {
  563. $this->setAPIResponse('error', 'Tab image was not supplied', 422);
  564. return false;
  565. }
  566. if (array_key_exists('background_color', $array)) {
  567. if (!$this->_checkColorHexCode($array['background_color'])) {
  568. $this->setAPIResponse('error', 'Tab background color is invalid', 422);
  569. return false;
  570. }
  571. } else {
  572. $this->setAPIResponse('error', 'Tab background color was not supplied', 422);
  573. return false;
  574. }
  575. if (array_key_exists('text_color', $array)) {
  576. if (!$this->_checkColorHexCode($array['text_color'])) {
  577. $this->setAPIResponse('error', 'Tab text color is invalid', 422);
  578. return false;
  579. }
  580. } else {
  581. $this->setAPIResponse('error', 'Tab text color was not supplied', 422);
  582. return false;
  583. }
  584. $response = [
  585. array(
  586. 'function' => 'query',
  587. 'query' => array(
  588. 'INSERT INTO [BOOKMARK-tabs]',
  589. $array
  590. )
  591. ),
  592. ];
  593. $this->setAPIResponse(null, 'Tab added');
  594. $this->writeLog('success', 'Tab Editor Function - Added Tab for [' . $array['name'] . ']', $this->user['username']);
  595. return $this->processQueries($response);
  596. }
  597. public function _updateTab($id, $array)
  598. {
  599. if (!$id || $id == '') {
  600. $this->setAPIResponse('error', 'id was not set', 422);
  601. return null;
  602. }
  603. if (!$array) {
  604. $this->setAPIResponse('error', 'no data was sent', 422);
  605. return null;
  606. }
  607. $tabInfo = $this->_getBookmarkTabById($id);
  608. if ($tabInfo) {
  609. $array = $this->checkKeys($tabInfo, $array);
  610. } else {
  611. $this->setAPIResponse('error', 'No tab info found', 404);
  612. return false;
  613. }
  614. if (array_key_exists('name', $array)) {
  615. if ($this->_isBookmarkTabNameTaken($array['name'], $id)) {
  616. $this->setAPIResponse('error', 'Tab name: ' . $array['name'] . ' is already taken', 409);
  617. return false;
  618. }
  619. }
  620. if (array_key_exists('background_color', $array)) {
  621. if (!$this->_checkColorHexCode($array['background_color'])) {
  622. $this->setAPIResponse('error', 'Tab background color is invalid', 422);
  623. return false;
  624. }
  625. }
  626. if (array_key_exists('text_color', $array)) {
  627. if (!$this->_checkColorHexCode($array['text_color'])) {
  628. $this->setAPIResponse('error', 'Tab text color is invalid', 422);
  629. return false;
  630. }
  631. }
  632. $response = [
  633. array(
  634. 'function' => 'query',
  635. 'query' => array(
  636. 'UPDATE `BOOKMARK-tabs` SET',
  637. $array,
  638. 'WHERE id = ?',
  639. $id
  640. )
  641. ),
  642. ];
  643. $this->setAPIResponse(null, 'Tab info updated');
  644. $this->writeLog('success', 'Tab Editor Function - Edited Tab Info for [' . $tabInfo['name'] . ']', $this->user['username']);
  645. return $this->processQueries($response);
  646. }
  647. public function _updateTabOrder($array)
  648. {
  649. if (count($array) >= 1) {
  650. foreach ($array as $tab) {
  651. if (count($tab) !== 2) {
  652. $this->setAPIResponse('error', 'data is malformed', 422);
  653. break;
  654. }
  655. $id = $tab['id'] ?? null;
  656. $order = $tab['order'] ?? null;
  657. if ($id && $order) {
  658. $response = [
  659. array(
  660. 'function' => 'query',
  661. 'query' => array(
  662. 'UPDATE `BOOKMARK-tabs` set `order` = ? WHERE `id` = ?',
  663. $order,
  664. $id
  665. )
  666. ),
  667. ];
  668. $this->processQueries($response);
  669. $this->setAPIResponse(null, 'Tab Order updated');
  670. } else {
  671. $this->setAPIResponse('error', 'data is malformed', 422);
  672. }
  673. }
  674. } else {
  675. $this->setAPIResponse('error', 'data is empty or not in array', 422);
  676. return false;
  677. }
  678. }
  679. // Categories
  680. public function _getSettingsTabEditorBookmarkCategoriesPage()
  681. {
  682. return '
  683. <script>
  684. buildBookmarkCategoryEditor();
  685. $( \'#bookmarkCategoryEditorTable\' ).sortable({
  686. stop: function () {
  687. var inputs = $(\'input.order\');
  688. var nbElems = inputs.length;
  689. inputs.each(function(idx) {
  690. $(this).val(idx + 1);
  691. });
  692. submitBookmarkCategoryOrder();
  693. }
  694. });
  695. </script>
  696. <div class="panel bg-org panel-info">
  697. <div class="panel-heading">
  698. <span lang="en">Bookmark Category Editor</span>
  699. <button type="button" class="btn btn-success btn-circle pull-right popup-with-form m-r-5" href="#new-bookmark-category-form" data-effect="mfp-3d-unfold"><i class="fa fa-plus"></i> </button>
  700. </div>
  701. <div class="table-responsive">
  702. <form id="submit-bookmark-categories-form" onsubmit="return false;">
  703. <table class="table table-hover manage-u-table">
  704. <thead>
  705. <tr>
  706. <th lang="en">NAME</th>
  707. <th lang="en" style="text-align:center">TABS</th>
  708. <th lang="en" style="text-align:center">DEFAULT</th>
  709. <th lang="en" style="text-align:center">EDIT</th>
  710. <th lang="en" style="text-align:center">DELETE</th>
  711. </tr>
  712. </thead>
  713. <tbody id="bookmarkCategoryEditorTable"><td class="text-center" colspan="6"><i class="fa fa-spin fa-spinner"></i></td></tbody>
  714. </table>
  715. </form>
  716. </div>
  717. </div>
  718. <form id="new-bookmark-category-form" class="mfp-hide white-popup-block mfp-with-anim">
  719. <h1 lang="en">Add New Bookmark Category</h1>
  720. <fieldset style="border:0;">
  721. <div class="form-group">
  722. <label class="control-label" for="new-bookmark-category-form-inputName" lang="en">Category Name</label>
  723. <input type="text" class="form-control" id="new-bookmark-category-form-inputName" name="category" required="" autofocus>
  724. </div>
  725. </fieldset>
  726. <button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none addNewBookmarkCategory" type="button"><span class="btn-label"><i class="fa fa-plus"></i></span><span lang="en">Add Category</span></button>
  727. <div class="clearfix"></div>
  728. </form>
  729. <form id="edit-bookmark-category-form" class="mfp-hide white-popup-block mfp-with-anim">
  730. <input type="hidden" name="id" value="">
  731. <h1 lang="en">Edit Category</h1>
  732. <fieldset style="border:0;">
  733. <div class="form-group">
  734. <label class="control-label" for="edit-bookmark-category-form-inputName" lang="en">Category Name</label>
  735. <input type="text" class="form-control" id="edit-bookmark-category-form-inputName" name="category" required="" autofocus>
  736. </div>
  737. </fieldset>
  738. <button class="btn btn-sm btn-info btn-rounded waves-effect waves-light pull-right row b-none editBookmarkCategory" type="button"><span class="btn-label"><i class="fa fa-plus"></i></span><span lang="en">Edit Category</span></button>
  739. <div class="clearfix"></div>
  740. </form>
  741. ';
  742. }
  743. public function _getDefaultBookmarkCategoryId()
  744. {
  745. $response = [
  746. array(
  747. 'function' => 'fetchSingle',
  748. 'query' => array(
  749. 'SELECT `category_id` FROM `BOOKMARK-categories` WHERE `default` = 1'
  750. )
  751. ),
  752. ];
  753. return $this->processQueries($response);
  754. }
  755. public function _getNextBookmarkCategoryOrder()
  756. {
  757. $response = [
  758. array(
  759. 'function' => 'fetchSingle',
  760. 'query' => array(
  761. 'SELECT `order` from `BOOKMARK-categories` ORDER BY `order` DESC'
  762. )
  763. ),
  764. ];
  765. return $this->processQueries($response);
  766. }
  767. public function _getNextBookmarkCategoryId()
  768. {
  769. $response = [
  770. array(
  771. 'function' => 'fetchSingle',
  772. 'query' => array(
  773. 'SELECT `category_id` from `BOOKMARK-categories` ORDER BY `category_id` DESC'
  774. )
  775. ),
  776. ];
  777. return $this->processQueries($response);
  778. }
  779. public function _isBookmarkCategoryNameTaken($name, $id = null)
  780. {
  781. if ($id) {
  782. $response = [
  783. array(
  784. 'function' => 'fetchAll',
  785. 'query' => array(
  786. 'SELECT * FROM `BOOKMARK-categories` WHERE `category` LIKE ? AND `id` != ?',
  787. $name,
  788. $id
  789. )
  790. ),
  791. ];
  792. } else {
  793. $response = [
  794. array(
  795. 'function' => 'fetchAll',
  796. 'query' => array(
  797. 'SELECT * FROM `BOOKMARK-categories` WHERE `category` LIKE ?',
  798. $name
  799. )
  800. ),
  801. ];
  802. }
  803. return $this->processQueries($response);
  804. }
  805. public function _getBookmarkCategoryById($id)
  806. {
  807. $response = [
  808. array(
  809. 'function' => 'fetch',
  810. 'query' => array(
  811. 'SELECT * FROM `BOOKMARK-categories` WHERE `id` = ?',
  812. $id
  813. )
  814. ),
  815. ];
  816. return $this->processQueries($response);
  817. }
  818. public function _clearBookmarkCategoryDefault()
  819. {
  820. $response = [
  821. array(
  822. 'function' => 'query',
  823. 'query' => array(
  824. 'UPDATE `BOOKMARK-categories` SET `default` = 0'
  825. )
  826. ),
  827. ];
  828. return $this->processQueries($response);
  829. }
  830. public function _addCategory($array)
  831. {
  832. if (!$array) {
  833. $this->setAPIResponse('error', 'no data was sent', 422);
  834. return null;
  835. }
  836. $array = $this->checkKeys($this->getTableColumnsFormatted('BOOKMARK-categories'), $array);
  837. $array['default'] = ($array['default']) ?? 0;
  838. $array['order'] = ($array['order']) ?? $this->_getNextBookmarkCategoryOrder() + 1;
  839. $array['category_id'] = ($array['category_id']) ?? $this->_getNextBookmarkCategoryId() + 1;
  840. if (array_key_exists('category', $array)) {
  841. if ($this->_isBookmarkCategoryNameTaken($array['category'])) {
  842. $this->setAPIResponse('error', 'Category name: ' . $array['category'] . ' is already taken', 409);
  843. return false;
  844. }
  845. } else {
  846. $this->setAPIResponse('error', 'Category name was not supplied', 422);
  847. return false;
  848. }
  849. $response = [
  850. array(
  851. 'function' => 'query',
  852. 'query' => array(
  853. 'INSERT INTO [BOOKMARK-categories]',
  854. $array
  855. )
  856. ),
  857. ];
  858. $this->setAPIResponse(null, 'Category added');
  859. $this->writeLog('success', 'Category Editor Function - Added Category for [' . $array['category'] . ']', $this->user['username']);
  860. $result = $this->processQueries($response);
  861. $this->_correctDefaultCategory();
  862. return $result;
  863. }
  864. public function _updateCategory($id, $array)
  865. {
  866. if (!$id || $id == '') {
  867. $this->setAPIResponse('error', 'id was not set', 422);
  868. return null;
  869. }
  870. if (!$array) {
  871. $this->setAPIResponse('error', 'no data was sent', 422);
  872. return null;
  873. }
  874. $categoryInfo = $this->_getBookmarkCategoryById($id);
  875. if ($categoryInfo) {
  876. $array = $this->checkKeys($categoryInfo, $array);
  877. } else {
  878. $this->setAPIResponse('error', 'No category info found', 404);
  879. return false;
  880. }
  881. if (array_key_exists('category', $array)) {
  882. if ($this->_isBookmarkCategoryNameTaken($array['category'], $id)) {
  883. $this->setAPIResponse('error', 'Category name: ' . $array['category'] . ' is already taken', 409);
  884. return false;
  885. }
  886. }
  887. if (array_key_exists('default', $array)) {
  888. if ($array['default']) {
  889. $this->_clearBookmarkCategoryDefault();
  890. }
  891. }
  892. $response = [
  893. array(
  894. 'function' => 'query',
  895. 'query' => array(
  896. 'UPDATE `BOOKMARK-categories` SET',
  897. $array,
  898. 'WHERE id = ?',
  899. $id
  900. )
  901. ),
  902. ];
  903. $this->setAPIResponse(null, 'Category info updated');
  904. $this->writeLog('success', 'Category Editor Function - Edited Category Info for [' . $categoryInfo['category'] . ']', $this->user['username']);
  905. $result = $this->processQueries($response);
  906. $this->_correctDefaultCategory();
  907. return $result;
  908. }
  909. public function _updateCategoryOrder($array)
  910. {
  911. if (count($array) >= 1) {
  912. foreach ($array as $category) {
  913. if (count($category) !== 2) {
  914. $this->setAPIResponse('error', 'data is malformed', 422);
  915. break;
  916. }
  917. $id = $category['id'] ?? null;
  918. $order = $category['order'] ?? null;
  919. if ($id && $order) {
  920. $response = [
  921. array(
  922. 'function' => 'query',
  923. 'query' => array(
  924. 'UPDATE `BOOKMARK-categories` set `order` = ? WHERE `id` = ?',
  925. $order,
  926. $id
  927. )
  928. ),
  929. ];
  930. $this->processQueries($response);
  931. $this->setAPIResponse(null, 'Category Order updated');
  932. } else {
  933. $this->setAPIResponse('error', 'data is malformed', 422);
  934. }
  935. }
  936. } else {
  937. $this->setAPIResponse('error', 'data is empty or not in array', 422);
  938. return false;
  939. }
  940. }
  941. public function _deleteCategory($id)
  942. {
  943. $response = [
  944. array(
  945. 'function' => 'query',
  946. 'query' => array(
  947. 'DELETE FROM `BOOKMARK-categories` WHERE id = ?',
  948. $id
  949. )
  950. ),
  951. ];
  952. $categoryInfo = $this->_getBookmarkCategoryById($id);
  953. if ($categoryInfo) {
  954. $this->writeLog('success', 'Category Delete Function - Deleted Category [' . $categoryInfo['category'] . ']', $this->user['username']);
  955. $this->setAPIResponse('success', 'Category deleted', 204);
  956. $result = $this->processQueries($response);
  957. $this->_correctDefaultCategory();
  958. return $result;
  959. } else {
  960. $this->setAPIResponse('error', 'id not found', 404);
  961. return false;
  962. }
  963. }
  964. protected function _correctDefaultCategory()
  965. {
  966. if ($this->_getDefaultBookmarkCategoryId() == null) {
  967. $response = [
  968. array(
  969. 'function' => 'query',
  970. 'query' => 'UPDATE `BOOKMARK-categories` SET `default` = 1 WHERE `category_id` = (SELECT `category_id` FROM `BOOKMARK-categories` ORDER BY `category_id` ASC LIMIT 0,1)'
  971. )
  972. ];
  973. return $this->processQueries($response);
  974. }
  975. }
  976. protected function _checkColorHexCode($hex)
  977. {
  978. return preg_match('/^\#([0-9a-fA-F]{3}){1,2}$/', $hex);
  979. }
  980. /**
  981. * Increases or decreases the brightness of a color by a percentage of the current brightness.
  982. *
  983. * @param string $hexCode Supported formats: `#FFF`, `#FFFFFF`, `FFF`, `FFFFFF`
  984. * @param float $adjustPercent A number between -1 and 1. E.g. 0.3 = 30% lighter; -0.4 = 40% darker.
  985. *
  986. * @return string
  987. *
  988. * @author maliayas
  989. * @link https://stackoverflow.com/questions/3512311/how-to-generate-lighter-darker-color-with-php
  990. */
  991. protected function adjustBrightness($hexCode, $adjustPercent)
  992. {
  993. $hexCode = ltrim($hexCode, '#');
  994. if (strlen($hexCode) == 3) {
  995. $hexCode = $hexCode[0] . $hexCode[0] . $hexCode[1] . $hexCode[1] . $hexCode[2] . $hexCode[2];
  996. }
  997. $hexCode = array_map('hexdec', str_split($hexCode, 2));
  998. foreach ($hexCode as &$color) {
  999. $adjustableLimit = $adjustPercent < 0 ? $color : 255 - $color;
  1000. $adjustAmount = ceil($adjustableLimit * $adjustPercent);
  1001. $color = str_pad(dechex($color + $adjustAmount), 2, '0', STR_PAD_LEFT);
  1002. }
  1003. return '#' . implode($hexCode);
  1004. }
  1005. public function _checkForBookmarkTab()
  1006. {
  1007. $response = [
  1008. array(
  1009. 'function' => 'fetchAll',
  1010. 'query' => array(
  1011. 'SELECT * FROM tabs',
  1012. 'WHERE url = ?',
  1013. 'api/v2/plugins/bookmark/page'
  1014. )
  1015. ),
  1016. ];
  1017. $tab = $this->processQueries($response);
  1018. if ($tab) {
  1019. $this->setAPIResponse('success', 'Tab already exists', 200);
  1020. return $tab;
  1021. } else {
  1022. $createTab = $this->_createBookmarkTab();
  1023. if ($createTab) {
  1024. $tab = $this->processQueries($response);
  1025. $this->setAPIResponse('success', 'Tab created', 200);
  1026. return $tab;
  1027. } else {
  1028. $this->setAPIResponse('error', 'Tab creation error', 500);
  1029. }
  1030. }
  1031. }
  1032. public function _createBookmarkTab()
  1033. {
  1034. $tabInfo = [
  1035. 'order' => $this->getNextTabOrder() + 1,
  1036. 'category_id' => $this->getDefaultCategoryId(),
  1037. 'name' => 'Bookmarks',
  1038. 'url' => 'api/v2/plugins/bookmark/page',
  1039. 'default' => false,
  1040. 'enabled' => true,
  1041. 'group_id' => $this->getDefaultGroupId(),
  1042. 'image' => 'fontawesome::book',
  1043. 'type' => 0
  1044. ];
  1045. $response = [
  1046. array(
  1047. 'function' => 'query',
  1048. 'query' => array(
  1049. 'INSERT INTO [tabs]',
  1050. $tabInfo
  1051. )
  1052. ),
  1053. ];
  1054. return $this->processQueries($response);
  1055. }
  1056. public function _checkForBookmarkCategories()
  1057. {
  1058. $categories = $this->_getAllCategories();
  1059. if ($categories) {
  1060. $this->setAPIResponse('success', 'Categories already exists', 200);
  1061. return $categories;
  1062. } else {
  1063. $createCategory = $this->_addCategory(['category' => 'Unsorted', 'default' => 1]);
  1064. if ($createCategory) {
  1065. $categories = $this->_getAllCategories();
  1066. $this->setAPIResponse('success', 'Category created', 200);
  1067. return $categories;
  1068. } else {
  1069. $this->setAPIResponse('error', 'Category creation error', 500);
  1070. }
  1071. }
  1072. }
  1073. }