You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2006/10/08 21:54:16 UTC
svn commit: r454197 [14/29] - in /incubator/roller/trunk/web:
WEB-INF/classes/ roller-ui/authoring/editors/
roller-ui/authoring/editors/xinha/ roller-ui/authoring/editors/xinha/conf/
roller-ui/authoring/editors/xinha/contrib/ roller-ui/authoring/editor...
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/GetHtml/get-html.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/GetHtml/get-html.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/GetHtml/get-html.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/GetHtml/get-html.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,209 @@
+/**
+ * Based on XML_Utility functions submitted by troels_kn.
+ * credit also to adios, who helped with reg exps:
+ * http://www.sitepoint.com/forums/showthread.php?t=201052
+ *
+ * A replacement for HTMLArea.getHTML
+ *
+ * Features:
+ * - Generates XHTML code
+ * - Much faster than HTMLArea.getHTML
+ * - Eliminates the hacks to accomodate browser quirks
+ * - Returns correct code for Flash objects and scripts
+ * - Formats html in an indented, readable format in html mode
+ * - Preserves script and pre formatting
+ * - Preserves formatting in comments
+ * - Removes contenteditable from body tag in full-page mode
+ * - Supports only7BitPrintablesInURLs config option
+ * - Supports htmlRemoveTags config option
+ */
+
+function GetHtml(editor) {
+ this.editor = editor;
+}
+
+GetHtml._pluginInfo = {
+ name : "GetHtml",
+ version : "1.0",
+ developer : "Nelson Bright",
+ developer_url : "http://www.brightworkweb.com/",
+ license : "htmlArea"
+};
+
+HTMLArea.RegExpCache = [
+/*00*/ new RegExp().compile(/<\s*\/?([^\s\/>]+)[\s*\/>]/gi),//lowercase tags
+/*01*/ new RegExp().compile(/(\S*\s*=\s*)?_moz[^=>]*(=\s*[^>]*)?/gi),//strip _moz attributes
+/*02*/ new RegExp().compile(/\s*=\s*(([^'"][^>\s]*)([>\s])|"([^"]+)"|'([^']+)')/g),// find attributes
+/*03*/ new RegExp().compile(/\/>/g),//strip singlet terminators
+/*04*/ // new RegExp().compile(/<(br|hr|img|input|link|meta|param|embed)([^>]*)>/g),//terminate singlet tags
+/*04*/ new RegExp().compile(/<(br|hr|img|input|link|meta|param|embed|area)((\s*\S*="[^"]*")*)>/g),//terminate singlet tags
+/*05*/ new RegExp().compile(/(checked|compact|declare|defer|disabled|ismap|multiple|no(href|resize|shade|wrap)|readonly|selected)([\s>])/gi),//expand singlet attributes
+/*06*/ new RegExp().compile(/(="[^']*)'([^'"]*")/),//check quote nesting
+/*07*/ new RegExp().compile(/&(?=[^<]*>)/g),//expand query ampersands
+/*08*/ new RegExp().compile(/<\s+/g),//strip tagstart whitespace
+/*09*/ new RegExp().compile(/\s+(\/)?>/g),//trim whitespace
+/*10*/ new RegExp().compile(/\s{2,}/g),//trim extra whitespace
+/*11*/ new RegExp().compile(/\s+([^=\s]+)(="[^"]+")/g),// lowercase attribute names
+/*12*/ new RegExp().compile(/(\S*\s*=\s*)?contenteditable[^=>]*(=\s*[^>\s\/]*)?/gi),//strip contenteditable
+/*13*/ new RegExp().compile(/((href|src)=")([^\s]*)"/g), //find href and src for stripBaseHref()
+/*14*/ new RegExp().compile(/<\/?(div|p|h[1-6]|table|tr|td|th|ul|ol|li|blockquote|object|br|hr|img|embed|param|pre|script|html|head|body|meta|link|title|area|input|form|textarea|select|option)[^>]*>/g),
+/*15*/ new RegExp().compile(/<\/(div|p|h[1-6]|table|tr|ul|ol|blockquote|object|html|head|body|script|form|select)( [^>]*)?>/g),//blocklevel closing tag
+/*16*/ new RegExp().compile(/<(div|p|h[1-6]|table|tr|ul|ol|blockquote|object|html|head|body|script|form|select)( [^>]*)?>/g),//blocklevel opening tag
+/*17*/ new RegExp().compile(/<(td|th|li|option|br|hr|img|embed|param|pre|meta|link|title|area|input|textarea)[^>]*>/g),//singlet tag or output on 1 line
+/*18*/ new RegExp().compile(/(^|<\/(pre|script)>)(\s|[^\s])*?(<(pre|script)[^>]*>|$)/g),//find content NOT inside pre and script tags
+/*19*/ new RegExp().compile(/(<pre[^>]*>)(\s|[^\s])*?(<\/pre>)/g),//find content inside pre tags
+/*20*/ new RegExp().compile(/(^|<!--(\s|\S)*?-->)((\s|\S)*?)(?=<!--(\s|\S)*?-->|$)/g),//find content NOT inside comments
+/*21*/ new RegExp().compile(/\S*=""/g), //find empty attributes
+/*22*/ new RegExp().compile(/<!--[\s\S]*?-->|<\?[\s\S]*?\?>|<\/?\w[^>]*>/g), //find all tags, including comments and php
+/*23*/ new RegExp().compile(/(^|<\/script>)(\s|[^\s])*?(<script[^>]*>|$)/g) //find content NOT inside script tags
+];
+
+/**
+ * Cleans HTML into wellformed xhtml
+ */
+HTMLArea.prototype.cleanHTML = function(sHtml) {
+ var c = HTMLArea.RegExpCache;
+ sHtml = sHtml.
+ replace(c[0], function(str) { return str.toLowerCase(); } ).//lowercase tags/attribute names
+ replace(c[1], ' ').//strip _moz attributes
+ replace(c[12], ' ').//strip contenteditable
+ replace(c[2], '="$2$4$5"$3').//add attribute quotes
+ replace(c[21], ' ').//strip empty attributes
+ replace(c[11], function(str, p1, p2) { return ' '+p1.toLowerCase()+p2; }).//lowercase attribute names
+ replace(c[3], '>').//strip singlet terminators
+ replace(c[9], '$1>').//trim whitespace
+ replace(c[5], '$1="$1"$3').//expand singlet attributes
+ replace(c[4], '<$1$2 />').//terminate singlet tags
+ replace(c[6], '$1$2').//check quote nesting
+ // replace(c[7], '&').//expand query ampersands
+ replace(c[8], '<').//strip tagstart whitespace
+ replace(c[10], ' ');//trim extra whitespace
+ if(HTMLArea.is_ie && c[13].test(sHtml)) {
+ sHtml = sHtml.replace(c[13],'$1'+this.stripBaseURL(RegExp.$3)+'"');
+ }
+ if(this.config.only7BitPrintablesInURLs && c[13].test(sHtml)) {
+ sHtml = sHtml.replace(c[13], '$1'+RegExp.$3.replace(/([^!-~]+)/g,function(chr){return escape(chr);})+'"');
+ }
+ return sHtml;
+};
+
+/**
+ * Prettyfies html by inserting linebreaks before tags, and indenting blocklevel tags
+ */
+HTMLArea.indent = function(s, sindentChar) {
+ HTMLArea.__nindent = 0;
+ HTMLArea.__sindent = "";
+ HTMLArea.__sindentChar = (typeof sindentChar == "undefined") ? " " : sindentChar;
+ var c = HTMLArea.RegExpCache;
+ if(HTMLArea.is_gecko) { //moz changes returns into <br> inside <pre> tags
+ s = s.replace(c[19], function(str){return str.replace(/<br \/>/g,"\n")});
+ }
+ s = s.replace(c[18], function(strn) { //skip pre and script tags
+ strn = strn.replace(c[20], function(st,$1,$2,$3) { //exclude comments
+ string = $3.replace(/[\n\r]/gi, " ").replace(/\s+/gi," ").replace(c[14], function(str) {
+ if (str.match(c[16])) {
+ var s = "\n" + HTMLArea.__sindent + str;
+ // blocklevel openingtag - increase indent
+ HTMLArea.__sindent += HTMLArea.__sindentChar;
+ ++HTMLArea.__nindent;
+ return s;
+ } else if (str.match(c[15])) {
+ // blocklevel closingtag - decrease indent
+ --HTMLArea.__nindent;
+ HTMLArea.__sindent = "";
+ for (var i=HTMLArea.__nindent;i>0;--i) {
+ HTMLArea.__sindent += HTMLArea.__sindentChar;
+ }
+ return "\n" + HTMLArea.__sindent + str;
+ } else if (str.match(c[17])) {
+ // singlet tag
+ return "\n" + HTMLArea.__sindent + str;
+ }
+ return str; // this won't actually happen
+ });
+ return $1 + string;
+ });return strn;
+ });
+ //final cleanup
+ s = s.replace(/^\s*/,'').//strip leading whitespace
+ replace(/ +\n/g,'\n').//strip spaces at end of lines
+ replace(/[\r\n]+<\/script>/g,'\n</script>');//strip returns added into scripts
+ return s;
+};
+
+HTMLArea.getHTML = function(root, outputRoot, editor) {
+ var html = "";
+ var c = HTMLArea.RegExpCache;
+
+ if(root.nodeType == 11) {//document fragment
+ //we can't get innerHTML from the root (type 11) node, so we
+ //copy all the child nodes into a new div and get innerHTML from the div
+ var div = document.createElement("div");
+ var temp = root.insertBefore(div,root.firstChild);
+ for (j = temp.nextSibling; j; j = j.nextSibling) {
+ temp.appendChild(j.cloneNode(true));
+ }
+ html += temp.innerHTML.replace(c[23], function(strn) { //skip content inside script tags
+ strn = strn.replace(c[22], function(tag){
+ if(/^<[!\?]/.test(tag)) return tag; //skip comments and php tags
+ else return editor.cleanHTML(tag)});
+ return strn;
+ });
+
+ } else {
+
+ var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : '';
+ if (outputRoot) { //only happens with <html> tag in fullpage mode
+ html += "<" + root_tag;
+ var attrs = root.attributes; // strangely, this doesn't work in moz
+ for (i = 0; i < attrs.length; ++i) {
+ var a = attrs.item(i);
+ if (!a.specified) {
+ continue;
+ }
+ var name = a.nodeName.toLowerCase();
+ var value = a.nodeValue;
+ html += " " + name + '="' + value + '"';
+ }
+ html += ">";
+ }
+ if(root_tag == "html") {
+ innerhtml = editor._doc.documentElement.innerHTML;
+ } else {
+ innerhtml = root.innerHTML;
+ }
+ //pass tags to cleanHTML() one at a time
+ //includes support for htmlRemoveTags config option
+ html += innerhtml.replace(c[23], function(strn) { //skip content inside script tags
+ strn = strn.replace(c[22], function(tag){
+ if(/^<[!\?]/.test(tag)) return tag; //skip comments and php tags
+ else if(!(editor.config.htmlRemoveTags && editor.config.htmlRemoveTags.test(tag.replace(/<([^\s>\/]+)/,'$1'))))
+ return editor.cleanHTML(tag);
+ else return ''});
+ return strn;
+ });
+ //IE drops all </li> tags in a list except the last one
+ if(HTMLArea.is_ie) {
+ html = html.replace(/<li( [^>]*)?>/g,'</li><li$1>').
+ replace(/(<(ul|ol)[^>]*>)[\s\n]*<\/li>/g, '$1').
+ replace(/<\/li>([\s\n]*<\/li>)+/g, '<\/li>');
+ }
+ if(HTMLArea.is_gecko)
+ html = html.replace(/<br \/>\n$/, ''); //strip trailing <br> added by moz
+ if (outputRoot) {
+ html += "</" + root_tag + ">";
+ }
+ html = HTMLArea.indent(html);
+ };
+// html = HTMLArea.htmlEncode(html);
+
+ return html;
+};
+
+//overload outwardHtml() to handle onclick suppression
+HTMLArea.prototype._origOutwardHtml = HTMLArea.prototype.outwardHtml;
+HTMLArea.prototype.outwardHtml = function(html) {
+ html = html.replace("onclick=\"try{if(document.designMode && document.designMode == 'on') return false;}catch(e){} window.open(", "onclick=\"window.open(");
+ html = this._origOutwardHtml(html);
+ return html;
+};
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/horizontal-rule.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/horizontal-rule.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/horizontal-rule.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/horizontal-rule.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,102 @@
+
+HorizontalRule._pluginInfo = {
+ name : "HorizontalRule",
+ version : "1.0",
+ developer : "Nelson Bright",
+ developer_url : "http://www.brightworkweb.com/",
+ c_owner : "Nelson Bright",
+ sponsor : "BrightWork, Inc.",
+ sponsor_url : "http://www.brightworkweb.com/",
+ license : "htmlArea"
+};
+
+function HorizontalRule(editor) {
+ this.editor = editor;
+
+ var cfg = editor.config;
+ var toolbar = cfg.toolbar;
+ var self = this;
+
+ cfg.registerButton({
+ id : "edithorizontalrule",
+ tooltip : this._lc("Insert/edit horizontal rule"),
+ // image : editor.imgURL("ed_hr.gif", "HorizontalRule"),
+ image : [_editor_url + "images/ed_buttons_main.gif",6,0],
+ textMode : false,
+ action : function(editor) {
+ self.buttonPress(editor);
+ }
+ });
+
+ cfg.addToolbarElement("edithorizontalrule","inserthorizontalrule",0);
+}
+
+HorizontalRule.prototype._lc = function(string) {
+ return HTMLArea._lc(string, 'HorizontalRule');
+};
+
+HorizontalRule.prototype.buttonPress = function(editor) {
+ this.editor = editor;
+ this._editHorizontalRule();
+};
+
+HorizontalRule.prototype._editHorizontalRule = function(rule) {
+ editor = this.editor;
+ var sel = editor._getSelection();
+ var range = editor._createRange(sel);
+ var outparam = null;
+ if (typeof rule == "undefined") {
+ rule = editor.getParentElement();
+ if (rule && !/^hr$/i.test(rule.tagName))
+ rule = null;
+ }
+ if (rule) outparam = {
+ f_size : rule.size,
+ f_width : /%/.test(rule.width)? rule.width.substring(0,rule.width.length-1):rule.width,
+ f_widthUnit : /%/.test(rule.width)?"%":"px",
+ f_color : rule.color,
+ f_noshade : rule.noShade,
+ f_align : rule.align
+ };
+
+ editor._popupDialog("plugin://HorizontalRule/edit_horizontal_rule.html", function(param) {
+ if (!param) { // user pressed Cancel
+ return false;
+ }
+ var hr = rule;
+ if (!hr) {
+ var hrule = "<hr";
+ for (var field in param) {
+ var value = param[field];
+ if(value == "") continue;
+ switch (field) {
+ case "f_width" :
+ if(param["f_widthUnit"]=="%")hrule += " width='" + value+"%'";
+ else hrule += " width='" + value +"'"; break;
+ case "f_size" :
+ hrule += " size='" + value +"'"; break;
+ case "f_align" :
+ hrule += " align='" + value +"'"; break;
+ case "f_color" :
+ hrule += " color='" + value +"'"; break;
+ case "f_noshade" :
+ hrule += (value)? " noshade":""; break;
+ }
+ }
+ hrule += ">";
+ editor.insertHTML(hrule);
+ } else {
+ for (var field in param) {
+ var value = param[field];
+ switch (field) {
+ case "f_size" : hr.size = value; break;
+ case "f_width" : hr.width = (param["f_widthUnit"]=="%")?value+"%":value; break;
+ case "f_align" : hr.align = value; break;
+ case "f_color" : hr.color = value; break;
+ case "f_noshade" : hr.noShade = value; break;
+ }
+ }
+ }
+ }, outparam);
+};
+
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/de.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/de.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/de.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/de.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,21 @@
+// I18N constants
+// LANG: "de", ENCODING: UTF-8
+// translated: Udo Schmal (gocher), http://www.schaffrath-neuemedien.de/, udo.schmal@t-online.de
+{
+ "Insert/edit horizontal rule": "horizontale Linie einfügen/bearbeiten",
+ "Horizontal Rule": "Horizontale Linie",
+ "Layout": "Gestaltung",
+ "Width:": "Breite:",
+ "percent": "Prozent",
+ "pixels": "Pixel",
+ "Height:": "Höhe:",
+ "Alignment:": "Ausrichtung:",
+ "Left": "links",
+ "Center": "zentriert",
+ "Right": "rechts",
+ "Style": "Stil",
+ "Color:": "Farbe",
+ "No shading": "keine Schattierung",
+ "Note:": "Anmerkung",
+ "To select an existing horizontal rule, a double-click may be needed.": "Um eine horizontale Linie auszuwählen kann ein Doppelklick erforderlich sein."
+};
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/fr.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/fr.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/fr.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/fr.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,20 @@
+// I18N constants
+// LANG: "fr", ENCODING: UTF-8
+{
+ "Insert/edit horizontal rule": "Insérer une règle horizontale",
+ "Horizontal Rule": "Règle horizontale",
+ "Layout": "Layout",
+ "Width:": "Largeur",
+ "percent": "pourcent",
+ "pixels": "pixels",
+ "Height:": "Hauteur",
+ "Alignment:": "Alignement",
+ "Left": "Gauche",
+ "Center": "Centre",
+ "Right": "Droite",
+ "Style": "Style",
+ "Color:": "Couleur",
+ "No shading": "Pas d'ombre",
+ "Note:": "Note",
+ "To select an existing horizontal rule, a double-click may be needed.": "Pour sélectionner une règle horizontale, un double-clic peut être nécessaire."
+};
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/nb.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/nb.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/nb.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/nb.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,21 @@
+// I18N constants
+// LANG: "nb", ENCODING: UTF-8
+// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com
+{
+ "Insert/edit horizontal rule": "Sett inn/ rediger horisontal linje",
+ "Horizontal Rule": "Horisontal linje",
+ "Layout": "Oppsett",
+ "Width:": "Bredde:",
+ "percent": "prosent",
+ "pixels": "Piksel",
+ "Height:": "Høyde:",
+ "Alignment:": "Justering:",
+ "Left": "Venstre",
+ "Center": "Sentrert",
+ "Right": "Høyre",
+ "Style": "Stil",
+ "Color:": "Farge",
+ "No shading": "Ingen skygge",
+ "Note:": "Notat",
+ "To select an existing horizontal rule, a double-click may be needed.": "For å velge en horisontal linje kan det hende du må dobbeltklikke."
+};
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/no.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/no.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/no.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/lang/no.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,21 @@
+// I18N constants
+// LANG: "de", ENCODING: UTF-8
+// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com
+{
+ "Insert/edit horizontal rule": "Sett inn/ rediger horisontal linje",
+ "Horizontal Rule": "Horisontal linje",
+ "Layout": "Oppsett",
+ "Width:": "Bredde:",
+ "percent": "prosent",
+ "pixels": "Piksel",
+ "Height:": "Høyde:",
+ "Alignment:": "Justering:",
+ "Left": "Venstre",
+ "Center": "Sentrert",
+ "Right": "Høyre",
+ "Style": "Stil",
+ "Color:": "Farge",
+ "No shading": "Ingen skygge",
+ "Note:": "Notat",
+ "To select an existing horizontal rule, a double-click may be needed.": "For å velge en horisontal linje kan det hende du må dobbeltklikke."
+};
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/popups/edit_horizontal_rule.html
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/popups/edit_horizontal_rule.html?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/popups/edit_horizontal_rule.html (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HorizontalRule/popups/edit_horizontal_rule.html Sun Oct 8 12:53:13 2006
@@ -0,0 +1,159 @@
+<html>
+<head>
+ <title>Insert/Edit Horizontal Rule</title>
+ <link rel="stylesheet" type="text/css" href="../../../popups/popup.css" />
+ <script type="text/javascript" src="../../../popups/popup.js"></script>
+
+<script type="text/javascript">
+editor = window.opener.editor;
+
+function Init() {
+ __dlg_translate("HorizontalRule");
+ __dlg_init();
+ window.resizeTo(300,320);
+ var params = window.dialogArguments;
+ if(params) {
+ document.getElementById("f_size").value = params.f_size;
+ document.getElementById("f_width").value = params.f_width;
+ document.getElementById("f_widthUnit").value = params.f_widthUnit;
+ document.getElementById("f_align").value = params.f_align;
+ document.getElementById("f_color").value = params.f_color;
+ document.getElementById("hrpv").style.backgroundColor = params.f_color;
+ document.getElementById("f_noshade").checked = params.f_noshade;
+ }
+ document.getElementById("f_width").focus();
+}
+
+function onOK() {
+ var fields = ["f_size", "f_width", "f_widthUnit", "f_align", "f_color", "f_noshade"];
+ var param = new Object();
+ for (var i in fields) {
+ var id = fields[i];
+ var el = document.getElementById(id);
+ param[id] = (el.type == "checkbox") ? el.checked : el.value;
+ }
+ __dlg_close(param);
+ return false;
+}
+
+function onCancel() {
+ __dlg_close(null);
+ return false;
+}
+
+function selectColor(id1,id2,color) {
+ Dialog(editor.popupURL("select_color.html"), function(color){
+ if (color) {
+ document.getElementById(id1).style.backgroundColor="#"+color;
+ document.getElementById(id2).value="#"+color;
+ }
+ }, color);
+}
+function Dialog(url, action, init) {
+ Dialog.openModal(url, action, init);
+}
+Dialog.openModal = function(url, action, init) {
+ var dlg2 = window.open(url, "hadialog2",
+ "toolbar=no,menubar=no,personalbar=no,width=10,height=10," +
+ "scrollbars=no,resizable=yes,modal=yes,dependable=yes");
+ Dialog._modal = dlg2;
+ Dialog._arguments = init;
+ Dialog._return = function (val) {
+ if (val && action) {
+ action(val);
+ }
+ Dialog._modal = null;
+ };
+};
+
+</script>
+
+<style type="text/css">
+.buttonColor {
+ padding: 1px;
+ cursor: default;
+ border: 1px solid;
+ border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight;
+}
+
+.buttonColor-hilite {
+ border-color: #000;
+}
+
+.buttonColor .chooser {
+ height: 0.6em;
+ border: 1px solid;
+ padding: 0px 1em;
+ border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
+}
+
+.buttonColor .nocolor {
+ padding: 0px;
+ height: 0.6em;
+ border: 1px solid;
+ border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow;
+}
+.buttonColor .nocolor-hilite { background-color: #fff; color: #f00; }
+</style>
+<style type="text/css">
+@import url(../../../popups/popupstyle.css);
+</style>
+
+</head>
+
+<body class="dialog" onload="Init()">
+<div class="title">Horizontal Rule</div>
+<form action="" method="get">
+ <fieldset>
+ <legend>Layout</legend>
+ <div class="fr">Width:</div>
+ <input style="margin-right: 0.5em;" name="f_width" id="f_width" size="5" type="text">
+ <select style="margin-right: 0.5em;" name="f_widthUnit" id="f_widthUnit">
+ <option value="%">percent</option>
+ <option value="px">pixels</option>
+ </select>
+ <p />
+ <div class="fr">Height:</div>
+ <input style="margin-right: 0.5em;" name="f_size" id="f_size" size="5" type="text"> <span>pixels</span>
+ <p />
+ <div class="fr">Alignment:</div>
+ <select name="f_align" id="f_align">
+ <option value="left">Left</option>
+ <option value="center">Center</option>
+ <option value="right">Right</option>
+ </select>
+ <p />
+ </fieldset>
+ <fieldset>
+ <legend>Style</legend>
+ <div class="fr">Color:</div>
+ <table cellpadding="2" cellspacing="0" id="hrbtn" class="buttonColor">
+ <tr>
+ <td class="chooser" id="hrpv"
+ onMouseOver="document.getElementById('hrbtn').style.borderColor='black'"
+ onMouseOut="document.getElementById('hrbtn').style.borderColor='ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight'"
+ onClick="selectColor('hrpv','f_color',document.getElementById('f_color').value)"> </td>
+ <td class="nocolor" id="hrclr"
+ onMouseOver="document.getElementById('hrclr').style.color='#f00'"
+ onMouseOut="document.getElementById('hrclr').style.color='#000'"
+ onClick="document.getElementById('f_color').value=''; document.getElementById('hrpv').style.backgroundColor=''">×</td>
+ </tr>
+ </table>
+ <p />
+ <div class="fr"> </div>
+ <input type="hidden" name="f_color" id="f_color">
+ <input type="checkbox" name="f_noshade" id="f_noshade" value="noshade">
+ <span>No shading</span>
+ <p />
+ </fieldset>
+ <fieldset>
+ <legend>Note:</legend>
+ <span>To select an existing horizontal rule, a double-click may be needed.</span>
+ </fieldset>
+<div id="buttons">
+ <button type="submit" name="ok" onclick="return onOK();">OK</button>
+ <button type="button" name="cancel" onclick="return onCancel();">Cancel</button>
+</div>
+</form>
+</body>
+</html>
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/README
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/README?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/README (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/README Sun Oct 8 12:53:13 2006
@@ -0,0 +1,104 @@
+// Plugin for htmlArea to run code through the server's HTML Tidy
+// By Adam Wright, for The University of Western Australia
+//
+// Email: zeno@ucc.gu.uwa.edu.au
+// Homepage: http://blog.hipikat.org/
+//
+// Distributed under the same terms as HTMLArea itself.
+// This notice MUST stay intact for use (see license.txt).
+//
+// Version: 0.5
+// Released to the outside world: 04/03/04
+
+
+HtmlTidy is a plugin for the popular cross-browser TTY WYSIWYG editor,
+htmlArea (http://www.interactivetools.com/products/htmlarea/). HtmlTidy
+basically queries HTML Tidy (http://tidy.sourceforge.net/) on the
+server side, getting it to make-html-nice, instead of relying on masses
+of javascript, which the client would have to download.
+
+Hi, this is a quick explanation of how to install HtmlTidy. Much better
+documentation is probably required, and you're welcome to write it :)
+
+
+* The HtmlTidy directory you should have found this file in should
+ include the following:
+
+ - README
+ This file, providing help installing the plugin.
+
+ - html-tidy-config.cfg
+ This file contains the configuration options HTML Tidy uses to
+ clean html, and can be modified to suit your organizations
+ requirements.
+
+ - html-tidy-logic.php
+ This is the php script, which is queried with dirty html and is
+ responsible for invoking HTML Tidy, getting nice new html and
+ returning it to the client.
+
+ - html-tidy.js
+ The main htmlArea plugin, providing functionality to tidy html
+ through the htmlArea interface.
+
+ - htmlarea.js.onmode_event.diff
+ At the time of publishing, an extra event handler was required
+ inside the main htmlarea.js file. htmlarea.js may be patched
+ against this file to make the changes reuquired, but be aware
+ that the event handler may either now be in the core or
+ htmlarea.js may have changed enough to invalidate the patch.
+
+ UPDATE: now it exists in the official htmlarea.js; applying
+ this patch is thus no longer necessary.
+
+ - img/html-tidy.gif
+ The HtmlTidy icon, for the htmlArea toolbar. Created by Dan
+ Petty for The University of Western Australia.
+
+ - lang/en.js
+ English language file. Add your own language files here and
+ please contribute back into the htmlArea community!
+
+ The HtmlArea directory should be extracted to your htmlarea/plugins/
+ directory.
+
+
+* Make sure the onMode event handler mentioned above, regarding
+ htmlarea.js.onmode_event.diff, exists in your htmlarea.js
+
+
+* html-tidy-logic.php should be executable, and your web server should
+ be configured to execute php scripts in the directory
+ html-tidy-logic.php exists in.
+
+
+* HTML Tidy needs to be installed on your server, and 'tidy' should be
+ an alias to it, lying in the PATH known to the user executing such
+ web scripts.
+
+
+* In your htmlArea configuration, do something like this:
+
+ HTMLArea.loadPlugin("HtmlTidy");
+
+ editor = new HTMLArea("doc");
+ editor.registerPlugin("HtmlTidy");
+
+
+* Then, in your htmlArea toolbar configuration, use:
+
+ - "HT-html-tidy"
+ This will create the 'tidy broom' icon on the toolbar, which
+ will attempt to tidy html source when clicked, and;
+
+ - "HT-auto-tidy"
+ This will create an "Auto Tidy" / "Don't Tidy" dropdown, to
+ select whether the source should be tidied automatically when
+ entering source view. On by default, if you'd like it otherwise
+ you can do so programatically after generating the toolbar :)
+ (Or just hack it to be otherwise...)
+
+
+Thank you.
+
+Any bugs you find can be emailed to zeno@ucc.gu.uwa.edu.au
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-config.cfg
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-config.cfg?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-config.cfg (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-config.cfg Sun Oct 8 12:53:13 2006
@@ -0,0 +1,29 @@
+// Default configuration file for the htmlArea, HtmlTidy plugin
+// By Adam Wright, for The University of Western Australia
+//
+// Evertything you always wanted to know about HTML Tidy *
+// can be found at http://tidy.sourceforge.net/, and a
+// quick reference to the configuration options exists at
+// http://tidy.sourceforge.net/docs/quickref.html
+//
+// * But were afraid to ask
+//
+// Distributed under the same terms as HTMLArea itself.
+// This notice MUST stay intact for use (see license.txt).
+
+word-2000: yes
+clean: yes
+drop-font-tags: no
+doctype: auto
+drop-empty-paras: yes
+drop-proprietary-attributes: yes
+enclose-block-text: yes
+enclose-text: yes
+escape-cdata: yes
+logical-emphasis: yes
+indent: auto
+indent-spaces: 2
+break-before-br: yes
+output-xhtml: yes
+
+force-output: yes
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-logic.php
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-logic.php?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-logic.php (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-logic.php Sun Oct 8 12:53:13 2006
@@ -0,0 +1,79 @@
+<?php
+##
+## Plugin for htmlArea, to run code through the server's HTML Tidy
+## By Adam Wright, for The University of Western Australia
+## This is the server-side script, which dirty code is run through.
+##
+## Distributed under the same terms as HTMLArea itself.
+## This notice MUST stay intact for use (see license.txt).
+##
+
+ // Get the original source
+ $source = $_POST['htisource_name'];
+ $source = stripslashes($source);
+ $cwd = str_replace("\\","/",getcwd())."/";
+
+ // Open a tidy process - I hope it's installed!
+ $descriptorspec = array(
+ 0 => array("pipe", "r"),
+ 1 => array("pipe", "w")
+ );
+ $process = @proc_open("tidy -utf8 -config {$cwd}html-tidy-config.cfg", $descriptorspec, $pipes);
+
+
+ // Make sure the program started and we got the hooks...
+ // Either way, get some source code into $source
+ if (is_resource($process)) {
+
+ // Feed untidy source into the stdin
+ fwrite($pipes[0], $source);
+ fclose($pipes[0]);
+
+ // Read clean source out to the browser
+ while (!feof($pipes[1])) {
+ //echo fgets($pipes[1], 1024);
+ $newsrc .= fgets($pipes[1], 1024);
+ }
+ fclose($pipes[1]);
+
+ // Clean up after ourselves
+ proc_close($process);
+
+ } else {
+ /* Use tidy if it's available from PECL */
+ if( function_exists('tidy_parse_string') )
+ {
+ $tempsrc = tidy_parse_string($source);
+ tidy_clean_repair();
+ $newsrc = tidy_get_output();
+ }
+ else
+ {
+ // Better give them back what they came with, so they don't lose it all...
+ $newsrc = "<body>\n" .$source. "\n</body>";
+ }
+ }
+
+ // Split our source into an array by lines
+ $srcLines = preg_split("/\n/",$newsrc,-1,PREG_SPLIT_NO_EMPTY);
+
+ // Get only the lines between the body tags
+ $startLn = 0;
+ while ( strpos( $srcLines[$startLn++], '<body' ) === false && $startLn < sizeof($srcLines) );
+ $endLn = $startLn;
+ while ( strpos( $srcLines[$endLn++], '</body' ) === false && $endLn < sizeof($srcLines) );
+
+ $srcLines = array_slice( $srcLines, $startLn, ($endLn - $startLn - 1) );
+
+ // Create a set of javascript code to compile a new source string
+ foreach ($srcLines as $line) {
+ $jsMakeSrc .= "\tns += '" . str_replace("'","\'",$line) . "\\n';\n";
+ }
+if(!sizeof($srcLines)) {
+ echo "alert(HTMLArea._lc('Tidy failed. Check your HTML for syntax errors.', 'HtmlTidy'));\n";
+} else {
+?>
+var ns="";
+<?php echo $jsMakeSrc; ?>
+editor.setHTML(ns);
+<? } ?>
\ No newline at end of file
Propchange: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy-logic.php
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/html-tidy.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,105 @@
+// Plugin for htmlArea to run code through the server's HTML Tidy
+// By Adam Wright, for The University of Western Australia
+//
+// Distributed under the same terms as HTMLArea itself.
+// This notice MUST stay intact for use (see license.txt).
+
+function HtmlTidy(editor) {
+ this.editor = editor;
+
+ var cfg = editor.config;
+ var bl = HtmlTidy.btnList;
+ var self = this;
+
+ this.onMode = this.__onMode;
+
+ // register the toolbar buttons provided by this plugin
+ var toolbar = [];
+ for (var i = 0; i < bl.length; ++i) {
+ var btn = bl[i];
+ if (btn == "html-tidy") {
+ var id = "HT-html-tidy";
+ cfg.registerButton(id, this._lc("HTML Tidy"), editor.imgURL(btn[0] + ".gif", "HtmlTidy"), true,
+ function(editor, id) {
+ // dispatch button press event
+ self.buttonPress(editor, id);
+ }, btn[1]);
+ toolbar.push(id);
+ } else if (btn == "html-auto-tidy") {
+ var btnTxt = [this._lc("Auto-Tidy"), this._lc("Don't Tidy")];
+ var optionItems = new Object();
+ optionItems[btnTxt[0]] = "auto";
+ optionItems[btnTxt[1]] = "noauto";
+ var ht_class = {
+ id : "HT-auto-tidy",
+ options : optionItems,
+ action : function (editor) { self.__onSelect(editor, this); },
+ refresh : function (editor) { },
+ context : "body"
+ };
+ cfg.registerDropdown(ht_class);
+ }
+ }
+
+ for (var i in toolbar) {
+ cfg.toolbar[0].push(toolbar[i]);
+ }
+}
+
+HtmlTidy._pluginInfo = {
+ name : "HtmlTidy",
+ version : "1.0",
+ developer : "Adam Wright",
+ developer_url : "http://blog.hipikat.org/",
+ sponsor : "The University of Western Australia",
+ sponsor_url : "http://www.uwa.edu.au/",
+ license : "htmlArea"
+};
+
+HtmlTidy.prototype._lc = function(string) {
+ return HTMLArea._lc(string, 'HtmlTidy');
+};
+
+HtmlTidy.prototype.__onSelect = function(editor, obj) {
+ // Get the toolbar element object
+ var elem = editor._toolbarObjects[obj.id].element;
+
+ // Set our onMode event appropriately
+ if (elem.value == "auto")
+ this.onMode = this.__onMode;
+ else
+ this.onMode = null;
+};
+
+HtmlTidy.prototype.__onMode = function(mode) {
+ if ( mode == "textmode" ) {
+ this.buttonPress(this.editor, "HT-html-tidy");
+ }
+};
+
+HtmlTidy.btnList = [
+ null, // separator
+ ["html-tidy"],
+ ["html-auto-tidy"]
+];
+
+HtmlTidy.prototype.buttonPress = function(editor, id) {
+
+ switch (id)
+ {
+ case "HT-html-tidy":
+ {
+ var oldhtml = editor.getHTML();
+ if(oldhtml=="") break; //don't clean empty text
+ // Ask the server for some nice new html, based on the old...
+ HTMLArea._postback(_editor_url + 'plugins/HtmlTidy/html-tidy-logic.php', {'htisource_name' : oldhtml},
+ function(javascriptResponse) { eval(javascriptResponse) });
+ }
+ break;
+ }
+};
+
+HtmlTidy.prototype.processTidied = function(newSrc) {
+ editor = this.editor;
+ editor.setHTML(newSrc);
+};
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/img/html-tidy.gif
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/img/html-tidy.gif?view=auto&rev=454197
==============================================================================
Binary file - no diff available.
Propchange: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/img/html-tidy.gif
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/de.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/de.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/de.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/de.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,7 @@
+// I18N constants
+// LANG: "de", ENCODING: UTF-8
+// Author: Raimund Meyer ray@ray-of-light.org
+{
+ "HTML Tidy": "HTML Tidy",
+ "Tidy failed. Check your HTML for syntax errors.": "Tidy fehlgeschlagen. Prüfen Sie den HTML Code nach Syntax-Fehlern."
+};
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/fr.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/fr.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/fr.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/fr.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,8 @@
+// I18N constants
+// LANG: "fr", ENCODING: UTF-8
+{
+ "HTML Tidy": "HTML Tidy",
+ "Auto-Tidy": "Tidy automatique",
+ "Don't Tidy": "Tidy non utilisé",
+ "Tidy failed. Check your HTML for syntax errors.": "Tidy a échoué. Vérifiez votre HTML for des erreurs de syntaxe"
+};
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nb.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nb.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nb.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nb.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,7 @@
+// I18N constants
+// LANG: "nb", ENCODING: UTF-8
+// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com
+{
+ "HTML Tidy": "HTML Tidy",
+ "Tidy failed. Check your HTML for syntax errors.": "Tidy feilet. Sjekk HTML koden for syntaksfeil."
+};
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nl.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nl.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nl.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/nl.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,5 @@
+// I18N constants
+// LANG: "nl", ENCODING: UTF-8
+{
+ "HT-html-tidy": "HTML opschonen"
+};
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/no.js
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/no.js?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/no.js (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/HtmlTidy/lang/no.js Sun Oct 8 12:53:13 2006
@@ -0,0 +1,7 @@
+// I18N constants
+// LANG: "no", ENCODING: UTF-8
+// translated: Kim Steinhaug, http://www.steinhaug.com/, kim@steinhaug.com
+{
+ "HTML Tidy": "HTML Tidy",
+ "Tidy failed. Check your HTML for syntax errors.": "Tidy feilet. Sjekk HTML koden for syntaksfeil."
+};
\ No newline at end of file
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/Files.php
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/Files.php?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/Files.php (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/Files.php Sun Oct 8 12:53:13 2006
@@ -0,0 +1,269 @@
+<?php
+/**
+ * File Utilities.
+ * @author $Author: Wei Zhuo $
+ * @version $Id: Files.php 26 2004-03-31 02:35:21Z Wei Zhuo $
+ * @package ImageManager
+ */
+
+define('FILE_ERROR_NO_SOURCE', 100);
+define('FILE_ERROR_COPY_FAILED', 101);
+define('FILE_ERROR_DST_DIR_FAILED', 102);
+define('FILE_COPY_OK', 103);
+
+/**
+ * File Utilities
+ * @author $Author: Wei Zhuo $
+ * @version $Id: Files.php 26 2004-03-31 02:35:21Z Wei Zhuo $
+ * @package ImageManager
+ * @subpackage files
+ */
+class Files
+{
+
+ /**
+ * Copy a file from source to destination. If unique == true, then if
+ * the destination exists, it will be renamed by appending an increamenting
+ * counting number.
+ * @param string $source where the file is from, full path to the files required
+ * @param string $destination_file name of the new file, just the filename
+ * @param string $destination_dir where the files, just the destination dir,
+ * e.g., /www/html/gallery/
+ * @param boolean $unique create unique destination file if true.
+ * @return string the new copied filename, else error if anything goes bad.
+ */
+ function copyFile($source, $destination_dir, $destination_file, $unique=true)
+ {
+ if(!(file_exists($source) && is_file($source)))
+ return FILE_ERROR_NO_SOURCE;
+
+ $destination_dir = Files::fixPath($destination_dir);
+
+ if(!is_dir($destination_dir))
+ Return FILE_ERROR_DST_DIR_FAILED;
+
+ $filename = Files::escape($destination_file);
+
+ if($unique)
+ {
+ $dotIndex = strrpos($destination_file, '.');
+ $ext = '';
+ if(is_int($dotIndex))
+ {
+ $ext = substr($destination_file, $dotIndex);
+ $base = substr($destination_file, 0, $dotIndex);
+ }
+ $counter = 0;
+ while(is_file($destination_dir.$filename))
+ {
+ $counter++;
+ $filename = $base.'_'.$counter.$ext;
+ }
+ }
+
+ if (!copy($source, $destination_dir.$filename))
+ return FILE_ERROR_COPY_FAILED;
+
+ //verify that it copied, new file must exists
+ if (is_file($destination_dir.$filename))
+ Return $filename;
+ else
+ return FILE_ERROR_COPY_FAILED;
+ }
+
+ /**
+ * Create a new folder.
+ * @param string $newFolder specifiy the full path of the new folder.
+ * @return boolean true if the new folder is created, false otherwise.
+ */
+ function createFolder($newFolder)
+ {
+ mkdir ($newFolder, 0777);
+ return chmod($newFolder, 0777);
+ }
+
+
+ /**
+ * Escape the filenames, any non-word characters will be
+ * replaced by an underscore.
+ * @param string $filename the orginal filename
+ * @return string the escaped safe filename
+ */
+ function escape($filename)
+ {
+ Return preg_replace('/[^\w\._]/', '_', $filename);
+ }
+
+ /**
+ * Delete a file.
+ * @param string $file file to be deleted
+ * @return boolean true if deleted, false otherwise.
+ */
+ function delFile($file)
+ {
+ if(is_file($file))
+ Return unlink($file);
+ else
+ Return false;
+ }
+
+ /**
+ * Delete folder(s), can delete recursively.
+ * @param string $folder the folder to be deleted.
+ * @param boolean $recursive if true, all files and sub-directories
+ * are delete. If false, tries to delete the folder, can throw
+ * error if the directory is not empty.
+ * @return boolean true if deleted.
+ */
+ function delFolder($folder, $recursive=false)
+ {
+ $deleted = true;
+ if($recursive)
+ {
+ $d = dir($folder);
+ while (false !== ($entry = $d->read()))
+ {
+ if ($entry != '.' && $entry != '..')
+ {
+ $obj = Files::fixPath($folder).$entry;
+ //var_dump($obj);
+ if (is_file($obj))
+ {
+ $deleted &= Files::delFile($obj);
+ }
+ else if(is_dir($obj))
+ {
+ $deleted &= Files::delFolder($obj, $recursive);
+ }
+
+ }
+ }
+ $d->close();
+
+ }
+
+ //$folder= $folder.'/thumbs';
+ //var_dump($folder);
+ if(is_dir($folder))
+ $deleted &= rmdir($folder);
+ else
+ $deleted &= false;
+
+ Return $deleted;
+ }
+
+ /**
+ * Append a / to the path if required.
+ * @param string $path the path
+ * @return string path with trailing /
+ */
+ function fixPath($path)
+ {
+ //append a slash to the path if it doesn't exists.
+ if(!(substr($path,-1) == '/'))
+ $path .= '/';
+ Return $path;
+ }
+
+ /**
+ * Concat two paths together. Basically $pathA+$pathB
+ * @param string $pathA path one
+ * @param string $pathB path two
+ * @return string a trailing slash combinded path.
+ */
+ function makePath($pathA, $pathB)
+ {
+ $pathA = Files::fixPath($pathA);
+ if(substr($pathB,0,1)=='/')
+ $pathB = substr($pathB,1);
+ Return Files::fixPath($pathA.$pathB);
+ }
+
+ /**
+ * Similar to makePath, but the second parameter
+ * is not only a path, it may contain say a file ending.
+ * @param string $pathA the leading path
+ * @param string $pathB the ending path with file
+ * @return string combined file path.
+ */
+ function makeFile($pathA, $pathB)
+ {
+ $pathA = Files::fixPath($pathA);
+ if(substr($pathB,0,1)=='/')
+ $pathB = substr($pathB,1);
+
+ Return $pathA.$pathB;
+ }
+
+
+ /**
+ * Format the file size, limits to Mb.
+ * @param int $size the raw filesize
+ * @return string formated file size.
+ */
+ function formatSize($size)
+ {
+ if($size < 1024)
+ return $size.' bytes';
+ else if($size >= 1024 && $size < 1024*1024)
+ return sprintf('%01.2f',$size/1024.0).' KB';
+ else
+ return sprintf('%01.2f',$size/(1024.0*1024)).' MB';
+ }
+
+ /**
+ * Returns size of a directory, with all file & subdirectory
+ * sizes added up
+ * @param string dir path
+ * @return int
+ */
+ function dirSize($dirName = '.')
+ {
+ $dir = dir($dirName);
+ $size = 0;
+
+ while ($file = $dir->read()) {
+ if ($file != '.' && $file != '..')
+ {
+ if (is_dir("$dirName$file"))
+ {
+ $size += Files::dirSize($dirName . '/' . $file);
+ }
+ else
+ {
+ $size += filesize($dirName . '/' . $file);
+ }
+ }
+ }
+ $dir->close();
+ return $size;
+ }
+
+ /**
+ * Renames file, preserving its directory and extension
+ * @param string $oldPath path to the old existing file
+ * @param string new filename (just the name, without path or extension)
+ * @author Krzysztof Kotowicz <ko...@webworkers.pl>
+ */
+ function renameFile($oldPath, $newName) {
+
+ if(!(file_exists($oldPath) && is_file($oldPath)))
+ return FILE_ERROR_NO_SOURCE;
+
+ $oldFileParts = pathinfo($oldPath);
+
+ $newPath = $oldFileParts['dirname'] . '/'
+ . $newName
+ . (!empty($oldFileParts['extension']) ? '.' . $oldFileParts['extension'] : '');
+
+ if (file_exists($newPath))
+ return false;
+
+ if (!rename($oldPath, $newPath))
+ return FILE_ERROR_COPY_FAILED;
+
+ }
+
+}
+
+?>
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/GD.php
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/GD.php?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/GD.php (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/GD.php Sun Oct 8 12:53:13 2006
@@ -0,0 +1,503 @@
+<?php
+/***********************************************************************
+** Title.........: GD Driver
+** Version.......: 1.0
+** Author........: Xiang Wei ZHUO <we...@zhuo.org>
+** Filename......: GD.php
+** Last changed..: 30 Aug 2003
+** Notes.........: Orginal is from PEAR
+**/
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Peter Bowyer <pe...@mapledesign.co.uk> |
+// | Alan Knowles <al...@akbkhome.com> |
+// +----------------------------------------------------------------------+
+//
+// Usage :
+// $img = new Image_Transform_GD();
+// $angle = -78;
+// $img->load('magick.png');
+//
+// if($img->rotate($angle,array('autoresize'=>true,'color_mask'=>array(255,0,0)))){
+// $img->addText(array('text'=>"Rotation $angle",'x'=>0,'y'=>100,'font'=>'/usr/share/fonts/default/TrueType/cogb____.ttf'));
+// $img->display();
+// } else {
+// echo "Error";
+// }
+//
+//
+// $Id: GD.php 26 2004-03-31 02:35:21Z Wei Zhuo $
+//
+// Image Transformation interface using the GD library
+//
+
+require_once "Transform.php";
+
+Class Image_Transform_Driver_GD extends Image_Transform
+{
+ /**
+ * Holds the image file for manipulation
+ */
+ var $imageHandle = '';
+
+ /**
+ * Holds the original image file
+ */
+ var $old_image = '';
+
+ /**
+ * Check settings
+ *
+ * @return mixed true or or a PEAR error object on error
+ *
+ * @see PEAR::isError()
+ */
+ function Image_Transform_GD()
+ {
+ return;
+ } // End function Image
+
+ /**
+ * Load image
+ *
+ * @param string filename
+ *
+ * @return mixed none or a PEAR error object on error
+ * @see PEAR::isError()
+ */
+ function load($image)
+ {
+ $this->uid = md5($_SERVER['REMOTE_ADDR']);
+ $this->image = $image;
+ $this->_get_image_details($image);
+ $functionName = 'ImageCreateFrom' . $this->type;
+ if(function_exists($functionName))
+ {
+ $this->imageHandle = $functionName($this->image);
+ }
+ } // End load
+
+ /**
+ * addText
+ *
+ * @param array options Array contains options
+ * array(
+ * 'text' The string to draw
+ * 'x' Horizontal position
+ * 'y' Vertical Position
+ * 'Color' Font color
+ * 'font' Font to be used
+ * 'size' Size of the fonts in pixel
+ * 'resize_first' Tell if the image has to be resized
+ * before drawing the text
+ * )
+ *
+ * @return none
+ * @see PEAR::isError()
+ */
+ function addText($params)
+ {
+ $default_params = array(
+ 'text' => 'This is Text',
+ 'x' => 10,
+ 'y' => 20,
+ 'color' => array(255,0,0),
+ 'font' => 'Arial.ttf',
+ 'size' => '12',
+ 'angle' => 0,
+ 'resize_first' => false // Carry out the scaling of the image before annotation? Not used for GD
+ );
+ $params = array_merge($default_params, $params);
+ extract($params);
+
+ if( !is_array($color) ){
+ if ($color[0]=='#'){
+ $this->colorhex2colorarray( $color );
+ } else {
+ include_once('Image/Transform/Driver/ColorsDefs.php');
+ $color = isset($colornames[$color])?$colornames[$color]:false;
+ }
+ }
+
+ $c = imagecolorresolve ($this->imageHandle, $color[0], $color[1], $color[2]);
+
+ if ('ttf' == substr($font, -3)) {
+ ImageTTFText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text);
+ } else {
+ ImagePSText($this->imageHandle, $size, $angle, $x, $y, $c, $font, $text);
+ }
+ return true;
+ } // End addText
+
+
+ /**
+ * Rotate image by the given angle
+ * Uses a fast rotation algorythm for custom angles
+ * or lines copy for multiple of 90 degrees
+ *
+ * @param int $angle Rotation angle
+ * @param array $options array( 'autoresize'=>true|false,
+ * 'color_mask'=>array(r,g,b), named color or #rrggbb
+ * )
+ * @author Pierre-Alain Joye
+ * @return mixed none or a PEAR error object on error
+ * @see PEAR::isError()
+ */
+ function rotate($angle, $options=null)
+ {
+ if(function_exists('imagerotate')) {
+ $white = imagecolorallocate ($this->imageHandle, 255, 255, 255);
+ $this->imageHandle = imagerotate($this->imageHandle, $angle, $white);
+ return true;
+ }
+
+ if ( $options==null ){
+ $autoresize = true;
+ $color_mask = array(255,255,0);
+ } else {
+ extract( $options );
+ }
+
+ while ($angle <= -45) {
+ $angle += 360;
+ }
+ while ($angle > 270) {
+ $angle -= 360;
+ }
+
+ $t = deg2rad($angle);
+
+ if( !is_array($color_mask) ){
+ if ($color[0]=='#'){
+ $this->colorhex2colorarray( $color_mask );
+ } else {
+ include_once('Image/Transform/Driver/ColorDefs.php');
+ $color = isset($colornames[$color_mask])?$colornames[$color_mask]:false;
+ }
+ }
+
+ // Do not round it, too much lost of quality
+ $cosT = cos($t);
+ $sinT = sin($t);
+
+ $img =& $this->imageHandle;
+
+ $width = $max_x = $this->img_x;
+ $height = $max_y = $this->img_y;
+ $min_y = 0;
+ $min_x = 0;
+
+ $x1 = round($max_x/2,0);
+ $y1 = round($max_y/2,0);
+
+ if ( $autoresize ){
+ $t = abs($t);
+ $a = round($angle,0);
+ switch((int)($angle)){
+ case 0:
+ $width2 = $width;
+ $height2 = $height;
+ break;
+ case 90:
+ $width2 = $height;
+ $height2 = $width;
+ break;
+ case 180:
+ $width2 = $width;
+ $height2 = $height;
+ break;
+ case 270:
+ $width2 = $height;
+ $height2 = $width;
+ break;
+ default:
+ $width2 = (int)(abs(sin($t) * $height + cos($t) * $width));
+ $height2 = (int)(abs(cos($t) * $height+sin($t) * $width));
+ }
+
+ $width2 -= $width2%2;
+ $height2 -= $height2%2;
+
+ $d_width = abs($width - $width2);
+ $d_height = abs($height - $height2);
+ $x_offset = $d_width/2;
+ $y_offset = $d_height/2;
+ $min_x2 = -abs($x_offset);
+ $min_y2 = -abs($y_offset);
+ $max_x2 = $width2;
+ $max_y2 = $height2;
+ }
+
+ $img2 = @imagecreate($width2,$height2);
+
+ if ( !is_resource($img2) ){
+ return false;/*PEAR::raiseError('Cannot create buffer for the rotataion.',
+ null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);*/
+ }
+
+ $this->img_x = $width2;
+ $this->img_y = $height2;
+
+
+ imagepalettecopy($img2,$img);
+
+ $mask = imagecolorresolve($img2,$color_mask[0],$color_mask[1],$color_mask[2]);
+
+ // use simple lines copy for axes angles
+ switch((int)($angle)){
+ case 0:
+ imagefill ($img2, 0, 0,$mask);
+ for ($y=0; $y < $max_y; $y++) {
+ for ($x = $min_x; $x < $max_x; $x++){
+ $c = @imagecolorat ( $img, $x, $y);
+ imagesetpixel($img2,$x+$x_offset,$y+$y_offset,$c);
+ }
+ }
+ break;
+ case 90:
+ imagefill ($img2, 0, 0,$mask);
+ for ($x = $min_x; $x < $max_x; $x++){
+ for ($y=$min_y; $y < $max_y; $y++) {
+ $c = imagecolorat ( $img, $x, $y);
+ imagesetpixel($img2,$max_y-$y-1,$x,$c);
+ }
+ }
+ break;
+ case 180:
+ imagefill ($img2, 0, 0,$mask);
+ for ($y=0; $y < $max_y; $y++) {
+ for ($x = $min_x; $x < $max_x; $x++){
+ $c = @imagecolorat ( $img, $x, $y);
+ imagesetpixel($img2, $max_x2-$x-1, $max_y2-$y-1, $c);
+ }
+ }
+ break;
+ case 270:
+ imagefill ($img2, 0, 0,$mask);
+ for ($y=0; $y < $max_y; $y++) {
+ for ($x = $max_x; $x >= $min_x; $x--){
+ $c = @imagecolorat ( $img, $x, $y);
+ imagesetpixel($img2,$y,$max_x-$x-1,$c);
+ }
+ }
+ break;
+ // simple reverse rotation algo
+ default:
+ $i=0;
+ for ($y = $min_y2; $y < $max_y2; $y++){
+
+ // Algebra :)
+ $x2 = round((($min_x2-$x1) * $cosT) + (($y-$y1) * $sinT + $x1),0);
+ $y2 = round((($y-$y1) * $cosT - ($min_x2-$x1) * $sinT + $y1),0);
+
+ for ($x = $min_x2; $x < $max_x2; $x++){
+
+ // Check if we are out of original bounces, if we are
+ // use the default color mask
+ if ( $x2>=0 && $x2<$max_x && $y2>=0 && $y2<$max_y ){
+ $c = imagecolorat ( $img, $x2, $y2);
+ } else {
+ $c = $mask;
+ }
+ imagesetpixel($img2,$x+$x_offset,$y+$y_offset,$c);
+
+ // round verboten!
+ $x2 += $cosT;
+ $y2 -= $sinT;
+ }
+ }
+ break;
+ }
+ $this->old_image = $this->imageHandle;
+ $this->imageHandle = $img2;
+ return true;
+ }
+
+
+ /**
+ * Resize Action
+ *
+ * For GD 2.01+ the new copyresampled function is used
+ * It uses a bicubic interpolation algorithm to get far
+ * better result.
+ *
+ * @param int $new_x new width
+ * @param int $new_y new height
+ *
+ * @return true on success or pear error
+ * @see PEAR::isError()
+ */
+ function _resize($new_x, $new_y) {
+ if ($this->resized === true) {
+ return false; /*PEAR::raiseError('You have already resized the image without saving it. Your previous resizing will be overwritten', null, PEAR_ERROR_TRIGGER, E_USER_NOTICE);*/
+ }
+ if(function_exists('ImageCreateTrueColor')){
+ $new_img =ImageCreateTrueColor($new_x,$new_y);
+ } else {
+ $new_img =ImageCreate($new_x,$new_y);
+ }
+ if(function_exists('ImageCopyResampled')){
+ ImageCopyResampled($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y);
+ } else {
+ ImageCopyResized($new_img, $this->imageHandle, 0, 0, 0, 0, $new_x, $new_y, $this->img_x, $this->img_y);
+ }
+ $this->old_image = $this->imageHandle;
+ $this->imageHandle = $new_img;
+ $this->resized = true;
+
+ $this->new_x = $new_x;
+ $this->new_y = $new_y;
+ return true;
+ }
+
+ /**
+ * Crop the image
+ *
+ * @param int $crop_x left column of the image
+ * @param int $crop_y top row of the image
+ * @param int $crop_width new cropped image width
+ * @param int $crop_height new cropped image height
+ */
+ function crop($new_x, $new_y, $new_width, $new_height)
+ {
+ if(function_exists('ImageCreateTrueColor')){
+ $new_img =ImageCreateTrueColor($new_width,$new_height);
+ } else {
+ $new_img =ImageCreate($new_width,$new_height);
+ }
+ if(function_exists('ImageCopyResampled')){
+ ImageCopyResampled($new_img, $this->imageHandle, 0, 0, $new_x, $new_y,$new_width,$new_height,$new_width,$new_height);
+ } else {
+ ImageCopyResized($new_img, $this->imageHandle, 0, 0, $new_x, $new_y, $new_width,$new_height,$new_width,$new_height);
+ }
+ $this->old_image = $this->imageHandle;
+ $this->imageHandle = $new_img;
+ $this->resized = true;
+
+ $this->new_x = $new_x;
+ $this->new_y = $new_y;
+ return true;
+ }
+
+ /**
+ * Flip the image horizontally or vertically
+ *
+ * @param boolean $horizontal true if horizontal flip, vertical otherwise
+ */
+ function flip($horizontal)
+ {
+ if(!$horizontal) {
+ $this->rotate(180);
+ }
+
+ $width = imagesx($this->imageHandle);
+ $height = imagesy($this->imageHandle);
+
+ for ($j = 0; $j < $height; $j++) {
+ $left = 0;
+ $right = $width-1;
+
+
+ while ($left < $right) {
+ //echo " j:".$j." l:".$left." r:".$right."\n<br>";
+ $t = imagecolorat($this->imageHandle, $left, $j);
+ imagesetpixel($this->imageHandle, $left, $j, imagecolorat($this->imageHandle, $right, $j));
+ imagesetpixel($this->imageHandle, $right, $j, $t);
+ $left++; $right--;
+ }
+
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Adjust the image gamma
+ *
+ * @param float $outputgamma
+ *
+ * @return none
+ */
+ function gamma($outputgamma=1.0) {
+ ImageGammaCorrect($this->imageHandle, 1.0, $outputgamma);
+ }
+
+ /**
+ * Save the image file
+ *
+ * @param string $filename the name of the file to write to
+ * @param int $quality output DPI, default is 85
+ * @param string $types define the output format, default
+ * is the current used format
+ *
+ * @return none
+ */
+ function save($filename, $type = '', $quality = 85)
+ {
+ $type = $type==''? $this->type : $type;
+ $functionName = 'image' . $type;
+
+ if(function_exists($functionName))
+ {
+ $this->old_image = $this->imageHandle;
+ if($type=='jpeg')
+ $functionName($this->imageHandle, $filename, $quality);
+ else
+ $functionName($this->imageHandle, $filename);
+ $this->imageHandle = $this->old_image;
+ $this->resized = false;
+ }
+ } // End save
+
+
+ /**
+ * Display image without saving and lose changes
+ *
+ * @param string type (JPG,PNG...);
+ * @param int quality 75
+ *
+ * @return none
+ */
+ function display($type = '', $quality = 75)
+ {
+ if ($type != '') {
+ $this->type = $type;
+ }
+ $functionName = 'Image' . $this->type;
+ if(function_exists($functionName))
+ {
+ header('Content-type: image/' . strtolower($this->type));
+ $functionName($this->imageHandle, '', $quality);
+ $this->imageHandle = $this->old_image;
+ $this->resized = false;
+ ImageDestroy($this->old_image);
+ $this->free();
+ }
+ }
+
+ /**
+ * Destroy image handle
+ *
+ * @return none
+ */
+ function free()
+ {
+ if ($this->imageHandle){
+ ImageDestroy($this->imageHandle);
+ }
+ }
+
+} // End class ImageGD
+?>
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/IM.php
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/IM.php?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/IM.php (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/IM.php Sun Oct 8 12:53:13 2006
@@ -0,0 +1,235 @@
+<?php
+
+/***********************************************************************
+** Title.........: ImageMagick Driver
+** Version.......: 1.0
+** Author........: Xiang Wei ZHUO <we...@zhuo.org>
+** Filename......: IM.php
+** Last changed..: 30 Aug 2003
+** Notes.........: Orginal is from PEAR
+**/
+
+// +----------------------------------------------------------------------+
+// | PHP Version 4 |
+// +----------------------------------------------------------------------+
+// | Copyright (c) 1997-2002 The PHP Group |
+// +----------------------------------------------------------------------+
+// | This source file is subject to version 2.02 of the PHP license, |
+// | that is bundled with this package in the file LICENSE, and is |
+// | available at through the world-wide-web at |
+// | http://www.php.net/license/2_02.txt. |
+// | If you did not receive a copy of the PHP license and are unable to |
+// | obtain it through the world-wide-web, please send a note to |
+// | license@php.net so we can mail you a copy immediately. |
+// +----------------------------------------------------------------------+
+// | Authors: Peter Bowyer <pe...@mapledesign.co.uk> |
+// +----------------------------------------------------------------------+
+//
+// $Id: IM.php 27 2004-04-01 08:31:57Z Wei Zhuo $
+//
+// Image Transformation interface using command line ImageMagick
+//
+
+require_once "Transform.php";
+
+Class Image_Transform_Driver_IM extends Image_Transform
+{
+ /**
+ * associative array commands to be executed
+ * @var array
+ */
+ var $command = array();
+
+ /**
+ *
+ *
+ */
+ function Image_Transform_Driver_IM()
+ {
+ return true;
+ } // End Image_IM
+
+ /**
+ * Load image
+ *
+ * @param string filename
+ *
+ * @return mixed none or a PEAR error object on error
+ * @see PEAR::isError()
+ */
+ function load($image)
+ {
+
+ $this->uid = md5($_SERVER['REMOTE_ADDR']);
+ /*if (!file_exists($image)) {
+ return PEAR::raiseError('The image file ' . $image . ' does\'t exist', true);
+ }*/
+ $this->image = $image;
+ $this->_get_image_details($image);
+ } // End load
+
+ /**
+ * Resize Action
+ *
+ * @param int new_x new width
+ * @param int new_y new height
+ *
+ * @return none
+ * @see PEAR::isError()
+ */
+ function _resize($new_x, $new_y)
+ {
+ /*if (isset($this->command['resize'])) {
+ return PEAR::raiseError("You cannot scale or resize an image more than once without calling save or display", true);
+ }*/
+ $this->command['resize'] = "-geometry ${new_x}x${new_y}!";
+
+ $this->new_x = $new_x;
+ $this->new_y = $new_y;
+ } // End resize
+
+ /**
+ * Crop the image
+ *
+ * @param int $crop_x left column of the image
+ * @param int $crop_y top row of the image
+ * @param int $crop_width new cropped image width
+ * @param int $crop_height new cropped image height
+ */
+ function crop($crop_x, $crop_y, $crop_width, $crop_height)
+ {
+ $this->command['crop'] = "-crop {$crop_width}x{$crop_height}+{$crop_x}+{$crop_y}";
+ }
+
+ /**
+ * Flip the image horizontally or vertically
+ *
+ * @param boolean $horizontal true if horizontal flip, vertical otherwise
+ */
+ function flip($horizontal)
+ {
+ if($horizontal)
+ $this->command['flop'] = "-flop";
+ else
+ $this->command['flip'] = "-flip";
+ }
+ /**
+ * rotate
+ *
+ * @param int angle rotation angle
+ * @param array options no option allowed
+ *
+ */
+ function rotate($angle, $options=null)
+ {
+ if ('-' == $angle{0}) {
+ $angle = 360 - substr($angle, 1);
+ }
+ $this->command['rotate'] = "-rotate $angle";
+ } // End rotate
+
+ /**
+ * addText
+ *
+ * @param array options Array contains options
+ * array(
+ * 'text' The string to draw
+ * 'x' Horizontal position
+ * 'y' Vertical Position
+ * 'Color' Font color
+ * 'font' Font to be used
+ * 'size' Size of the fonts in pixel
+ * 'resize_first' Tell if the image has to be resized
+ * before drawing the text
+ * )
+ *
+ * @return none
+ * @see PEAR::isError()
+ */
+ function addText($params)
+ {
+ $default_params = array(
+ 'text' => 'This is Text',
+ 'x' => 10,
+ 'y' => 20,
+ 'color' => 'red',
+ 'font' => 'Arial.ttf',
+ 'resize_first' => false // Carry out the scaling of the image before annotation?
+ );
+ $params = array_merge($default_params, $params);
+ extract($params);
+ if (true === $resize_first) {
+ // Set the key so that this will be the last item in the array
+ $key = 'ztext';
+ } else {
+ $key = 'text';
+ }
+ $this->command[$key] = "-font $font -fill $color -draw 'text $x,$y \"$text\"'";
+ // Producing error: gs: not found gs: not found convert: Postscript delegate failed [No such file or directory].
+ } // End addText
+
+ /**
+ * Adjust the image gamma
+ *
+ * @param float $outputgamma
+ *
+ * @return none
+ */
+ function gamma($outputgamma=1.0) {
+ $this->command['gamma'] = "-gamma $outputgamma";
+ }
+
+ /**
+ * Save the image file
+ *
+ * @param string $filename the name of the file to write to
+ * @param quality $quality image dpi, default=75
+ * @param string $type (JPG,PNG...)
+ *
+ * @return none
+ */
+ function save($filename, $type='', $quality = 85)
+ {
+ $type == '' ? $this->type : $type;
+ $cmd = '' . IMAGE_TRANSFORM_LIB_PATH . 'convert ';
+ $cmd .= implode(' ', $this->command) . " -quality $quality ";
+ $cmd .= '"'.($this->image) . '" "' . ($filename) . '"';
+
+ //$cmd = str_replace('/', '\\', $cmd);
+ //echo($cmd.'<br>');
+ exec($cmd,$retval);
+ //error_log('IM '.print_r($retval,true));
+ } // End save
+
+ /**
+ * Display image without saving and lose changes
+ *
+ * @param string type (JPG,PNG...);
+ * @param int quality 75
+ *
+ * @return none
+ */
+ function display($type = '', $quality = 75)
+ {
+ if ($type == '') {
+ header('Content-type: image/' . $this->type);
+ passthru(IMAGE_TRANSFORM_LIB_PATH . 'convert ' . implode(' ', $this->command) . " -quality $quality " . escapeshellarg($this->image) . ' ' . strtoupper($this->type) . ":-");
+ } else {
+ header('Content-type: image/' . $type);
+ passthru(IMAGE_TRANSFORM_LIB_PATH . 'convert ' . implode(' ', $this->command) . " -quality $quality " . escapeshellarg($this->image) . ' ' . strtoupper($type) . ":-");
+ }
+ }
+
+
+ /**
+ * Destroy image handle
+ *
+ * @return none
+ */
+ function free()
+ {
+ return true;
+ }
+
+} // End class ImageIM
+?>
Added: incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/ImageEditor.php
URL: http://svn.apache.org/viewvc/incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/ImageEditor.php?view=auto&rev=454197
==============================================================================
--- incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/ImageEditor.php (added)
+++ incubator/roller/trunk/web/roller-ui/authoring/editors/xinha/plugins/ImageManager/Classes/ImageEditor.php Sun Oct 8 12:53:13 2006
@@ -0,0 +1,449 @@
+<?php
+/**
+ * Image Editor. Editing tools, crop, rotate, scale and save.
+ * @author $Author: Wei Zhuo $
+ * @version $Id: ImageEditor.php 27 2004-04-01 08:31:57Z Wei Zhuo $
+ * @package ImageManager
+ */
+
+require_once('Transform.php');
+
+/**
+ * Handles the basic image editing capbabilities.
+ * @author $Author: Wei Zhuo $
+ * @version $Id: ImageEditor.php 27 2004-04-01 08:31:57Z Wei Zhuo $
+ * @package ImageManager
+ * @subpackage Editor
+ */
+class ImageEditor
+{
+ /**
+ * ImageManager instance.
+ */
+ var $manager;
+
+ /**
+ * user based on IP address
+ */
+ var $_uid;
+
+ /**
+ * tmp file storage time.
+ */
+ var $lapse_time =900; //15 mins
+
+ var $filesaved = 0;
+
+ /**
+ * Create a new ImageEditor instance. Editing requires a
+ * tmp file, which is saved in the current directory where the
+ * image is edited. The tmp file is assigned by md5 hash of the
+ * user IP address. This hashed is used as an ID for cleaning up
+ * the tmp files. In addition, any tmp files older than the
+ * the specified period will be deleted.
+ * @param ImageManager $manager the image manager, we need this
+ * for some file and path handling functions.
+ */
+ function ImageEditor($manager)
+ {
+ $this->manager = $manager;
+ $this->_uid = md5($_SERVER['REMOTE_ADDR']);
+ }
+
+ /**
+ * Did we save a file?
+ * @return int 1 if the file was saved sucessfully,
+ * 0 no save operation, -1 file save error.
+ */
+ function isFileSaved()
+ {
+ Return $this->filesaved;
+ }
+
+ /**
+ * Process the image, if not action, just display the image.
+ * @return array with image information, empty array if not an image.
+ * <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
+ * 'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
+ */
+ function processImage()
+ {
+ if(isset($_GET['img']))
+ $relative = rawurldecode($_GET['img']);
+ else
+ Return array();
+
+ //$relative = '/Series2004NoteFront.jpg';
+
+ $imgURL = $this->manager->getFileURL($relative);
+ $fullpath = $this->manager->getFullPath($relative);
+
+ $imgInfo = @getImageSize($fullpath);
+ if(!is_array($imgInfo))
+ Return array();
+
+ $action = $this->getAction();
+
+ if(!is_null($action))
+ {
+ $image = $this->processAction($action, $relative, $fullpath);
+ }
+ else
+ {
+ $image['src'] = $imgURL;
+ $image['dimensions'] = $imgInfo[3];
+ $image['file'] = $relative;
+ $image['fullpath'] = $fullpath;
+ }
+
+ Return $image;
+ }
+
+ /**
+ * Process the actions, crop, scale(resize), rotate, flip, and save.
+ * When ever an action is performed, the result is save into a
+ * temporary image file, see createUnique on the filename specs.
+ * It does not return the saved file, alway returning the tmp file.
+ * @param string $action, should be 'crop', 'scale', 'rotate','flip', or 'save'
+ * @param string $relative the relative image filename
+ * @param string $fullpath the fullpath to the image file
+ * @return array with image information
+ * <code>array('src'=>'url of the image', 'dimensions'=>'width="xx" height="yy"',
+ * 'file'=>'image file, relative', 'fullpath'=>'full path to the image');</code>
+ */
+ function processAction($action, $relative, $fullpath)
+ {
+ $params = '';
+
+ if(isset($_GET['params']))
+ $params = $_GET['params'];
+
+ $values = explode(',',$params,4);
+ $saveFile = $this->getSaveFileName($values[0]);
+
+ $img = Image_Transform::factory(IMAGE_CLASS);
+ $img->load($fullpath);
+
+ switch ($action)
+ {
+ case 'crop':
+ $img->crop(intval($values[0]),intval($values[1]),
+ intval($values[2]),intval($values[3]));
+ break;
+ case 'scale':
+ $img->resize(intval($values[0]),intval($values[1]));
+ break;
+ case 'rotate':
+ $img->rotate(floatval($values[0]));
+ break;
+ case 'flip':
+ if ($values[0] == 'hoz')
+ $img->flip(true);
+ else if($values[0] == 'ver')
+ $img->flip(false);
+ break;
+ case 'save':
+ if(!is_null($saveFile))
+ {
+ $quality = intval($values[1]);
+ if($quality <0) $quality = 85;
+ $newSaveFile = $this->makeRelative($relative, $saveFile);
+ $newSaveFile = $this->getUniqueFilename($newSaveFile);
+
+ //get unique filename just returns the filename, so
+ //we need to make the relative path once more.
+ $newSaveFile = $this->makeRelative($relative, $newSaveFile);
+ $image['saveFile'] = $newSaveFile;
+ $newSaveFullpath = $this->manager->getFullPath($newSaveFile);
+ $img->save($newSaveFullpath, $values[0], $quality);
+ if(is_file($newSaveFullpath))
+ $this->filesaved = 1;
+ else
+ $this->filesaved = -1;
+ }
+ break;
+ }
+
+ //create the tmp image file
+ $filename = $this->createUnique($fullpath);
+ $newRelative = $this->makeRelative($relative, $filename);
+ $newFullpath = $this->manager->getFullPath($newRelative);
+ $newURL = $this->manager->getFileURL($newRelative);
+
+ //save the file.
+ $img->save($newFullpath);
+ $img->free();
+
+ //get the image information
+ $imgInfo = @getimagesize($newFullpath);
+
+ $image['src'] = $newURL;
+ $image['width'] = $imgInfo[0];
+ $image['height'] = $imgInfo[1];
+ $image['dimensions'] = $imgInfo[3];
+ $image['file'] = $newRelative;
+ $image['fullpath'] = $newFullpath;
+
+ Return $image;
+
+ }
+
+ /**
+ * Get the file name base on the save name
+ * and the save type.
+ * @param string $type image type, 'jpeg', 'png', or 'gif'
+ * @return string the filename according to save type
+ */
+ function getSaveFileName($type)
+ {
+ if(!isset($_GET['file']))
+ Return null;
+
+ $filename = Files::escape(rawurldecode($_GET['file']));
+ $index = strrpos($filename,'.');
+ $base = substr($filename,0,$index);
+ $ext = strtolower(substr($filename,$index+1,strlen($filename)));
+
+ if($type == 'jpeg' && !($ext=='jpeg' || $ext=='jpg'))
+ {
+ Return $base.'.jpeg';
+ }
+ if($type=='png' && $ext != 'png')
+ Return $base.'.png';
+ if($type=='gif' && $ext != 'gif')
+ Return $base.'.gif';
+
+ Return $filename;
+ }
+
+ /**
+ * Get the default save file name, used by editor.php.
+ * @return string a suggestive filename, this should be unique
+ */
+ function getDefaultSaveFile()
+ {
+ if(isset($_GET['img']))
+ $relative = rawurldecode($_GET['img']);
+ else
+ Return null;
+
+ Return $this->getUniqueFilename($relative);
+ }
+
+ /**
+ * Get a unique filename. If the file exists, the filename
+ * base is appended with an increasing integer.
+ * @param string $relative the relative filename to the base_dir
+ * @return string a unique filename in the current path
+ */
+ function getUniqueFilename($relative)
+ {
+ $fullpath = $this->manager->getFullPath($relative);
+
+ $pathinfo = pathinfo($fullpath);
+
+ $path = Files::fixPath($pathinfo['dirname']);
+ $file = Files::escape($pathinfo['basename']);
+
+ $filename = $file;
+
+ $dotIndex = strrpos($file, '.');
+ $ext = '';
+
+ if(is_int($dotIndex))
+ {
+ $ext = substr($file, $dotIndex);
+ $base = substr($file, 0, $dotIndex);
+ }
+
+ $counter = 0;
+ while(is_file($path.$filename))
+ {
+ $counter++;
+ $filename = $base.'_'.$counter.$ext;
+ }
+
+ Return $filename;
+
+ }
+
+ /**
+ * Specifiy the original relative path, a new filename
+ * and return the new filename with relative path.
+ * i.e. $pathA (-filename) + $file
+ * @param string $pathA the relative file
+ * @param string $file the new filename
+ * @return string relative path with the new filename
+ */
+ function makeRelative($pathA, $file)
+ {
+ $index = strrpos($pathA,'/');
+ if(!is_int($index))
+ Return $file;
+
+ $path = substr($pathA, 0, $index);
+ Return Files::fixPath($path).$file;
+ }
+
+ /**
+ * Get the action GET parameter
+ * @return string action parameter
+ */
+ function getAction()
+ {
+ $action = null;
+ if(isset($_GET['action']))
+ $action = $_GET['action'];
+ Return $action;
+ }
+
+ /**
+ * Generate a unique string based on md5(microtime()).
+ * Well not so uniqe, as it is limited to 6 characters
+ * @return string unique string.
+ */
+ function uniqueStr()
+ {
+ return substr(md5(microtime()),0,6);
+ }
+
+ /**
+ * Create unique tmp image file name.
+ * The filename is based on the tmp file prefix
+ * specified in config.inc.php plus
+ * the UID (basically a md5 of the remote IP)
+ * and some random 6 character string.
+ * This function also calls to clean up the tmp files.
+ * @param string $file the fullpath to a file
+ * @return string a unique filename for that path
+ * NOTE: it only returns the filename, path no included.
+ */
+ function createUnique($file)
+ {
+ $pathinfo = pathinfo($file);
+ $path = Files::fixPath($pathinfo['dirname']);
+ $imgType = $this->getImageType($file);
+
+ $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
+
+ //make sure the the unique temp file does not exists
+ while (file_exists($path.$unique_str))
+ {
+ $unique_str = $this->manager->getTmpPrefix().$this->_uid.'_'.$this->uniqueStr().".".$imgType;
+ }
+
+ $this->cleanUp($path,$pathinfo['basename']);
+
+ Return $unique_str;
+ }
+
+ /**
+ * Delete any tmp image files.
+ * @param string $path the full path
+ * where the clean should take place.
+ */
+ function cleanUp($path,$file)
+ {
+ $path = Files::fixPath($path);
+
+ if(!is_dir($path))
+ Return false;
+
+ $d = @dir($path);
+
+ $tmp = $this->manager->getTmpPrefix();
+ $tmpLen = strlen($tmp);
+
+ $prefix = $tmp.$this->_uid;
+ $len = strlen($prefix);
+
+ while (false !== ($entry = $d->read()))
+ {
+ //echo $entry."<br>";
+ if(is_file($path.$entry) && $this->manager->isTmpFile($entry))
+ {
+ if(substr($entry,0,$len)==$prefix && $entry != $file)
+ Files::delFile($path.$entry);
+ else if(substr($entry,0,$tmpLen)==$tmp && $entry != $file)
+ {
+ if(filemtime($path.$entry)+$this->lapse_time < time())
+ Files::delFile($path.$entry);
+ }
+ }
+ }
+ $d->close();
+ }
+
+ /**
+ * Get the image type base on an image file.
+ * @param string $file the full path to the image file.
+ * @return string of either 'gif', 'jpeg', 'png' or 'bmp'
+ * otherwise it will return null.
+ */
+ function getImageType($file)
+ {
+ $imageInfo = @getImageSize($file);
+
+ if(!is_array($imageInfo))
+ Return null;
+
+ switch($imageInfo[2])
+ {
+ case 1:
+ Return 'gif';
+ case 2:
+ Return 'jpeg';
+ case 3:
+ Return 'png';
+ case 6:
+ Return 'bmp';
+ }
+
+ Return null;
+ }
+
+ /**
+ * Check if the specified image can be edit by GD
+ * mainly to check that GD can read and save GIFs
+ * @return int 0 if it is not a GIF file, 1 is GIF is editable, -1 if not editable.
+ */
+ function isGDEditable()
+ {
+ if(isset($_GET['img']))
+ $relative = rawurldecode($_GET['img']);
+ else
+ Return 0;
+ if(IMAGE_CLASS != 'GD')
+ Return 0;
+
+ $fullpath = $this->manager->getFullPath($relative);
+
+ $type = $this->getImageType($fullpath);
+ if($type != 'gif')
+ Return 0;
+
+ if(function_exists('ImageCreateFrom'+$type)
+ && function_exists('image'+$type))
+ Return 1;
+ else
+ Return -1;
+ }
+
+ /**
+ * Check if GIF can be edit by GD.
+ * @return int 0 if it is not using the GD library, 1 is GIF is editable, -1 if not editable.
+ */
+ function isGDGIFAble()
+ {
+ if(IMAGE_CLASS != 'GD')
+ Return 0;
+
+ if(function_exists('ImageCreateFromGif')
+ && function_exists('imagegif'))
+ Return 1;
+ else
+ Return -1;
+ }
+}
+
+?>