Making a block that has insert link similar to content block (redactor)
Permalink
Theres the image helper, the page selector helper, etc.
What I want to do is make a block that has the same link selector available in the content block when you go to 'Insert link'.
I like how you can either paste in an external link, or you can select an internal page, or you can select a file. My main goal is to use this just for links that could be either internal or external, and instead of having seperate fields in my custom block, one that says "Select internal link" and then another that says "Or paste in external link".
What I want to do is make a block that has the same link selector available in the content block when you go to 'Insert link'.
I like how you can either paste in an external link, or you can select an internal page, or you can select a file. My main goal is to use this just for links that could be either internal or external, and instead of having seperate fields in my custom block, one that says "Select internal link" and then another that says "Or paste in external link".
The functionality is contained within the image block, but my goal in this instance is the usability. I like how the redactor is set up when you want to select a link. Its all there in one line, nothing hidden or revealed, no selects. You just paste a link, or click one of the buttons. So it is very user friendly. It would be sweet to have a helper that embedded this in one line. But until then, any idea where the code running the redactor link select is at? I looked for it but couldn't find it, I want to emulate its user interface.
I finally figured this out.
The answer lies in concrete/js/build/vendor/redactor/redactor.js
This file does everything.
I was able to build my own link selector that behaves exactly like the one built into redactor:
The html markup looks like this:
In the above, using bootstraps input group with the child a href as input-group-addons sets the syling up.
Now for the code that actually makes this happen:
Launching the site-map and retrieving a link (the following code runs when the sitemap button gets pressed):
Opening up the file manager is similar, the following runs when the file manager button is pressed:
Both functions end by setting the input value to whatever URL was retrieved, whether for file or page link.
The answer lies in concrete/js/build/vendor/redactor/redactor.js
This file does everything.
I was able to build my own link selector that behaves exactly like the one built into redactor:
The html markup looks like this:
<div class="input-group"> <input name="<?php echo $view->field('link');?>" type="text" class="form-control info-box-link"/> <a href="#" class="btn btn-default input-group-addon choose-link-from-sitemap"><i class="fa fa-sitemap"></i></a> <a href="#" class="btn btn-default input-group-addon choose-file-from-file-manager"><i class="fa fa-file"></i></a> </div>
In the above, using bootstraps input group with the child a href as input-group-addons sets the syling up.
Now for the code that actually makes this happen:
Launching the site-map and retrieving a link (the following code runs when the sitemap button gets pressed):
e.preventDefault(); thisLink = $(this); console.log("open site map!"); jQuery.fn.dialog.open({ width: '90%', height: '70%', modal: false, title: ccmi18n_sitemap.choosePage, href: CCM_TOOLS_PATH + '/sitemap_search_selector' }); ConcreteEvent.unsubscribe('SitemapSelectPage'); ConcreteEvent.subscribe('SitemapSelectPage', function(e, data) { jQuery.fn.dialog.closeTop(); var url = CCM_APPLICATION_URL + '/index.php?cID=' + data.cID; thisLink.closest('.input-group').find('.info-box-link').val(url);
Viewing 15 lines of 16 lines. View entire code block.
Opening up the file manager is similar, the following runs when the file manager button is pressed:
$obj.click(function(e) { e.preventDefault(); thisLink = $(this); ConcreteFileManager.launchDialog(function(data) { jQuery.fn.dialog.showLoader(); ConcreteFileManager.getFileDetails(data.fID, function(r) { jQuery.fn.dialog.hideLoader(); var file = r.files[0]; thisLink.closest('.input-group').find('.info-box-link').val(file.urlDownload); }); }); });
Both functions end by setting the input value to whatever URL was retrieved, whether for file or page link.
One other thing to keep in mind if your using the javascript link selector is that it gets the full path via the page cID, and it needs to be converted to an actual path name for a number of reasons:
1.) so your urls aren't ugly
2.) if you ever change root URL's the page links will break.
So in the controller handling the data coming from the javascript, you need to use Concrete\Core\Editor\LinkAbstractor, one for converting the full cID path to a non hard coded cID, and two for converting it to a real path name URL when viewed:
On save: which converts it to a string like {CCM:URL} or something like that...
And then when you need to actually load the URL into a view, as a full URL path:. That will output the real url path such as concrete5.org/is-really/awesome
1.) so your urls aren't ugly
2.) if you ever change root URL's the page links will break.
So in the controller handling the data coming from the javascript, you need to use Concrete\Core\Editor\LinkAbstractor, one for converting the full cID path to a non hard coded cID, and two for converting it to a real path name URL when viewed:
On save:
if ($data['link']) { $data['link'] = LinkAbstractor::translateTo($data['link']); }
And then when you need to actually load the URL into a view, as a full URL path:
$data['link'] = LinkAbstractor::translateFrom($data['link']);
My form:
link form select options:
• Option: None
• Option: Another page
• Option: External link
How to accomplish this:
+ DB: 2 table cols for the urls (internalLinkCID (integer for page id)/ externalLink (string for url path) - names of $vars in your code must match db cols names!!
+ Form (Use the form and asset_library helpers)
+ Form: some inline JS inside form.php (to hide/show form areas - depend on the option selected)
+ Controller to "control" the link output (external VS internal (convert id to url)) - and send this var to the view ($this->set('linkURL', $this->getLinkURL());)
+ view: print '<a href="' . $linkURL . '">'...rest of the code.
---------------------------------------------------------------
You can really create this by "copy and paste" ("AS IS") from this 4 spots the correct code (form, db, controller, view) and dont change the names of vars. (Also remember to refresh DB under "block types"). And learn this idea / code deeply later (MVC).
---------------------------------------------------------------
** You will find this "pattern" (external Vs internal) in most of galleries or sliders - their is a lot of code solutions for this.