bookmark.php 36 KB

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