user1051870
user1051870

Reputation: 913

Play framework - insert user-defined css file

I have try to insert user-defined css file into my template.

Model:

@Entity
public class MyModel extends Model {

    // Some code stuff...

    /** User-defined css file. */
    public Blob stylesheet;

}

Controller

public class MyController extends Controller {

    // Some code stuff...

    /**
     * Displays user-defined css file for specified instance of MyModel.
     */
    public static void displayStylesheet(Long id) {
        final MyModel myModel = MyModel.findById(id);
        notFoundIfNull(myModel);
        response.setContentTypeIfNotSet(myModel.stylesheet.type());
        if (myModel.stylesheet.exists()) {
            renderBinary(myModel.stylesheet.getFile());
        }
    }

    /**
     * Displays page, that contains user-defined css file
     * for specified instance of MyModel.
     */
    public static void index(Long id) {
        render(id);
    }

}

View

#{extends 'main.html' /}
#{set 'styles'}
  <link rel="stylesheet" href="@{MyController.displayStylesheet(id)}" />
#{/set}
<p>This page contains user-defined stylesheet.</p>

When I try to display stylesheet by GET request all working fine:

http://localhost:9000/mycontroller/displaystylesheet?id=1188

But FireBug or Google Chrome developer`s panel are not displays this style like sourced.

Updated:

I found the solution, but it is not so beautyfull. Code in the controller:

/**
 * Displays page, that contains user-defined css file
 * for specified instance of MyModel.
 */
public static void index(Long id) {
    final MyModel myModel = MyModel.findById(id);
    String styles = "";
    File stylesheet = myModel.stylesheet.getFile();
    try {
        FileInputStream stream = new FileInputStream(stylesheet);
        try {
          FileChannel fc = stream.getChannel();
          MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
          styles = Charset.defaultCharset().decode(bb).toString();
        }
        finally {
          stream.close();
        }
    }
    catch (IOException ioe){
        throw new RuntimeException(ioe);
    }
    render(id, styles);
}

It will put all styles into the one string styles. Then we can render it in the template:

<style type="text/css">
  ${styles}
</style>

May be someone can suggest more beautyfull solution?

Upvotes: 1

Views: 998

Answers (1)

Codemwnci
Codemwnci

Reputation: 54914

The problem you are having, is that the content type is being returned as application/binary because you are using renderBinary, so the browser is ignoring it, because it is not of type "text/css".

When using renderBinary, the renderBinary code sets the contentType in a range of different ways depending on the parameters used. As you are using File, it determines the content type from the filename.

So, if you can guarantee that your filename is of type CSS, so when it performs MimeType.getContentType(filename); it will set the contentType accordingly.

Otherwise, you can change your code to something like this

public static void displayStylesheet(Integer id) {

    // ... read css data from file into a String
    String cssTextData = readCSSFromFile(); // <-- You can use the method you have used in your update here

    response.contentType = "text/css";
    renderText(cssTextData);
}

Upvotes: 3

Related Questions