Commit 5516d803 authored by Thibaut Frain's avatar Thibaut Frain

added presentation editor gadget

parent 409f3ae0
...@@ -189,8 +189,17 @@ module.exports = function (grunt) { ...@@ -189,8 +189,17 @@ module.exports = function (grunt) {
src: '<%= curl.jquerymobilejs.src_base %>.css', src: '<%= curl.jquerymobilejs.src_base %>.css',
relative_dest: 'lib/jquerymobile.css', relative_dest: 'lib/jquerymobile.css',
dest: '<%= global_config.dest %>/<%= curl.jquerymobilecss.relative_dest %>' dest: '<%= global_config.dest %>/<%= curl.jquerymobilecss.relative_dest %>'
},
html-beautify: {
src: 'https://raw.githubusercontent.com/einars/js-beautify/master/js/lib/beautify-html.js'
relative_dest: 'lib/html-beautify.js',
dest: '<%= global_config.dest %>/<%= curl.html-beautify.relative_dest %>'
},
animatecss: {
src: 'https://raw.github.com/daneden/animate.css/master/animate.css'
relative_dest: 'lib/animate.css',
dest: '<%= global_config.dest %>/<%= curl.animatecss.relative_dest %>'
} }
// qunit: { // qunit: {
// all: ['test/index.html'] // all: ['test/index.html']
}, },
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Presentation editor</title>
<!-- Presentation editor dependencies -->
<script src="../lib/jquery.min.js"></script>
<script src="../lib/jquery-ui.min.js"></script>
<script src="../lib/jquery.mobile.min.js"></script>
<script src="../lib/beautify-html.js"></script>
<!-- Renderjs -->
<script src="../lib/rsvp.min.js"></script>
<script src="../lib/renderjs.js"></script>
<!-- Jquery ui and jquery-mobile stylesheet -->
<link rel="stylesheet" href="../lib/jquery-ui.min.css">
<link rel="stylesheet" href="../lib/jquery.mobile.min.css">
<link rel="stylesheet" href="../lib/animate.min.css">
<!-- Presentation editor stylesheet -->
<link rel="stylesheet" href="presentation-editor.css">
<!-- Presentation editor gadget -->
<script src="presentation-editor.js"></script>
</head>
<body>
<div data-role="page">
<div id="form-panel" data-role="panel" data-display="push">
<div class="panel-content page">
<form id="slide-form">
<div data-role="fieldcontain">
<label for="title" ><strong>Title</strong></label>
<input type="text" name="title" id="title" placeholder="Type here the slide title" data-clear-btn="true" required/>
</div>
<br/>
<div data-role="fieldcontain">
<label for="type"><strong>Type</strong></label>
<fieldset data-role="controlgroup" data-mini="true" id="type">
<input type="radio" name="type" id="basic-type" value="" checked="checked" />
<label for="basic-type">basic</label>
<input type="radio" name="type" id="chapter-type" value="chapter" />
<label for="chapter-type">chapter</label>
<input type="radio" name="type" id="screenshot-type" value="screenshot" />
<label for="screenshot-type">screenshot</label>
<input type="radio" name="type" id="illustration-type" value="illustration" />
<label for="illustration-type">illustration</label>
<input type="radio" name="type" id="code-type" value="code" />
<label for="code-type">code</label>
<input type="radio" name="type" id="master-type" value="master" />
<label for="master-type">master</label>
</fieldset>
</div>
<br/>
<div data-role="fieldcontain" id="image-field">
<label for="image"><strong>Image URL</strong></label>
<input type="text" name="image" id="image-url" />
<img id="image-preview" class="ui-shadow ui-corner-all">
<br/>
</div>
<br/>
<div data-role="fieldcontain">
<label for="content"><strong>Slide text</strong></label>
<textarea name="content" id="content" placeholder="This text will appear in the slide"></textarea>
</div>
<div data-role="fieldcontain">
<label for="details"><strong>Slide details</strong></label>
<textarea name="details" id="details" placeholder="This text will be hidden"></textarea>
</div>
<br/>
<div id="slide-form-buttons" class="ui-grid-a">
<div class="ui-block-a"><input type="button" id="cancel" value="Cancel" data-theme="b"></div>
<div class="ui-block-b"><input type="submit" id="submit" value="Add slide" class="ui-block-b"></div>
</div>
</form>
</div>
</div>
<div role="main" class="ui-content">
<div id="slide-list">
</div>
<section id="add-slide" class="block ui-shadow ui-corner-all ui-btn">
<div class="dummy"></div>
<div class="slide">
New slide
</div>
</section>
</div>
<template id="slide-html">
<section class="block slide-thumb ui-shadow ui-corner-all">
<button class="edit ui-shadow ui-corner-all ui-btn ui-btn-inline ui-icon-edit ui-btn-icon-notext"
data-inline="true">
</button>
<button class="delete ui-shadow ui-corner-all ui-btn ui-btn-inline ui-icon-delete ui-btn-icon-notext"
data-inline="true">
</button>
<div class="dummy"></div>
<div class="slide">
<h1></h1>
<img>
<div class="content"></div>
</div>
</section>
</template>
<template id="slide-data">
<section>
<h1></h1>
</section>
</template>
</div>
</body>
</html>
.block {
display: inline-block;
float: left;
margin: 1%;
position: relative;
padding: 2%;
cursor: pointer;
position: relative;
width: 7.9vw;
min-width: 150px;
z-index: 10;
overflow: hidden;
}
.block.slide-thumb {
background-color: white;
/* box-shadow: 2px 2px 2px 3px #ccc; */
border: 2px solid grey;
}
.block#add-slide .slide {
margin-left: auto;
margin-right: auto;
margin-top: 30%;
font-size: 150%;
}
.block > .dummy {
margin-top: 100%;
}
.block > .slide {
position: absolute;
top: 2%;
bottom: 2%;
left: 2%;
right: 2%;
}
.block > button.edit {
position: absolute;
bottom: -2%;
right: -2%;
z-index: 20;
}
.block > button.delete {
position: absolute;
top: -2%;
right: -2%;
z-index: 20;
}
.block .slide > h1 {
text-align: center;
}
.block > .slide * {
position: relative;
max-width: 98%;
word-wrap: break-word;
}
.ui-panel-page-content-open.ui-panel-page-content-position-left.ui-panel-page-content-display-push {
padding-right: 35vw;
}
.ui-panel-page-content-open.ui-panel-page-content-display-push {
width: auto;
}
.ui-panel-dismiss-display-push {
display: none;
}
body {
background: url('images/tweed.png');
background-repeat: repeat;
background-position: center center;
background-attachment: scroll;
background-size: 100% 100%;
}
.ui-page .ui-overlay-a, .ui-page-theme-a, .ui-page-theme-a .ui-panel-wrapper{
background: url('images/tweed.png');
}
.ui-content{
background: transparent;
}
@media (max-width: 1000px) {
.ui-panel {
width: 100%;
}
.ui-panel-position-left {
left: 100%;
}
.ui-panel-animate.ui-panel-page-content-position-left {
-webkit-transform: translate3d(100%,0,0);
-moz-transform: translate3d(100%,0,0);
transform: translate3d(100%,0,0);
}
}
#image-preview {
position: relative;
float: right;
width: 24%;
margin: 3%
}
\ No newline at end of file
/*globals window, document, $, html_beautify, FileReader, */
/*jslint unparam: true */
$(function (window, $, html_beautify, rJS) {
"use strict";
var presentation = null,
slideForm,
newSlideButton = $('#add-slide'),
formPanel = $('#form-panel');
formPanel.panel({ beforeclose: function () {
newSlideButton.show("fade");
slideForm.bindToAdd();
}});
function openForm() {
formPanel.panel("open");
newSlideButton.hide("fade");
}
function closeForm() {
formPanel.panel("close");
}
function animate(selector, animation) {
var $selector = $(selector);
$selector.off("animationend webkitAnimationEnd");
$selector.on("animationend webkitAnimationEnd", function () {
$selector.removeClass("animated " + animation);
});
$selector.addClass("animated " + animation);
}
function Slide(params) {
var that = this;
this.html = document.importNode(this.htmlTemplate, true);
this.update(params);
$(this.editBtn()).click(function () {
if (slideForm.currentSlide !== that) {
slideForm.bindToEdit(that);
openForm();
}
});
$(this.deleteBtn()).click(function () {
presentation.deleteSlide(that);
});
}
function readSlide(domElement) {
var $el = $(domElement),
title = $el.find('h1').first().text(),
type = $el.attr('class'),
img,
content = "";
if (type === 'screenshot' || type === 'illustration') {
img = $el.find('img').first().attr('src');
}
$el.contents().filter(function () {
return $(this).is(':not(img, h1, details)') || this.nodeType === 3;
}).each(function () {
content += this.outerHTML || this.textContent;
});
return new Slide({
title: title,
type: type,
content: content,
image: img
});
}
Slide.prototype = {
dataTemplate: document.querySelector('template#slide-data').content.firstElementChild,
htmlTemplate: document.querySelector('template#slide-html').content.firstElementChild,
editBtn: function () {return this.html.querySelector("button.edit"); },
deleteBtn: function () {return this.html.querySelector("button.delete"); },
htmlContent: function () {return this.html.querySelector(".content"); },
htmlImage: function () {return this.html.querySelector("img"); },
htmlTitle: function () {return this.html.querySelector("h1"); },
data: function () {
var res = document.importNode(this.dataTemplate, true), img;
res.className = this.type;
res.querySelector('h1').textContent = this.title;
$(res).append(this.content);
if (this.type === "screenshot" || this.type === "illustration") {
img = document.createElement('img');
img.src = this.image;
res.appendChild(img);
}
return res;
},
update: function (params) {
$.extend(this, params);
this.htmlTitle().textContent = this.title;
this.htmlContent().innerHTML = this.content;
if (this.type === "screenshot" || this.type === "illustration") {
this.htmlImage().src = this.image;
} else {
this.htmlImage().src = "";
}
}
};
function SlideForm() {
var that = this;
this.elt = document.querySelector("#slide-form");
this.bindToAdd();
$(this.elt).find("#cancel").click(closeForm);
$(this.elt).find('input[type="radio"]').click(function () {
that.updateFieldVisibility(true);
});
$("#image-url").on("change", function () {
that.updatePreview(that.attrImageURL());
});
}
SlideForm.prototype = {
attrTextInput: function (inputElt, content) {
if (content !== undefined) {
inputElt.value = content;
} else {
return inputElt.value;
}
},
attrTitle: function (content) {
return this.attrTextInput(this.elt.querySelector('#title'), content);
},
attrContent: function (content) {
return this.attrTextInput(this.elt.querySelector('#content'), content);
},
attrDetails: function (content) {
return this.attrTextInput(this.elt.querySelector('#details'), content);
},
attrType: function (type) {
var radios = $(this.elt).find('input[type="radio"]');
if (type !== undefined) {
radios.prop('checked', false);
if (type === "") {type = "basic"; }
radios.filter("#" + type + "-type").prop('checked', true);
radios.checkboxradio('refresh');
this.updateFieldVisibility();
} else {
return radios.filter(':checked').val();
}
},
attrImageURL: function (content) {
return this.attrTextInput(this.elt.querySelector('#image-url'), content);
},
updatePreview: function (content) {
var preview = this.elt.querySelector('#image-preview');
if (content) {
$(preview).show();
preview.src = content;
} else {
$(preview).hide();
}
},
attrAll: function (slide) {
if (slide !== undefined) {
this.attrTitle(slide.title);
this.attrType(slide.type);
this.attrContent(slide.content);
this.attrDetails(slide.details);
this.attrImageURL(slide.image);
this.updatePreview(slide.image);
} else {
return {
title: this.attrTitle(),
type: this.attrType(),
content: this.attrContent(),
details: this.attrDetails(),
image: this.attrImageURL()
};
}
},
updateFieldVisibility: function (withEffect) {
var type = this.attrType(),
$imageField = $(this.elt).find('#image-field'),
$imageInputURL = $(this.elt).find('input#image-url');
if (type === "screenshot" || type === "illustration") {
if (withEffect) {
$imageField.show("blind", {direction: "up"});
} else {
$imageField.show();
}
$imageInputURL.attr('required', true);
} else {
if (withEffect) {
$imageField.hide("blind", {direction: "up"});
} else {
$imageField.hide();
}
$imageInputURL.attr('required', false);
}
},
setSubmitLabel: function (label) {
var submit = $(this.elt).find("#submit");
submit.prop("value", label).button('refresh');
},
reset: function () {
this.attrAll({title: "", type: "basic", content: "", details: "", image: ""});
this.currentSlide = null;
$(this.elt).off("submit");
},
bindToEdit: function (slide) {
var that = this;
this.reset();
animate(this.elt, "fadeIn");
that.currentSlide = slide;
this.attrAll(slide);
$(this.elt).submit(function (e) {
slide.update(that.attrAll());
animate(slide.html, "bounce");
e.preventDefault();
that.bindToAdd();
});
this.setSubmitLabel("Save");
},
bindToAdd: function () {
var that = this;
this.reset();
$(this.elt).submit(function (e) {
presentation.addSlide(new Slide(that.attrAll()));
that.bindToAdd();
e.preventDefault();
});
this.setSubmitLabel("Add");
}
};
function Presentation(DOMElement) {
this.html = DOMElement;
slideForm = new SlideForm();
this.slides = [];
$("#add-slide").click(openForm);
$(this.html).sortable({
update: function (event, ui) {
presentation.updateOrder(ui.item);
}
});
}
Presentation.prototype = {
addSlide: function (slide) {
this.slides.push(slide);
this.html.appendChild(slide.html);
animate(slide.html, "pulse");
return slide;
},
deleteSlide: function (slide) {
if (slideForm.currentSlide === slide) {
slideForm.bindToAdd();
}
var index = this.slides.indexOf(slide);
this.slides.splice(index, 1);
animate(slide.html, 'rollOut');
$(slide.html).on("animationend webkitAnimationEnd", function () {
slide.html.remove();
});
return index;
},
updateOrder: function (DOMElement) {
var newIndex = $(this.html.children).index(DOMElement),
oldIndex,
i,
tmp;
for (i = 0; i < this.slides.length; i++) {
if (this.slides[i].html === DOMElement[0]) {
oldIndex = i;
break;
}
}
tmp = this.slides.splice(oldIndex, 1)[0];
this.slides.splice(newIndex, 0, tmp);
},
getContent: function () {
var i, container = document.createElement('div');
for (i = 0; i < this.slides.length; i++) {
container.appendChild(this.slides[i].data());
}
return html_beautify(container.innerHTML);
},
setContent: function (content) {
var i, sections, container = document.createElement('div');
container.innerHTML = content;
sections = container.children;
for (i = 0; i < sections.length; i++) {
this.addSlide(readSlide(sections[i]));
}
}
};
$.fn.extend({
presentation: function () {
presentation = new Presentation(this[0]);
window.prez = presentation;
return presentation;
}
});
rJS(window)
.declareMethod('setContent', function (content) {
rJS(this).editor.setContent(content);
})
.declareMethod('getContent', function () {
return rJS(this).editor.getContent();
})
.ready(function (g) {
g.editor = $('#slide-list').presentation();
});
}(window, $, html_beautify, rJS));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment