I wrote a Class MyGridView extends from the CGridView.
MyGridView will automaticlly generate two buttons in the header,
one is a pdf icon, another is a excel icon. but how can I bind event to this two icon?
so that I can use my code to generate PDF or EXCEL for this CGridView based on the dataprovider and columns.
the PDF export code and the EXCEL export code are all ready, I just don't know how to bind server-side event for the Class
this depends a lot on your code to generate the PDF and EXCEL files, there are several ways to "bind" those buttons to generate the files.
In the same action that renders the grid view in the first place
different actions that use the same code base that generates the CDataProvider.
for the first case, you can pass a parameter to the action that tells it to generate the corresponding file:
<?php
public function actionIndex()
{
//Code base to generate the CActiveData provider.
//Check if we are asking for the PDF version
if(isset($_GET["pdf"])){
//Your code to generate the PDF
}elseif (isset($_GET["excel"])) {
//Your code to generate the EXCEL
}else{
//render the view with the Grid
}
}
?>
Then in your MyGridClass, just point your buttons to the corresponding url:
//For the pdf
Yii::app()->controller->createUrl('', array('pdf' => '1'));
//For the excel
Yii::app()->controller->createUrl('', array('excel' => '1'));
You can adjust this to have 2 separate actions if you want.
Related
I have two editors on the screen, one read-only. What I want to do is allow the user to select content from the read-only editor and paste it into the current position of the other by clicking a button. (the logic may manipulate the text which is one reason I don't want to use the system's clipboard.)
So far I have the function that is able to paste the text like as follows. (I am using the Angular wrapper which explains the presence of the CKEditorComponent reference.
doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
editor.model.change(writer => {
writer.insertText(pasteEvent.text, editor.model.document.selection.getFirstPosition() );
});
}
What I can't find from the documentation is how to extract the selected text. What I have so far is:
clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
const selection = editor.model.document.selection;
console.log('clickPasteAll selection', selection);
console.log('clickPasteAll selectedcontent', editor.model.document.getSelectedContent);
}
The selection appears to change depending on what is selected in the editor's view. The getSelectedContent function is undefined. How do I get the content?
With a bit of poking around I figured out how to do this. I'll document it here on the chance that it will help someone down the road avoid the process of discovery that I went through.
On the source document I have a ckeditor element like this:
<div *ngIf="document">
<ckeditor #ckEditor
[editor]="Editor" [config]="ckconfig" [disabled]="true"
[(ngModel)]="document.text"></ckeditor>
<button mat-flat-button (click)="clickPasteSelectedPlain(ckEditor)">Paste Selected Text Plain</button>
</div>
In the component the function called on the click event is like this:
#Output() paste = new EventEmitter<PasteEvent>();
...
clickPasteSelectedPlain(editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
this.paste.emit({
content: editor.model.getSelectedContent(editor.model.document.selection),
obj: this.document,
quote: false
});
}
The PasteEvent is defined as an exported interface which I will omit here to save space. The content key will refer to a DocumentFragment.
Note that I am passing the CKEditorComponent as a parameter. You could also access it via an Angular #ViewChild declaration but note that my ckeditor is inside an *ngIf structure. I think that works well in Angular 6 but in the past I have had difficulty with #ViewChild references when the target was conditionally in the DOM. This method always works but use whatever method you want.
The event fired by the emit is processed with a method that looks like this:
doPaste(pasteEvent: PasteEvent, editorComponent: CKEditorComponent) {
const editor = editorComponent.editorInstance;
editor.model.insertContent(pasteEvent.content);
}
Because the content is a DocumentFragment the paste operation will include all formatting and text attributes contained in the selected source. But that's all there is to it.
is there a way to change stylesheet file dynamically depending on if the document is in edit or read mode?
What I would like to do is to add the following code to the "compute value" option of the resource href property:
if(document.isEditable()){
return "style_edit.css"
}
else{
return "style_read.css"
}
My main problem with this is that when the page loads, it gives the error "document not found". This is probably because when the page loads, there is only a view that includes the documents and when the user clicks a document id, then the custom control with the binded document appears. I don't know how to make the binded to custom control document available on load of the page.
Edited:
I tried a try/catch block and now the xpage opens without displaying an error. But although the custom control is refreshed, the css file does not change, althoug I use compute dynamically and not compute on load
Thank you in advance!
You can set the resource href attribute as computed. For this go to All Properties of XPage "basics > resources > styleSheet". Here you can compute the href attribute with your JavaScript code. So your resource in XPage source would look something like this
<xp:this.resources>
<xp:styleSheet>
<xp:this.href><![CDATA[#{javascript:if (document.isEditable()) {
return "style_edit.css";
} else {
return "style_read.css";
}}]]></xp:this.href>
</xp:styleSheet>
</xp:this.resources>
To access the data source from custom control you can use the global variable currentDocument instead of document.
Why force user to download separate files on edition when You can simply add computed styleClass to some panel/component:
<xp:panel>
<xp:this.styleClass><![CDATA[#{javascript:return document.isEditable()?"docEditMode":"docReadMode";}]]></xp:this.styleClass>
</xp:panel>
and use it as a selector inside style.css
I'm editing a page in the ToolTwist Designer, and I have all the normal tabs shown - edit page, navpoint, test page, source, etc, but the "Page Data" tab is not showing. How can I make the tab show, so I can enter page data for my page?
The page data tab only appears if there is a widget on your page that requires page data. You also need to editing the navpoint, rather than the page, because the page data belongs to the navpoint, and a single page definition might be shared by many navpoints. In other words, the page data allows widgets to appear different at various locations (navpoints) within the website.
If you are developing a widget that you wish to have use page data, you need to do the following:
In the Widget Controller class, implement the "UsesPageData" interface. This tells the Designer that the page data tab needs to be displayed when you click on a navpoint that references a page that included this widget, and on the tab it creates a section where the XML for this widget can be entered, specific to that particular navpoint.
public class CarouselTab extends WbdWidgetController implements UsesPageData
To give the user an indication of what XML the widget expects, you need to implement a method that returns template XML code. For example:
public XData getInitialPageData(WbdWidget instance)
{
StringBuffer xml = new StringBuffer();
xml.append("\n");
xml.append("\n");
xml.append(" id01\n");
xml.append(" [Label 01]\n");
xml.append(" [Add your widget here 01]\n");
xml.append("\n");
xml.append("\n");
xml.append(" id02\n");
xml.append(" [Label 02]\n");
xml.append(" [Add your widget here 02]\n");
xml.append("\n");
xml.append("");
return new XData(xml);
}
Define a property that defines a name to be displayed above where you enter the XML on the page data tab:
protected void init(WbdWidget instance) throws WbdException
{
instance.defineProperty(new WbdStringProperty("pageDataSection", null, "PageDataSection", ""));
...
}
Use the page data when you are generating the page:
#Override
public void renderForJSP(WbdGenerator generator, WbdWidget instance, UimHelper ud, WbdRenderHelper rh) throws WbdException
{
...
Xpc xpc = ud.getXpc();
xpc.start("tooltwist.wbd.getPagedata", "select");
xpc.attrib("navpointId", WbdSession.getNavpointId(ud.getCredentials()));
xpc.attrib("pageDataSection", pageDataSection);
XData pagedata = xpc.run();
// Do something with the page data
...
}
Can someone tell me how can I have the breadcrumb nav within the header.tpl and not in the product.tpl of opencart?
I've just had to figure this out for a new site we're building and I've come up with the following; use at your own risk (I'll report back if I run into any major problems, but I can't foresee any... famous last words)
Basically the breadcrumbs are built in the controllers and we need the resulting $breadcrumbs array in the header controller. Modify system/engine/controller.php as follows:
[...snip...]
protected function render() {
foreach ($this->children as $child) {
$this->data[basename($child)] = $this->getChild($child,array('parent_data'=>&$this->data));
}
[...snip...]
This will send all the data in the parent controller, before render() was called, to every controller/method of the $children. Then we just need to pick this up in the header controller as follows:
<?php
class ControllerCommonHeader extends Controller {
protected function index($args=array()) {
// parent data
$this->data['parent_data'] = $args['parent_data'];
[...snip...]
And we can access everything in the template with $parent_data['whatever']. In this case, $parent_data['breadcrumbs'] will be the array of breadcrumbs that I can loop over with the code I've removed from each page.tpl and added to my header.tpl.
Due to the way 1.5.X is coded, you'll need to rewrite every controller and add a method back to the document class to allow passing from the product controller to the header controller. Is there any particular reason you want to do so?
if all else fails just hack the css, something like
.breadcrumb {
margin-left: -270px;
margin-top: -65px;
}
will move the breadcrumb up and to the left.
The medical company I work for has a EMR system setup to keep digital copies of patient files so they are searchable as well as quick to access. A new request has come through to be able to save e-mail to the EMR system, however it does not display .msg files very nicely. It does display files nicely as .htm, so was hoping i could figure out a way to save email messages to a specific folder in a .htm format with the user just hitting a single button.
Should i be looking at making an add-in using vs 2010 to do this simple task? Or would there be a better way to do this?
I've explored making an Add-In breifly over the past few days using command bars but have hit numerous problems with adding the menu item to mail items, as well as losing event handlers or having them fire quite a few times, so i'm wondering if i'm barking up the wrong tree.
Edit: Looking at ribbon bar customization as well, may have to upgrade some users that are still using 2003, but seems like it might be the better option than command bars going forward.
Ribbon bar was the best path i found, however i had trouble finding a great how-to for the start-to-finish project, so i'll make a small write up here.
To add a button to the ribbon for only existing mail messages including a image for the button.
Using VS 2010
New project, Office, select "Outlook 2007 add in", enter a name for your project.
To your newly created project, Add a new item "Ribbon (XML)" name it however you want, i'll call it CustomRibbon
open your newly created CustomRibbon.xml file and change the tab node to have the following
<tab idMso="TabReadMessage">
<group insertBeforeMso="GroupActions" id="CustomGroup" label="GroupNameThatShowsInOutlook">
<button id="btnCustomButton"
label = "Text For The Custom Button"
supertip="tip for the button hover"
onAction ="ButtonClicked"
size="large"
getImage="GetCustomButtonImage" />
</group>
</tab>
This then has 2 callback functions to the CustomRibbon.cs file, one called GetCustomButtonImage, the other ButtonClicked.
open CustomRibbon.cs to fill this in, in the Ribbon Callbacks region add the following
public void ButtonClicked(Office.IRibbonControl Control)
{
//Do work here
}
also add the following in the same section
public stdole.IPictureDisp GetCustomButtonImage(Office.IRibbonControl control)
{
System.Drawing.Image myImage;
myImage = OutlookAddIn.Properties.Resources.ImageName;
return AxHostConverter.ImageToPictureDisp(myImage);
}
this will then show there is a class missing, we'll get to that shortly, but first we are going to add in the last part we need in CustomRibbon.cs. In the IRibbonExtensibility Members region, in GetCustomUI change the existing code
public string GetCustomUI(string ribbonID)
{
if (ribbonID == "Microsoft.Outlook.Mail.Read")
{
return GetResourceText("OutlookAddIn.CustomRibbon.xml");
}
else
{
return "";
}
}
Add a new class to your project call it AxHostConverter, add add this to the top
using System.Windows.Forms;
using System.Drawing;
Then change the class to have the following code
class AxHostConverter : AxHost
{
private AxHostConverter() : base("") { }
static public stdole.IPictureDisp ImageToPictureDisp(Image image)
{
return (stdole.IPictureDisp)GetIPictureDispFromPicture(image);
}
static public Image PictureDispToImage(stdole.IPictureDisp pictureDisp)
{
return GetPictureFromIPicture(pictureDisp);
}
}
Add your image for your button to the project, and change the GetCustomButtonImage function to use that resource. I used a PNG and had good luck with transparencies displaying well.
And finally, all that should be left is to add the following to ThisAddIn.cs
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return new CustomRibbon();
}
Add whatever code you are wanting to ButtonClicked and you are set.
Deploy using Clickonce and installation is fairly straightforward.