From 5ac83243b1488529f54b4554060b29a708fadf41 Mon Sep 17 00:00:00 2001 From: Sam Hibberd Date: Sun, 28 Feb 2016 13:46:49 +0000 Subject: [PATCH] Version 2.3.0 --- LICENSE.txt | 8 + README.md | 220 ++++++------ fruitlinkit/FruitLinkItPlugin.php | 46 +++ .../fieldtypes/FruitLinkItFieldType.php | 221 ++++++++++++ ...FruitLinkIt_UpdateExistingLinkItFields.php | 140 ++++++++ fruitlinkit/models/FruitLinkIt_LinkModel.php | 324 ++++++++++++++++++ .../models/FruitLinkIt_LinkSettingsModel.php | 64 ++++ fruitlinkit/resources/css/linkit.css | 33 ++ fruitlinkit/resources/js/FruitLinkIt.js | 47 +++ fruitlinkit/services/FruitLinkItService.php | 53 +++ fruitlinkit/templates/_fieldtype/input.html | 134 ++++++++ .../templates/_fieldtype/settings.html | 119 +++++++ 12 files changed, 1308 insertions(+), 101 deletions(-) create mode 100644 LICENSE.txt create mode 100644 fruitlinkit/FruitLinkItPlugin.php create mode 100644 fruitlinkit/fieldtypes/FruitLinkItFieldType.php create mode 100644 fruitlinkit/migrations/m160208_010101_FruitLinkIt_UpdateExistingLinkItFields.php create mode 100644 fruitlinkit/models/FruitLinkIt_LinkModel.php create mode 100644 fruitlinkit/models/FruitLinkIt_LinkSettingsModel.php create mode 100644 fruitlinkit/resources/css/linkit.css create mode 100644 fruitlinkit/resources/js/FruitLinkIt.js create mode 100644 fruitlinkit/services/FruitLinkItService.php create mode 100644 fruitlinkit/templates/_fieldtype/input.html create mode 100644 fruitlinkit/templates/_fieldtype/settings.html diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..c5b4d3a --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2016 Fruit Studios + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index ae40446..3c873e9 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,16 @@ -# Linkit plugin for Craft +# FruitLinkIt plugin for Craft CMS ![Craft 2.5](https://img.shields.io/badge/craft-2.5-red.svg?style=flat-square) One link field to replace them all, a multi-purpose link fieldtype for Craft CMS. -This plugin adds a fieldtype which links to all sorts of stuff, Linkit can currently link to: + +## UPGRADING Pre 2.3.0??? + +See upgrade details below. + + +## FruitLinkIt Overview + +This plugin adds a fieldtype which links to all sorts of stuff, Link It can currently link to: * Entries * Assets @@ -11,120 +19,128 @@ This plugin adds a fieldtype which links to all sorts of stuff, Linkit can curre * Phone numbers * Custom URLs -And it plays really nicely with Matrix! - -Field settings allow you to: +Link It supports Matrix fields and allows you to: -* Configure what elements each field can link too. -* Set which entry/asset sources are available to each field. +* Configure what elements each field can link to. +* Set which element sources are available to each field. * Allow fields to set custom link text. * Allow fields to set links to open in new window. * Set default link text. - ## Installation -To install Linkit, follow these steps: - -1. Upload the linkit/ folder to your craft/plugins/ folder. -2. Go to Settings > Plugins from your Craft control panel and enable the Linkit plugin. -3. Create and configure a new linkit field. - -## Template Usage - -Get the link object: - - {% set yourLink = entry.yourLinkFieldHandle %} - -Just the link - output a pre built HTML link: - - {{ yourLink.link|raw }} - -Build a simple custom link: - - {{ yourLink.linkText }} - -Build your own: - - {% switch yourLink.type %} - - {% case "entry" %} - - {{ yourLink.entry.title }} - - {% case "category" %} - - {{ yourLink.category.title }} - - {% case "asset" %} - - - {% if yourLink.asset.kind == 'image' %} - - {% else %} - - {% endif %} - - - {% case "custom" %} - - - {{ yourLink.linkText }} - - - {% case "email" %} - - {{ yourLink.email }}

- - {% case "tel" %} - - {{ yourLink.tel }}

- - {% endswitch %} - -## Template Variables - -Each link returns a link object which contains the following: - - {% set yourLink = entry.yourLinkFieldHandle %} // Get the link - - {{ yourLink.type }} // Returns the link type - entry, asset, email, tel, custom - - {{ yourLink.email }} // Email String / False - {{ yourLink.custom }} // Custom URL String / False - {{ yourLink.tel }} // Telephone Number / False - {{ yourLink.entry }} // Entry Object / False - {{ yourLink.category }} // Category Object / False - {{ yourLink.asset }} // Asset Object / False - // Each link type is returned - only the active type will return data the rest return false - - {{ yourLink.text }} // The Custom Text String - {{ yourLink.target }} // True/False (Bool) - Open in new window? - - {{ yourLink.url }} // The full url (correct prefix added eg mailto: or tel:) - {{ yourLink.linkText }} // The link text string ready to use (If no custom text is provided it generates it based on the link type) - - {{ yourLink.link }} // Full link HTML ready to use - -## Roadmap - -* Force download option -* Rework the way link data is returned -* Improve handling of target stuff - if it's required -* More Validation Options - - -## Changelog +To install FruitLinkIt, follow these steps: + +1. Download & unzip the file and place the `fruitlinkit` directory into your `craft/plugins` directory +2. Install plugin in the Craft Control Panel under Settings > Plugins + +FruitLinkIt requires Craft 2.5, for pre 2.5 support see releases. + +## Upgrading + +Always ensure you have tested any new releases in a development environment. + +### Upgrading FruitLinkIt (Pre Version 2.3.0) + +Upgrading from a version prior to 2.3.0 please take extra care to backup and test in a development environment. FruitLinkIt will run a migration that automatically updates any existing field settings and content after which it will remove the old version. + +NB. Existing templates will not break but you will get a load of deprecator errors, take a look at the readme file for updated usage guides. + +## Configuring FruitLinkIt + +Add a new Link It field and configure it. Easy. + +## Using FruitLinkIt + + +### Template Variables (Basic Use) + +Just output the custom field to get a ready built html link + + {{ entry.linkItField }} + +or in full + + {{ entry.linkItField.htmlLink }} or {{ entry.linkItField.getHtmlLink() }} + +Customised html link + + {% set attributes = { + title: 'Custom Title', + target: '_self', + class: 'my-class', + "data-custom": 'custom-data-attribute' + } %} + {{ entry.linkItField.htmlLink(attributes) }} + + +### Template Variables (Advanced Use) + +Each Link it field returns a LinkIt model with the following attributes / methods available + + {{ entry.linkItField.type }} (email, custom, tel, entry, category or asset) + {{ entry.linkItField.target }} + {{ entry.linkItField.url }} or {{ entry.linkItField.getUrl() }} + {{ entry.linkItField.text }} or {{ entry.linkItField.getText() }} + +If your link is an element link (asset, entry, category) you also have access to the following: + + {{ entry.linkItField.element }} or {{ entry.linkItField.getElement() }} + +or specific element types + + {{ entry.linkItField.entry }} or {{ entry.linkItField.getEntry() }} + {{ entry.linkItField.asset }} or {{ entry.linkItField.getAsset() }} + {{ entry.linkItField.category }} or {{ entry.linkItField.getCategory() }} + +### Deprecated Template Variables + + {{ linkItField.linkText }} use {{ linkItField.text }} instead. + {{ linkItField.link }} use {{ linkItField }} or {{ linkItField.htmlLink }} instead. + {{ linkItField.email }} use {{ linkItField.url }} instead. + {{ linkItField.custom }} use {{ linkItField.url }} instead. + {{ linkItField.tel }} use {{ linkItField.url }} instead. + +## FruitLinkIt Roadmap + +Some things to do, and ideas for potential features: + +* Add front end template support +* More validation options +* Force download options +* Improved cp field layout + +## FruitLinkIt Changelog + +### 2.3.0 + +Complete rewrite for Craft 2.5.x, same functionality with some UI tweaks and + +* Improved: Now returns a custom validated link model to the template +* Improved: Validation of the link model +* Improved: Template usage - __toSting method now returns full html link +* Improved: Field settings layout +* Added: Facility to customise the html link attributes +* Added: Fully translate Link It +* Fixed: Locale settings bug + +Amongst other stuff :) + + +### 1.0 + +* Updated: Plugin renamed to bring it inline with the rest of our plugins. + ### 0.9.1 -* Fixed: Input field not displaying correctly when set to single type when field had previously been saved. +* Fixed: Input field not displaying correctly when set to single type when field had previously been saved. * Fixed: Custom text returning false. ### 0.9 * Added: Removed the requirement to use the |raw filter when using the link variable. -* Fixed: Input field now corectly displays when on one link type is setup. +* Fixed: Input field now correctly displays when on one link type is setup. ### 0.8.1 @@ -146,6 +162,8 @@ Each link returns a link object which contains the following: * Initial beta release +Brought to you by [Fruit Studios](http://fruitstudios.co.uk) + ## Licence Copyright 2014 Fruit Studios Ltd diff --git a/fruitlinkit/FruitLinkItPlugin.php b/fruitlinkit/FruitLinkItPlugin.php new file mode 100644 index 0000000..69708e8 --- /dev/null +++ b/fruitlinkit/FruitLinkItPlugin.php @@ -0,0 +1,46 @@ +classHandle); + } + + public function onAfterInstall() + { + $migrationClass = 'm160208_010101_FruitLinkIt_UpdateExistingLinkItFields'; + $migration = craft()->migrations->instantiateMigration($migrationClass, $this); + if (!$migration->up()) + { + FruitLinkItPlugin::log("Link It Upgrade Error. Could not run: " . $migrationClass, LogLevel::Error); + } + } + +} diff --git a/fruitlinkit/fieldtypes/FruitLinkItFieldType.php b/fruitlinkit/fieldtypes/FruitLinkItFieldType.php new file mode 100644 index 0000000..7fbd29a --- /dev/null +++ b/fruitlinkit/fieldtypes/FruitLinkItFieldType.php @@ -0,0 +1,221 @@ +templates->render('fruitlinkit/_fieldtype/settings', array( + 'settings' => $this->getSettings(), + 'types' => $this->_getAvaiableLinkItTypes(), + 'elementSources' => craft()->fruitLinkIt->getLinkItElementSources(), + )); + } + + public function getInputHtml($name, $value) + { + // CSS + craft()->templates->includeCssResource('fruitlinkit/css/linkit.css'); + + // Javascript + $id = craft()->templates->formatInputId($name); + craft()->templates->includeJsResource('fruitlinkit/js/FruitLinkIt.js'); + craft()->templates->includeJs('new FruitLinkIt("'.craft()->templates->namespaceInputId($id).'");'); + + // Settings + $settings = $this->getSettings(); + + // LinkIt Types + $availableTypes = $this->_getLinkItTypes(); + $types = array('' => Craft::t('Link To...')); + + if(is_array($settings['types'])) + { + foreach($settings['types'] as $type) + { + $types[$type] = $availableTypes[$type]; + } + } + else + { + $types = $types + $availableTypes; + } + + // Element Select Options + $elementSelectSettings = array( + 'entry' => array( + 'elementType' => new ElementTypeVariable( craft()->elements->getElementType(ElementType::Entry) ), + 'elements' => $value && $value->entry ? array($value->entry) : null, + 'sources' => $settings->entrySources, + 'criteria' => array( + 'status' => null, + ), + 'sourceElementId' => ( isset($this->element->id) ? $this->element->id : null ), + 'limit' => 1, + 'addButtonLabel' => Craft::t($settings->entrySelectionLabel), + 'storageKey' => 'field.'.$this->model->id, + ), + 'asset' => array( + 'elementType' => new ElementTypeVariable( craft()->elements->getElementType(ElementType::Asset) ), + 'elements' => $value && $value->asset ? array($value->asset) : null, + 'sources' => $settings->assetSources, + 'criteria' => array( + 'status' => null, + ), + 'sourceElementId' => ( isset($this->element->id) ? $this->element->id : null ), + 'limit' => 1, + 'addButtonLabel' => Craft::t($settings->assetSelectionLabel), + 'storageKey' => 'field.'.$this->model->id, + ), + 'category' => array( + 'elementType' => new ElementTypeVariable( craft()->elements->getElementType(ElementType::Category) ), + 'elements' => $value && $value->category ? array($value->category) : null, + 'sources' => $settings->categorySources, + 'criteria' => array( + 'status' => null, + ), + 'sourceElementId' => ( isset($this->element->id) ? $this->element->id : null ), + 'limit' => 1, + 'addButtonLabel' => Craft::t($settings->categorySelectionLabel), + 'storageKey' => 'field.'.$this->model->id, + ) + ); + + // Render Field + return craft()->templates->render('fruitlinkit/_fieldtype/input', array( + 'name' => $name, + 'value' => $value, + 'settings' => $settings, + 'types' => $types, + 'elementSelectSettings' => $elementSelectSettings, + )); + } + + /** + * Returns the input value as it should be saved to the database. + * + * @param mixed $value + * @return mixed + */ + public function prepValueFromPost($value) + { + if( is_array($value) && $value['type'] != '' ) + { + return json_encode($value); + } + else + { + return ''; + } + } + + /** + * Preps the field value for use. + * + * @param mixed $value + * @return mixed + */ + public function prepValue($value) + { + return $this->_valueToModel($value); + } + + public function validate($value) + { + if(is_array($value) && $value['type'] != '') + { + $linkModel = $this->_valueToModel($value); + $validated = $linkModel->validate(); + return $validated ? true : $linkModel->getAllErrors(); + } + parent::validate($value); + } + + + // Protected Methods + // ========================================================================= + + protected function getSettingsModel() + { + return new FruitLinkIt_LinkSettingsModel(); + } + + + // Private Methods + // ========================================================================= + + private function _getAvaiableLinkItTypes() + { + $types = $this->_getLinkItTypes(); + $sources = craft()->fruitLinkIt->getLinkItElementSources(); + if(!$sources['entry']) + { + unset($types['entry']); + } + if(!$sources['category']) + { + unset($types['category']); + } + if(!$sources['asset']) + { + unset($types['asset']); + } + return $types; + } + + private function _getLinkItTypes() + { + return array( + 'email' => Craft::t('Email Address'), + 'tel' => Craft::t('Phone Number'), + 'custom' => Craft::t('Custom URL'), + 'entry' => Craft::t('Entry'), + 'category' => Craft::t('Category'), + 'asset' => Craft::t('Asset'), + ); + } + + private function _valueToModel($value, $settings = false) + { + if( is_array($value) && $value['type'] != '' ) + { + $settings = $settings ? $settings : $this->getSettings(); + + $link = new FruitLinkIt_LinkModel; + + $value = $this->_prepLinkItValueArray($value); + + $link->type = isset($value['type']) && $value['type'] != '' ? $value['type'] : false; + $link->value = $link->type ? $value[$link->type] : false; + $link->target = isset($value['target']) ? ($value['target'] == 1 ? '_blank' : false) : false; + $link->customText = isset($value['customText']) ? $value['customText'] : false; + $link->defaultText = $settings->defaultText; + + return $link; + } + + return ''; + } + + private function _prepLinkItValueArray(array $value) + { + // Update pre link it v2.0 array keys + if(array_key_exists('text', $value)) + { + $value['customText'] = $value['text']; + unset($value['text']); + } + return $value; + } + +} diff --git a/fruitlinkit/migrations/m160208_010101_FruitLinkIt_UpdateExistingLinkItFields.php b/fruitlinkit/migrations/m160208_010101_FruitLinkIt_UpdateExistingLinkItFields.php new file mode 100644 index 0000000..bc90304 --- /dev/null +++ b/fruitlinkit/migrations/m160208_010101_FruitLinkIt_UpdateExistingLinkItFields.php @@ -0,0 +1,140 @@ +plugins->getPlugin('fruitlinkit'); + + // Firstly lets check if we have any existing Link It fields + $query = craft()->db->createCommand() + ->select('*') + ->from('fields') + ->where('type = :fruitlinkit OR type = :linkit', array( + 'fruitlinkit' => 'FruitLinkIt_LinkIt', + 'linkit' => 'Linkit_Linkit' + )) + ->queryAll(); + + // Now lets update any existing Link It fields to the new settings structure + $fields = FieldModel::populateModels($query); + if($fields) + { + // Build new default types string + $sources = craft()->fruitLinkIt->getLinkItElementSources(); + $defaultTypes = array('email','tel','custom'); + if($sources['entry']) + { + array_push($defaultTypes, 'entry'); + } + if($sources['category']) + { + array_push($defaultTypes, 'category'); + } + if($sources['asset']) + { + array_push($defaultTypes, 'asset'); + } + + $defaultSettings = array( + 'types' => $defaultTypes, + 'defaultText' => '', + 'allowCustomText' => false, + 'allowTarget' => false, + 'entrySources' => '*', + 'entrySelectionLabel' => 'Select an entry', + 'assetSources' => '*', + 'assetSelectionLabel' => 'Select an asset', + 'categorySources' => '*', + 'categorySelectionLabel' => 'Select a category' + ); + + foreach($fields as $field) + { + $existingSettings = $field->settings; + $settings = $defaultSettings; + + // Same: Sources + $settings['entrySources'] = $existingSettings['entrySources']; + $settings['assetSources'] = $existingSettings['assetSources']; + + // Changed: Types + if($existingSettings['types'] != '*') + { + $settings['types'] = $existingSettings['types']; + } + + // Changed: Allow Target + if(array_key_exists('allowTarget', $existingSettings)) + { + $settings['allowTarget'] = $existingSettings['allowTarget']; + } + elseif(array_key_exists('target', $existingSettings)) + { + $settings['allowTarget'] = $existingSettings['target']; + } + + // Changed: Default Text + if(array_key_exists('defaultText', $existingSettings)) + { + $settings['defaultText'] = $existingSettings['defaultText']; + } + + // Changed: Allow Custom Text + if(array_key_exists('allowCustomText', $existingSettings)) + { + $settings['allowCustomText'] = $existingSettings['allowCustomText']; + } + elseif(array_key_exists('text', $existingSettings)) + { + $settings['allowCustomText'] = $existingSettings['text']; + } + + // Changed: Category Sources + if(array_key_exists('categorySources', $existingSettings)) + { + $settings['categorySources'] = $existingSettings['categorySources']; + } + + // Changed: Entry Selection Label + if(array_key_exists('entrySelectionLabel', $existingSettings)) + { + $settings['entrySelectionLabel'] = $existingSettings['entrySelectionLabel']; + } + + // Changed: Category Selection Label + if(array_key_exists('categorySelectionLabel', $existingSettings)) + { + $settings['categorySelectionLabel'] = $existingSettings['categorySelectionLabel']; + } + + // Changed: Asset Selection Label + if(array_key_exists('assetSelectionLabel', $existingSettings)) + { + $settings['assetSelectionLabel'] = $existingSettings['assetSelectionLabel']; + } + + // Update + $data = array('settings' => JsonHelper::encode($settings)); + if(craft()->db->createCommand()->update('fields', $data, 'id = :id', array(':id' => $field->id))) + { + FruitLinkItPlugin::log('Updated field to latest schema: '.$field->id); + } + else + { + FruitLinkItPlugin::log('Could not update field id: '.$field->id, LogLevel::Error); + } + } + // Uupdate any old version fields fieldtype + craft()->db->createCommand()->update('fields', ['type' => 'FruitLinkIt'], 'type=:fieldType', [':fieldType' => 'FruitLinkIt_LinkIt']); + craft()->db->createCommand()->update('fields', ['type' => 'FruitLinkIt'], 'type=:fieldType', [':fieldType' => 'Linkit_Linkit']); + + } + + // Now delete the old version + craft()->db->createCommand()->delete('plugins', "class = 'Linkit'"); + + return true; + } +} diff --git a/fruitlinkit/models/FruitLinkIt_LinkModel.php b/fruitlinkit/models/FruitLinkIt_LinkModel.php new file mode 100644 index 0000000..f5c6f66 --- /dev/null +++ b/fruitlinkit/models/FruitLinkIt_LinkModel.php @@ -0,0 +1,324 @@ + array(AttributeType::String, 'default' => false), + 'value' => array(AttributeType::String, 'default' => false), + 'defaultText' => array(AttributeType::String, 'default' => false), + 'customText' => array(AttributeType::String, 'default' => false), + 'target' => array(AttributeType::String, 'default' => false), + ); + } + + public function __toString() + { + $htmlLink = $this->getHtmlLink(); + return $htmlLink ? (string) $htmlLink : ''; + } + + public function getHtmlLink($attributes = false) + { + $url = $this->getUrl(); + $text = $this->getText(); + if($url && $text) + { + // Open Link + $htmlLink = 'target ) + { + $htmlLink .= ' target="'.$this->target.'"'; + } + + // Add Attributes + if(is_array($attributes)) + { + foreach ($attributes as $attr => $value) + { + $htmlLink .= ' '.$attr.'="'.$value.'"'; + } + } + + // Close Up Link + $htmlLink .= '>'.$text.''; + + // Get Raw + return TemplateHelper::getRaw($htmlLink); + } + return false; + } + + + public function getUrl() + { + $url = false; + switch ($this->type) + { + case('entry'): + $entry = $this->_entry ? $this->_entry : $this->getEntry(); + if($entry) + { + $url = $entry->status == 'live' ? $entry->getUrl() : false; + } + break; + case('asset'): + $asset = $this->_asset ? $this->_asset : $this->getAsset(); + if($asset) + { + $url = $asset->getUrl(); + } + break; + case('category'): + $category = $this->_category ? $this->_category : $this->getCategory(); + if($category) + { + $url = $category->enabled ? $category->getUrl() : false; + } + break; + case('custom'): + $url = $this->value; + break; + case('tel'): + $url = 'tel:'.str_replace(' ', '', $this->value); + break; + case('email'): + $url = 'mailto:'.$this->value; + break; + } + return $url; + } + + + public function getText() + { + if($this->customText) + { + return $this->customText; + } + + if($this->defaultText) + { + return $this->defaultText; + } + + $text = ''; + switch ($this->type) + { + case('entry'): + $entry = $this->_entry ? $this->_entry : $this->getEntry(); + if($entry) + { + $text = $entry->title; + } + break; + case('asset'): + $asset = $this->_asset ? $this->_asset : $this->getAsset(); + if($asset) + { + $text = $asset->title; + } + break; + case('category'): + $category = $this->_category ? $this->_category : $this->getCategory(); + if($category) + { + $text = $category->title; + } + break; + default: + $text = $this->value; + break; + + } + return $text; + } + + + public function getElement() + { + + switch ($this->type) + { + case('entry'): + $element = $this->entry; + break; + case('asset'): + $element = $this->asset; + break; + case('category'): + $element = $this->category; + break; + default: + $element = false; + } + return $element; + } + + + public function getEntry() + { + if($this->type != 'entry') + { + return false; + } + + if(!$this->_entry) + { + $id = is_array($this->value) ? $this->value[0] : false; + if( $id && $entry = craft()->entries->getEntryById($id) ) + { + + $this->_entry = $entry; + } + } + return $this->_entry; + } + + + public function getAsset() + { + if($this->type != 'asset') + { + return false; + } + + if(!$this->_asset) + { + $id = is_array($this->value) ? $this->value[0] : false; + if( $id && $asset = craft()->assets->getFileById($id) ) + { + $this->_asset = $asset; + } + } + return $this->_asset; + } + + + public function getCategory() + { + if($this->type != 'category') + { + return false; + } + + if(!$this->_category) + { + $id = is_array($this->value) ? $this->value[0] : false; + if( $id && $category = craft()->categories->getCategoryById($id) ) + { + $this->_category = $category; + } + } + return $this->_category; + } + + public function validate($attributes = null, $clearErrors = true) + { + switch($this->type) + { + case('email'): + if( !filter_var($this->value, FILTER_VALIDATE_EMAIL) ) + { + $this->addError('value', Craft::t('Please enter a valid email address.')); + } + break; + + case('tel'): + $regexp = '/^[0-9+\(\)#\.\s\/ext-]+$/'; + if(!filter_var($this->value, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => $regexp)))) + { + $this->addError('value', Craft::t('Please enter a valid telephone.')); + } + break; + + case('custom'): + if(!filter_var($this->value, FILTER_VALIDATE_URL) && $this->value == '#') + { + $this->addError('value', Craft::t('Please enter a valid url.')); + } + break; + + case('entry'): + if($this->value == '') + { + $this->addError('value', Craft::t('Please select an entry.')); + } + break; + + case('asset'): + if($this->value == '') + { + $this->addError('value', Craft::t('Please select an asset.')); + } + break; + + case('category'): + if($this->value == '') + { + $this->addError('value', Craft::t('Please select a category.')); + } + break; + } + + return !$this->hasErrors(); + } + + + + // Deprecated: Pre Link It 2.0 + public function getLinkText() + { + craft()->deprecator->log('FruitLinkIt', '{{ linkItField.linkText }} has been deprecated. Use {{ linkItField.text }} instead.'); + return $this->getText(); + } + + public function getLink() + { + craft()->deprecator->log('FruitLinkIt', '{{ linkItField.link }} has been deprecated. Use {{ linkItField }} or {{ linkItField.htmlLink }} instead.'); + return $this->getHtmlLink(); + } + + public function getEmail() + { + craft()->deprecator->log('FruitLinkIt', '{{ linkItField.email }} has been deprecated. Use {{ linkItField.url }} instead.'); + return $this->getUrl(); + } + + public function getCustom() + { + craft()->deprecator->log('FruitLinkIt', '{{ linkItField.custom }} has been deprecated. Use {{ linkItField.url }} instead.'); + return $this->getUrl(); + } + + public function getTel() + { + craft()->deprecator->log('FruitLinkIt', '{{ linkItField.tel }} has been deprecated. Use {{ linkItField.url }} instead.'); + return $this->getUrl(); + } + +} diff --git a/fruitlinkit/models/FruitLinkIt_LinkSettingsModel.php b/fruitlinkit/models/FruitLinkIt_LinkSettingsModel.php new file mode 100644 index 0000000..9c7c585 --- /dev/null +++ b/fruitlinkit/models/FruitLinkIt_LinkSettingsModel.php @@ -0,0 +1,64 @@ + AttributeType::Mixed, + 'allowCustomText' => AttributeType::Bool, + 'defaultText' => AttributeType::String, + 'allowTarget' => AttributeType::Bool, + + 'entrySources' => AttributeType::Mixed, + 'entrySelectionLabel' => array(AttributeType::String, 'default' => Craft::t('Select an entry')), + + 'assetSources' => AttributeType::Mixed, + 'assetSelectionLabel' => array(AttributeType::String, 'default' => Craft::t('Select an asset')), + + 'categorySources' => AttributeType::Mixed, + 'categorySelectionLabel' => array(AttributeType::String, 'default' => Craft::t('Select a category')), + ); + } + + public function validate($attributes = null, $clearErrors = true) + { + parent::validate($attributes, $clearErrors); + + if(is_array($this->types)) + { + if( in_array('entry', $this->types) && $this->entrySources == '') + { + $this->addError('entrySources', Craft::t('Please select at least 1 entry source.')); + } + + if( in_array('asset', $this->types) && $this->assetSources == '') + { + $this->addError('assetSources', Craft::t('Please select at least 1 asset source.')); + } + + if( in_array('category', $this->types) && $this->categorySources == '') + { + $this->addError('categorySources', Craft::t('Please select at least 1 category source.')); + } + } + else + { + $this->addError('types', Craft::t('Please select at least 1 link type.')); + } + + return !$this->hasErrors(); + } +} diff --git a/fruitlinkit/resources/css/linkit.css b/fruitlinkit/resources/css/linkit.css new file mode 100644 index 0000000..e747287 --- /dev/null +++ b/fruitlinkit/resources/css/linkit.css @@ -0,0 +1,33 @@ +.fruit-field { + overflow: hidden; +} +.fruit-field-column { + width: 50%; + float:left; +} +.fruit-field-column:first-child div { + padding-right: 8px; +} +.fruit-field-column:last-child div { + padding-left: 8px; +} +.fruit-field-column .checkboxfield { + padding-top: 5px; +} +.fruitlinkit {} +.fruitlinkit-type { + float:left; + margin-bottom:16px; + margin-right: 16px; +} +.fruitlinkit-type select { max-width: 130px; } +.fruitlinkit-options { + float:left; +} +.fruitlinkit-option, +.fruitlinkit-text, +.fruitlinkit-target { margin-bottom:16px; } + +.fruitlinkit-settings { + clear:both; +} diff --git a/fruitlinkit/resources/js/FruitLinkIt.js b/fruitlinkit/resources/js/FruitLinkIt.js new file mode 100644 index 0000000..f8d0a3a --- /dev/null +++ b/fruitlinkit/resources/js/FruitLinkIt.js @@ -0,0 +1,47 @@ +(function($){ + + FruitLinkIt = Garnish.Base.extend({ + + $field: null, + $typeSelect: null, + $optionsHolder: null, + $settingsHolder: null, + $options: null, + + type: null, + + init: function(id) + { + this.$field = $('#'+id); + + this.$typeSelect = this.$field.find('.fruitlinkit-type select'); + this.type = this.$typeSelect.val(); + + this.$optionsHolder = this.$field.find('.fruitlinkit-options'); + this.$settingsHolder = this.$field.find('.fruitlinkit-settings'); + this.$options = this.$optionsHolder.find('.fruitlinkit-option'); + + this.addListener(this.$typeSelect, 'change', 'onChangeType'); + }, + + onChangeType: function(e) + { + var $select = $(e.currentTarget); + this.type = $select.val(); + + if(this.type === '') + { + this.$optionsHolder.add(this.$settingsHolder).addClass('hidden'); + } + else + { + this.$optionsHolder.add(this.$settingsHolder).removeClass('hidden'); + } + + this.$options.addClass('hidden'); + this.$options.filter('.fruitlinkit-' + this.type).removeClass('hidden'); + } + + }); + +})(jQuery); diff --git a/fruitlinkit/services/FruitLinkItService.php b/fruitlinkit/services/FruitLinkItService.php new file mode 100644 index 0000000..78d37c2 --- /dev/null +++ b/fruitlinkit/services/FruitLinkItService.php @@ -0,0 +1,53 @@ +plugin = craft()->plugins->getPlugin('fruitlinkit'); + $this->pluginHandle = $this->plugin->getPluginHandle(); + } + + public function getLinkItElementSources() + { + return array( + 'entry' => $this->_getElementSourcesWithUrls(ElementType::Entry), + 'asset' => $this->_getElementSourcesWithUrls(ElementType::Asset), + 'category' => $this->_getElementSourcesWithUrls(ElementType::Category), + ); + } + + private function _getElementSourcesWithUrls($type) + { + $elementType = craft()->elements->getElementType($type); + $sources = array(); + + foreach ($elementType->getSources() as $key => $source) + { + if (!isset($source['heading'])) + { + $sources[] = array( + 'label' => $source['label'], + 'value' => $key + ); + } + } + return $sources; + } + +} diff --git a/fruitlinkit/templates/_fieldtype/input.html b/fruitlinkit/templates/_fieldtype/input.html new file mode 100644 index 0000000..84bc7fa --- /dev/null +++ b/fruitlinkit/templates/_fieldtype/input.html @@ -0,0 +1,134 @@ +{% import "_includes/forms" as forms %} + +{% set singleType = types|length == 1 ? types[0] : null %} +{% set type = singleType ? singleType : ( value.type is defined and value.type ? value.type : null) %} + +
+ + {# Type #} + {% if singleType %} + + + + {% else %} + +
+ {{ forms.selectField({ + id: name~'-Type', + class: name~'-Type', + name: name~'[type]', + options: types, + value: type ? type + }) }} +
+ + {% endif %} + + {# Options #} +
+ + {% if types.email is defined %} +
+ {{ forms.textField({ + id: name~'Email', + class: name~'Email', + name: name~'[email]', + placeholder: 'Email Address', + value: type == 'email' ? value.value + }) }} +
+ {% endif %} + + {% if types.tel is defined %} +
+ {{ forms.textField({ + id: name~'Tel', + class: name~'Tel', + name: name~'[tel]', + placeholder: 'Telephone Number', + value: type == 'tel' ? value.value + }) }} +
+ {% endif %} + + {% if types.custom is defined %} +
+ {{ forms.textField({ + id: name~'Custom', + class: name~'Custom', + name: name~'[custom]', + placeholder: 'Custom URL', + value: type == 'custom' ? value.value + }) }} +
+ {% endif %} + + {% if types.entry is defined %} +
+ {{ forms.elementSelectField({ + id: name~'Entry', + class: name~'Entry', + name: name~'[entry]', + }|merge(elementSelectSettings.entry)) }} +
+ {% endif %} + + {% if types.asset is defined %} +
+ {{ forms.elementSelectField({ + id: name~'Asset', + class: name~'Asset', + name: name~'[asset]', + }|merge(elementSelectSettings.asset)) }} +
+ {% endif %} + + {% if types.category is defined %} +
+ {{ forms.elementSelectField({ + id: name~'Category', + class: name~'Category', + name: name~'[category]', + }|merge(elementSelectSettings.category)) }} +
+ {% endif %} + +
+ + {# Text & Target #} + {% if settings.allowCustomText or settings.allowTarget %} +
+ + {% if settings.allowCustomText %} + +
+ {{ forms.textField({ + id: name~'CustomText', + class: name~'CustomText', + name: name~'[customText]', + placeholder: settings.defaultText == '' ? 'Custom Link Text' : settings.defaultText, + value: value.customText is defined and value.customText ? value.customText + }) }} +
+ + {% endif %} + + {% if settings.allowTarget %} + +
+ {{ forms.checkboxField({ + id: name~'Target', + class: name~'Target', + name: name~'[target]', + value: '_blank', + label: 'Open link in new window?', + checked: value.target is defined and value.target == '_blank' ? true : null + }) }} +
+ + {% endif %} + +
+ {% endif %} + +
diff --git a/fruitlinkit/templates/_fieldtype/settings.html b/fruitlinkit/templates/_fieldtype/settings.html new file mode 100644 index 0000000..1289ee0 --- /dev/null +++ b/fruitlinkit/templates/_fieldtype/settings.html @@ -0,0 +1,119 @@ +{% import "_includes/forms" as forms %} + +{{ forms.checkboxSelectField({ + label: "Link Types"|t, + instructions: "Select the types of links would you like available."|t, + id: 'types', + name: 'types', + options: types, + values: settings.types, + errors: settings.getErrors('types'), + showAllOption: false, +}) }} + +
+ +{{ forms.textField({ + label: "Default Link Text"|t, + instructions: "Set a default value for this links text value, can be overridden if custom link text option is selected."|t, + name: 'defaultText', + value: settings.defaultText +}) }} + +{{ forms.checkboxField({ + label: "Allow custom link text"|t, + name: 'allowCustomText', + checked: settings.allowCustomText +}) }} + +{{ forms.checkboxField({ + label: "Allow option to open link in new window"|t, + name: 'allowTarget', + checked: settings.allowTarget +}) }} + +{% if elementSources.entry %} + +
+ + {{ forms.checkboxSelectField({ + label: "Entry Sources"|t, + instructions: "Which sources do you want to select entries from?"|t, + id: 'entrySources', + name: 'entrySources', + options: elementSources.entry, + values: settings.entrySources, + errors: settings.getErrors('entrySources'), + })}} + + {{ forms.textField({ + label: "Entry Selection Label"|t, + instructions: "Enter the text you want to appear on the entry selection input."|t, + name: 'entrySelectionLabel', + value: settings.entrySelectionLabel + }) }} + +{% else %} + {# {{ forms.field({ + label: "Entry Sources"|t, + instructions: "No entry sources exist yet."|t + }) }} #} +{% endif %} + + +{% if elementSources.asset %} + +
+ + {{ forms.checkboxSelectField({ + label: "Asset Sources"|t, + instructions: "Which sources do you want to select assets from?"|t, + id: 'assetSources', + name: 'assetSources', + options: elementSources.asset, + values: settings.assetSources, + errors: settings.getErrors('assetSources'), + })}} + + {{ forms.textField({ + label: "Asset Selection Label"|t, + instructions: "Enter the text you want to appear on the asset selection input.", + name: 'assetSelectionLabel', + value: settings.assetSelectionLabel + }) }} + +{% else %} + {# {{ forms.field({ + label: "Asset Sources"|t, + instructions: "No asset sources exist yet."|t + }) }} #} +{% endif %} + + +{% if elementSources.category %} + +
+ + {{ forms.checkboxSelectField({ + label: "Category Sources"|t, + instructions: "Which sources do you want to select categories from?"|t, + id: 'categorySources', + name: 'categorySources', + options: elementSources.category, + values: settings.categorySources, + errors: settings.getErrors('categorySources'), + }) }} + + {{ forms.textField({ + label: "Category Selection Label"|t, + instructions: "Enter the text you want to appear on the category selection input."|t, + name: 'categorySelectionLabel', + value: settings.categorySelectionLabel + }) }} + +{% else %} + {# {{ forms.field({ + label: "Category Sources"|t, + instructions: "No category sources exist yet."|t + }) }} #} +{% endif %}