PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/app/views/helpers/tricky_file_input.php

http://github.com/Datawalke/Coordino
PHP | 492 lines | 266 code | 77 blank | 149 comment | 71 complexity | 8ab98e8a7f587715b12f4f48b9d6958f MD5 | raw file
  1. <?php
  2. /********************************************************
  3. * TrickyFileInputHelper for CakePHP 1.2.something or whenever
  4. *
  5. * Sorry for the non-conformity to standard documentation guidelines, I usually do my commenting
  6. * all at the end of development, and I usually just want to finish the damn thing so I can either
  7. * get it up and running, or share it. Sooo yeah, I tried to make them as understandable as possible
  8. * so just keep that in mind.
  9. *
  10. * I was creating stylized file inputs, and found out that there was a bit of a problem here: I wanted
  11. * this functionality usable everywhere as a generic file input object. So I created a helper for the
  12. * section, and started making it more and more general, until I realized I should post this as my work
  13. * in the bakery. If you think this code is useful, let let me know.
  14. *
  15. * This software is a CakePHP Helper variation on a whole host of immensely knowledgeable authors and
  16. * amazingly resourceful online documentation. Among them are:
  17. * Shaun Inmann: http://www.shauninman.com/archive/2007/09/10/styling_file_inputs_with_css_and_the_dom
  18. * Michael McGrady: whom I have not been able to pull a site of, but basically thought up the premise. kudos, dude.
  19. *
  20. * So, use the examples provided on the Bakery page, or go to www.vibrantinstincts.com to check out this helper.
  21. * Or, get in touch with me via AIM @ vibrantinstincts. I'd open up some other channel of communication, but I'm
  22. * just motivated enough to write this.
  23. *
  24. * @author Michael Marcos
  25. * @name TrickyFileInput.php
  26. * @version 0.8.10.20 (I've always wanted to make a product with 3 sub-revisions :p)
  27. * @last-updated Fri July 3, 2009 4:13 PM
  28. */
  29. class TrickyFileInputHelper extends AppHelper {
  30. /**
  31. * Chooses the type of Tricky Input to print by default using draw(array()); Must be included in the
  32. * switch statements in the draw functions, or in the list below:
  33. *
  34. * picker
  35. * pickerWithName
  36. *
  37. */
  38. var $defaultType = 'picker';
  39. /**
  40. * Set debug to 'yes' to show debug, and 'no' to hide it. Set 'displayOnFail' to
  41. * 'regular' to display a regular elements (no onverlay) with the default error_classes.
  42. * This way, if it fails, you can still get the element displayed to the user. You can
  43. * choose 'autosubmit', which creates a form wrapped file input that submits onchange.
  44. * Or you can set it to the default: 'none' which displays, shockingly, nothing.
  45. */
  46. var $debug = 'no';
  47. var $displayOnFail = 'autosubmit';
  48. /**
  49. * The array of styles and function of the form elements. Some are defined
  50. * as an enumerated list, please make sure your passed in array follows the
  51. * examples provided, and follows the conventions below:
  52. *
  53. * @index ['form'] can be either an array defined below, or false to not display (default: false)
  54. * @index ['form']['id'] the id of the form (default: tricky_file_form)
  55. * @index ['form']['name'] the name of the form (default: tricky_file_form)
  56. * @index ['form']['action'] the form's action (default: ?)
  57. * @index ['form']['method'] the method of the form, can be either get or post (lowercase) (default: post)
  58. * @index ['input'] the array of options for the input
  59. * @index ['input']['id'] the id of the file input (default: tricky_file_input)
  60. * @index ['input']['name'] the name of the file input (default: tricky_file_input)
  61. * @index ['input']['submitOnChange'] either true or false. determines if the form (required for use) is automatically submitted on change
  62. *
  63. */
  64. var $defaultOptions = array(
  65. 'form' => array(
  66. 'id' => 'tricky_file_form',
  67. 'name' => 'tricky_file_form',
  68. 'action' => '?',
  69. 'method' => 'post'),
  70. 'input' => array(
  71. 'id' => 'tricky_file_input',
  72. 'name' => 'tricky_file_input',
  73. 'submitOnChange' => ''),
  74. 'name' => array(
  75. 'id' => 'tricky_file_name',
  76. 'name' => 'tricky_file_name'),
  77. 'image' => '/img/buttons/choose_image.png');
  78. /**
  79. * The options array that contains the defaults to the same structure as $defaultOptions.
  80. */
  81. var $options = array();
  82. /**
  83. * The number of runs that have been made using the program, to increment HTML values
  84. */
  85. var $runs = 0;
  86. /**
  87. * The array of css styling to avoid conflicts with existing css styles. The styles array
  88. * indexes are as follows:
  89. *
  90. * @index ['div'] the div wrapping the input field (default: pick_file_wrapper)
  91. * @index ['input'] the input field behind the image (default: pick_file)
  92. * @index ['image'] the image above the input (default: pick_file_overlay)
  93. * @index ['name'] the span next to the input, if included
  94. */
  95. var $styles = array(
  96. 'div' => 'pick_file_wrapper',
  97. 'input' => 'pick_file',
  98. 'image' => 'pick_file_overlay',
  99. 'name' => 'pick_file_name');
  100. /**
  101. * The CSS classes that will be displayed if displayOnFail != 'none'
  102. */
  103. var $errorStyles = array(
  104. 'div' => 'pick_file_wrapper_error',
  105. 'input' => 'pick_file_error',
  106. 'image' => 'pick_file_overlay_error',
  107. 'name' => 'pick_file_name_error');
  108. /**
  109. * Array that contains the errors found inside the _findErrors() method.
  110. */
  111. private $errors = array();
  112. /**
  113. * This method can be called using from a view to print a Tricky Element to the
  114. * page. This method accepts a custom type, that must be included in the $this->types
  115. * array. If the element is not found, an error will be displayed.
  116. *
  117. * @param $type the type of tricky element to print
  118. * @param $params the options array that affects the element's attributes
  119. */
  120. function draw($type = null, $params = array()) {
  121. if($type != null) {
  122. switch($type) {
  123. case 'picker':
  124. $this->__picker($params);
  125. break;
  126. case 'pickerWithName':
  127. $this->__pickerWithName($params);
  128. break;
  129. }
  130. } else {
  131. switch($this->defaultType) {
  132. case 'picker':
  133. $this->__picker($params);
  134. break;
  135. case 'pickerWithName':
  136. $this->__pickerWithName($params);
  137. break;
  138. }
  139. }
  140. }
  141. /**
  142. * Called from the draw() function based on the $type parameter to draw
  143. * a file picking button without any other elements.
  144. */
  145. function __picker($params = array()) {
  146. if(!$this->__startup('picker', $params)) {
  147. return;
  148. }
  149. if($this->options['form'] != false) { ?>
  150. <?php $this->__htmlForm(); ?>
  151. <?php $this->__htmlDiv(); ?>
  152. <?php $this->__htmlInput(); ?>
  153. <?php $this->__htmlImage(); ?>
  154. <?php $this->__htmlEndTag('div'); ?>
  155. <?php $this->__htmlEndTag('form'); ?>
  156. <?php } else { ?>
  157. <?php $this->__htmlDiv(); ?>
  158. <?php $this->__htmlInput(); ?>
  159. <?php $this->__htmlImage(); ?>
  160. <?php $this->__htmlEndTag('div'); ?>
  161. <?php }
  162. }
  163. /**
  164. * Called from the draw() function based on the $type parameter to draw
  165. * a file picking button with a disabled text field to show the name of the file.
  166. */
  167. function __pickerWithName($params = array()) {
  168. if(!$this->__startup('pickerWithName', $params)) {
  169. return;
  170. }
  171. if($this->options['form'] != false) {
  172. $this->__htmlForm();
  173. $this->__htmlDiv();
  174. $this->__htmlInput();
  175. $this->__htmlImage();
  176. $this->__htmlEndTag('div');
  177. $this->__htmlName();
  178. $this->__htmlEndTag('form');
  179. } else {
  180. $this->__htmlDiv();
  181. $this->__htmlInput();
  182. $this->__htmlImage();
  183. $this->__htmlEndTag('div');
  184. }
  185. $this->__javascriptNameChange();
  186. }
  187. /**
  188. * Displays a regular file element if the program fails with errors and is requested.
  189. */
  190. function __displayAutosubmit() { ?>
  191. <form
  192. enctype="multipart/form-data"
  193. action="<?=$this->options['form']['action']?>"
  194. id="<?=$this->options['form']['id']?>"
  195. name="<?=$this->options['form']['name']?>"
  196. method="<?=$this->options['form']['method']?>"
  197. >
  198. <div class="<?=$this->errorStyles['div']?>">
  199. <input
  200. type="file"
  201. id="<?=$this->options['input']['id']?>"
  202. name="<?=$this->options['input']['name']?>"
  203. class="<?=$this->errorStyles['input']?>"
  204. onchange="document.<?=$this->options['form']['name']?>.submit();"
  205. />
  206. </div>
  207. </form>
  208. <?php }
  209. /**
  210. * Displays a regular file element if the program fails with errors and is requested.
  211. */
  212. function __displayRegular() { ?>
  213. <div class="<?=$this->errorStyles['div']?>">
  214. <input
  215. type="file"
  216. id="<?=$this->options['input']['id']?>"
  217. name="<?=$this->options['input']['name']?>"
  218. class="<?=$this->errorStyles['input']?>"
  219. onchange="<?=$this->options['input']['submitOnChange']?>"
  220. />
  221. </div>
  222. <?php }
  223. /**
  224. * Increments the default values to prevent overwriting
  225. */
  226. function __incrementDefaultOptionIds() {
  227. if($this->options['form']['name'] == $this->defaultOptions['form']['name']) {
  228. $this->options['form']['name'] = $this->defaultOptions['form']['name'] . '_' . $this->runs;
  229. } if($this->options['form']['id'] == $this->defaultOptions['form']['id']) {
  230. $this->options['form']['id'] = $this->defaultOptions['form']['id'] . '_' . $this->runs;
  231. }
  232. if($this->options['input']['name'] == $this->defaultOptions['input']['name']) {
  233. $this->options['input']['name'] = $this->defaultOptions['input']['name'] . '_' . $this->runs;
  234. } if($this->options['input']['id'] == $this->defaultOptions['input']['id']) {
  235. $this->options['input']['id'] = $this->defaultOptions['input']['id'] . '_' . $this->runs;
  236. }
  237. if($this->options['name']['name'] == $this->defaultOptions['name']['name']) {
  238. $this->options['name']['name'] = $this->defaultOptions['name']['name'] . '_' . $this->runs;
  239. } if($this->options['name']['id'] == $this->defaultOptions['name']['id']) {
  240. $this->options['name']['id'] = $this->defaultOptions['name']['id'] . '_' . $this->runs;
  241. }
  242. }
  243. /**
  244. * Called from the drawing functions to initiate the components.
  245. */
  246. function __startup($type, $params) {
  247. $this->__resetElementOptions();
  248. $this->__getErrors($type, $params);
  249. if(!empty($this->errors)) {
  250. if($this->debug == 'yes') {
  251. $this->__printErrors();
  252. }
  253. if($this->displayOnFail == 'regular') {
  254. $this->__displayRegular();
  255. } else if($this->displayOnFail == 'autosubmit') {
  256. $this->__displayAutosubmit();
  257. }
  258. return false;
  259. }
  260. $this->runs++;
  261. $this->__setOptions($params);
  262. $this->__incrementDefaultOptionIds();
  263. return true;
  264. }
  265. /**
  266. * This method resets the options for the next field to be drawn.
  267. */
  268. function __resetElementOptions() {
  269. $this->options = $this->defaultOptions;
  270. }
  271. /**
  272. * This method prints founds errors.
  273. */
  274. function __printErrors() {
  275. echo '<b>SNAKES IN YOUR PLANE!</b><br/>';
  276. foreach($this->errors as $err) {
  277. echo $err . '<br/>';
  278. }
  279. }
  280. /**
  281. * This method finds any errors, and set the errors array with them.
  282. */
  283. function __getErrors($type, $params) {
  284. if((!isset($params['form']) || $params['form'] == false) && (isset($params['input']['submitOnChange']) && $params['input']['submitOnChange'])) {
  285. $this->errors[] = '<b>Squawk!</b> You cannot autosubmit this element if form is turned off.';
  286. }
  287. if(isset($params['form']['method']) && !($params['form']['method'] == 'post' || $params['form']['method'] == 'get')) {
  288. $this->errors[] = '<b>Sqwawk!</b> Invalid method type (optional: get or post)!';
  289. }
  290. if($type == 'pickerWithName' && isset($params['input']['submitOnChange']) && $params['input']['submitOnChange']) {
  291. $this->errors[] = '<b>Squawk!</b> You cannot autosubmit an element with a name input field';
  292. }
  293. if($type == 'pickerWithName' && $params['form'] !== false) {
  294. $this->errors[] = '<b>Squawk!</b> You cannot create a pickerWithName with a form wrapper! You have to create your own submit.';
  295. }
  296. }
  297. /**
  298. * This method accepts the parameters passed into this helper,
  299. * in preparation for printing the element.
  300. */
  301. function __setOptions($params) {
  302. if(!isset($params) && empty($params)) {
  303. return;
  304. }
  305. /* set form elements */
  306. if(isset($params['form']) && $params['form'] !== false) {
  307. if(isset($params['form']['id'])) { $this->options['form']['id'] = $params['form']['id']; }
  308. if(isset($params['form']['name'])) { $this->options['form']['name'] = $params['form']['name']; }
  309. if(isset($params['form']['method'])) { $this->options['form']['method'] = $params['form']['method']; }
  310. if(isset($params['form']['action'])) { $this->options['form']['action'] = $params['form']['action']; }
  311. } else {
  312. $this->options['form'] = false;
  313. }
  314. /* set input elements */
  315. if(isset($params['input'])) {
  316. if(isset($params['input']['id'])) { $this->options['input']['id'] = $params['input']['id']; }
  317. if(isset($params['input']['name'])) { $this->options['input']['name'] = $params['input']['name']; }
  318. if(isset($params['input']['submitOnChange']) && $params['input']['submitOnChange']) {
  319. $this->options['input']['submitOnChange'] = 'document.' . $this->options['form']['name'] . '.submit();';
  320. }
  321. }
  322. /* set name elements */
  323. if(isset($params['name'])) {
  324. if(isset($params['name']['id'])) { $this->options['name']['id'] = $params['name']['id']; }
  325. if(isset($params['name']['name'])) { $this->options['name']['name'] = $params['name']['name']; }
  326. }
  327. /* set styles elements */
  328. if(isset($params['styles'])) {
  329. if(isset($params['styles']['div'])) { $this->styles['div'] = $params['styles']['div']; }
  330. if(isset($params['styles']['input'])) { $this->styles['input'] = $params['styles']['input']; }
  331. if(isset($params['styles']['image'])) { $this->styles['image'] = $params['styles']['image']; }
  332. if(isset($params['styles']['name'])) { $this->styles['name'] = $params['styles']['name']; }
  333. }
  334. /* set the image */
  335. if(isset($params['image'])) { $this->options['image'] = $params['image']; }
  336. }
  337. /**
  338. * Creates an HTML ending tag based on a tagName
  339. */
  340. function __htmlEndTag($tagName = null) {
  341. echo '</' . $tagName . '>';
  342. }
  343. /**
  344. * Creates a tricky input html form
  345. */
  346. function __htmlForm() { ?>
  347. <form
  348. enctype="multipart/form-data"
  349. action="<?=$this->options['form']['action']?>"
  350. id="<?=$this->options['form']['id']?>"
  351. name="<?=$this->options['form']['name']?>"
  352. method="<?=$this->options['form']['method']?>"
  353. >
  354. <?php }
  355. /**
  356. * Creates a tricky input html div wrapper
  357. */
  358. function __htmlDiv() { ?>
  359. <div class="<?=$this->styles['div']?>">
  360. <?php }
  361. /**
  362. * Creates a tricky input html file input field
  363. */
  364. function __htmlInput() { ?>
  365. <input
  366. type="file"
  367. id="<?=$this->options['input']['id']?>"
  368. name="<?=$this->options['input']['name']?>"
  369. class="<?=$this->styles['input']?>"
  370. onchange="<?=$this->options['input']['submitOnChange']?>"
  371. />
  372. <?php }
  373. /**
  374. * Creates a tricky input html file input field
  375. */
  376. function __htmlInputForName() { ?>
  377. <input
  378. type="file"
  379. id="<?=$this->options['input']['id']?>"
  380. name="<?=$this->options['input']['name']?>"
  381. class="<?=$this->styles['input']?>"
  382. onchange="<?=$this->options['input']['submitOnChange']?>"
  383. />
  384. <?php }
  385. /**
  386. * Creates a tricky input html image
  387. */
  388. function __htmlImage() { ?>
  389. <img
  390. class="<?=$this->styles['image']?>"
  391. src="<?=$this->options['image']?>"
  392. />
  393. <?php }
  394. /**
  395. * Creates a tricky input html name text field
  396. */
  397. function __htmlName() { ?>
  398. <span
  399. id="<?=$this->options['name']['id']?>"
  400. class="<?=$this->styles['name']?>"
  401. ></span>
  402. <?php }
  403. /**
  404. * Creates a javascript onchange
  405. */
  406. function __javascriptNameChange() { ?>
  407. <script type="text/javascript">
  408. document.getElementById("<?=$this->options['input']['id']?>").onchange = function() {
  409. var name = document.getElementById("<?=$this->options['input']['id']?>");
  410. document.getElementById("<?=$this->options['name']['id']?>").innerHTML = name.value;
  411. }
  412. </script>
  413. <?php }
  414. }
  415. ?>