Version Description
- Maintenace update: Greeting messages are now saved properly.
- Add more language options in customization page.
- Using new Zopim async embed script: improve page's load time and do not block page's rendering anymore.
Download this release
Release Info
Developer | bencxr |
Plugin | ![]() |
Version | 1.1.0 |
Comparing to | |
See all releases |
Code changes from version 1.0.7 to 1.1.0
- customizewidget.php +5 -6
- readme.txt +7 -2
- trunk/JSON.php +807 -0
- trunk/ZeroClipboard.js +302 -0
- trunk/ZeroClipboard.swf +0 -0
- trunk/accountconfig.php +297 -0
- trunk/customizewidget.php +468 -0
- trunk/imintegration.php +140 -0
- trunk/readme.txt +154 -0
- trunk/screenshot-1.png +0 -0
- trunk/screenshot-2.png +0 -0
- trunk/screenshot-3.png +0 -0
- trunk/screenshot-4.png +0 -0
- trunk/zopim.php +298 -0
- zopim.php +26 -12
customizewidget.php
CHANGED
@@ -142,6 +142,8 @@ function zopim_customize_widget() {
|
|
142 |
var el = document.getElementById(inputs[i]);
|
143 |
el.disabled = isDisabled;
|
144 |
}
|
|
|
|
|
145 |
}
|
146 |
|
147 |
var timer;
|
@@ -340,7 +342,7 @@ line-height:21px;
|
|
340 |
</div>
|
341 |
|
342 |
<?php
|
343 |
-
|
344 |
$useGreetings = true;
|
345 |
} else {
|
346 |
$useGreetings = false;
|
@@ -354,7 +356,7 @@ line-height:21px;
|
|
354 |
<tr>
|
355 |
<td colspan="2">
|
356 |
<input type="checkbox" id="zopimUseGreetings" onchange="greetingsChanged()" value="zopimUseGreetings" name="zopimUseGreetings"
|
357 |
-
<?php if (
|
358 |
Use these greeting messages
|
359 |
</td>
|
360 |
</tr>
|
@@ -450,16 +452,13 @@ function generate_options($options, $current) {
|
|
450 |
}
|
451 |
|
452 |
function get_languages() {
|
453 |
-
|
454 |
-
$langjson = '{"--":" - Auto Detect - ","ar":"Arabic","bg":"Bulgarian","cs":"Czech","da":"Danish","de":"German","en":"English","es":"Spanish; Castilian","fa":"Persian","fo":"Faroese","fr":"French","he":"Hebrew","hr":"Croatian","id":"Indonesian","it":"Italian","ja":"Japanese","ko":"Korean","ms":"Malay","nb":"Norwegian Bokmal","nl":"Dutch; Flemish","pl":"Polish","pt":"Portuguese","ru":"Russian","sk":"Slovak","sl":"Slovenian","sv":"Swedish","th":"Thai","tr":"Turkish","ur":"Urdu","vi":"Vietnamese","zh_CN":"Chinese (China)"}hihi{"--":" - Auto Detect - ","ar":"Arabic","bg":"Bulgarian","cs":"Czech","da":"Danish","de":"German","en":"English","es":"Spanish; Castilian","fa":"Persian","fo":"Faroese","fr":"French","he":"Hebrew","hr":"Croatian","id":"Indonesian","it":"Italian","ja":"Japanese","ko":"Korean","ms":"Malay","nb":"Norwegian Bokmal","nl":"Dutch; Flemish","pl":"Polish","pt":"Portuguese","ru":"Russian","sk":"Slovak","sl":"Slovenian","sv":"Swedish","th":"Thai","tr":"Turkish","ur":"Urdu","vi":"Vietnamese","zh_CN":"Chinese (China)"}';
|
455 |
|
456 |
return json_to_array($langjson);
|
457 |
}
|
458 |
|
459 |
function update_checkbox($fieldname) {
|
460 |
if (isset($_POST["$fieldname"]) && $_POST["$fieldname"] != "") {
|
461 |
-
echo $fieldname." : ".$_POST["$fieldname"];
|
462 |
-
|
463 |
update_option($fieldname, $_POST["$fieldname"]);
|
464 |
} else {
|
465 |
update_option($fieldname, "disabled");
|
142 |
var el = document.getElementById(inputs[i]);
|
143 |
el.disabled = isDisabled;
|
144 |
}
|
145 |
+
|
146 |
+
updateWidget();
|
147 |
}
|
148 |
|
149 |
var timer;
|
342 |
</div>
|
343 |
|
344 |
<?php
|
345 |
+
if (get_option('zopimUseGreetings') && get_option('zopimUseGreetings')!="disabled") {
|
346 |
$useGreetings = true;
|
347 |
} else {
|
348 |
$useGreetings = false;
|
356 |
<tr>
|
357 |
<td colspan="2">
|
358 |
<input type="checkbox" id="zopimUseGreetings" onchange="greetingsChanged()" value="zopimUseGreetings" name="zopimUseGreetings"
|
359 |
+
<?php if ($useGreetings) { echo "checked='checked'"; } ?>/>
|
360 |
Use these greeting messages
|
361 |
</td>
|
362 |
</tr>
|
452 |
}
|
453 |
|
454 |
function get_languages() {
|
455 |
+
$langjson = '{"--":" - Auto Detect - ","ar":"Arabic","bn":"Bengali","bg":"Bulgarian","zh_CN":"Chinese (China)","zh_TW":"Chinese (Taiwan)","hr":"Croatian","cs":"Czech","da":"Danish","nl":"Dutch; Flemish","et":"Estonian","fo":"Faroese","fi":"Finnish","fr":"French","ka":"Georgian","de":"German","el":"Greek","he":"Hebrew","hu":"Hungarian","is":"Icelandic","id":"Indonesian","it":"Italian","ja":"Japanese","ko":"Korean","ku":"Kurdish","lv":"Latvian","lt":"Lithuanian","mk":"Macedonian","ms":"Malay","nb":"Norwegian Bokmal","fa":"Persian","pl":"Polish","pt":"Portuguese","pt_BR":"Portuguese (Brazil)","ro":"Romanian","ru":"Russian","sr":"Serbian","sk":"Slovak","sl":"Slovenian","es":"Spanish; Castilian","sv":"Swedish","th":"Thai","tr":"Turkish","uk":"Ukrainian","ur":"Urdu","vi":"Vietnamese"}';
|
|
|
456 |
|
457 |
return json_to_array($langjson);
|
458 |
}
|
459 |
|
460 |
function update_checkbox($fieldname) {
|
461 |
if (isset($_POST["$fieldname"]) && $_POST["$fieldname"] != "") {
|
|
|
|
|
462 |
update_option($fieldname, $_POST["$fieldname"]);
|
463 |
} else {
|
464 |
update_option($fieldname, "disabled");
|
readme.txt
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
Contributors: bencxr
|
3 |
Tags: widget, plugin, sidebar, page, admin, enhancement, livechat, chat, widget
|
4 |
Requires at least: 2.7
|
5 |
-
Tested up to: 3.
|
6 |
-
Stable tag: 1.0
|
7 |
|
8 |
Zopim is an award winning facebook-like chatbar built for websites. It connects website owners and visitors together via a cross-browser platform.
|
9 |
|
@@ -44,6 +44,11 @@ Zopim shows up as a chatbar docked to the bottom of your website. Visitors chat
|
|
44 |
|
45 |
|
46 |
== Changelog ==
|
|
|
|
|
|
|
|
|
|
|
47 |
= 1.0.7 =
|
48 |
* Maintenance update: Remove phased out "middle left", "middle right" positions
|
49 |
* Add options to let user decides hiding of chat bubble, no longer force show/hide
|
2 |
Contributors: bencxr
|
3 |
Tags: widget, plugin, sidebar, page, admin, enhancement, livechat, chat, widget
|
4 |
Requires at least: 2.7
|
5 |
+
Tested up to: 3.1.1
|
6 |
+
Stable tag: 1.1.0
|
7 |
|
8 |
Zopim is an award winning facebook-like chatbar built for websites. It connects website owners and visitors together via a cross-browser platform.
|
9 |
|
44 |
|
45 |
|
46 |
== Changelog ==
|
47 |
+
= 1.1.0 =
|
48 |
+
* Maintenace update: Greeting messages are now saved properly.
|
49 |
+
* Add more language options in customization page.
|
50 |
+
* Using new Zopim async embed script: improve page's load time and do not block page's rendering anymore.
|
51 |
+
|
52 |
= 1.0.7 =
|
53 |
* Maintenance update: Remove phased out "middle left", "middle right" positions
|
54 |
* Add options to let user decides hiding of chat bubble, no longer force show/hide
|
trunk/JSON.php
ADDED
@@ -0,0 +1,807 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if(!class_exists('Services_JSON')):
|
3 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Converts to and from JSON format.
|
7 |
+
*
|
8 |
+
* JSON (JavaScript Object Notation) is a lightweight data-interchange
|
9 |
+
* format. It is easy for humans to read and write. It is easy for machines
|
10 |
+
* to parse and generate. It is based on a subset of the JavaScript
|
11 |
+
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
|
12 |
+
* This feature can also be found in Python. JSON is a text format that is
|
13 |
+
* completely language independent but uses conventions that are familiar
|
14 |
+
* to programmers of the C-family of languages, including C, C++, C#, Java,
|
15 |
+
* JavaScript, Perl, TCL, and many others. These properties make JSON an
|
16 |
+
* ideal data-interchange language.
|
17 |
+
*
|
18 |
+
* This package provides a simple encoder and decoder for JSON notation. It
|
19 |
+
* is intended for use with client-side Javascript applications that make
|
20 |
+
* use of HTTPRequest to perform server communication functions - data can
|
21 |
+
* be encoded into JSON notation for use in a client-side javascript, or
|
22 |
+
* decoded from incoming Javascript requests. JSON format is native to
|
23 |
+
* Javascript, and can be directly eval()'ed with no further parsing
|
24 |
+
* overhead
|
25 |
+
*
|
26 |
+
* All strings should be in ASCII or UTF-8 format!
|
27 |
+
*
|
28 |
+
* LICENSE: Redistribution and use in source and binary forms, with or
|
29 |
+
* without modification, are permitted provided that the following
|
30 |
+
* conditions are met: Redistributions of source code must retain the
|
31 |
+
* above copyright notice, this list of conditions and the following
|
32 |
+
* disclaimer. Redistributions in binary form must reproduce the above
|
33 |
+
* copyright notice, this list of conditions and the following disclaimer
|
34 |
+
* in the documentation and/or other materials provided with the
|
35 |
+
* distribution.
|
36 |
+
*
|
37 |
+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
38 |
+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
39 |
+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
40 |
+
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
41 |
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
42 |
+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
43 |
+
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
44 |
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
45 |
+
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
46 |
+
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
47 |
+
* DAMAGE.
|
48 |
+
*
|
49 |
+
* @category
|
50 |
+
* @package Services_JSON
|
51 |
+
* @author Michal Migurski <mike-json@teczno.com>
|
52 |
+
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
|
53 |
+
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
|
54 |
+
* @copyright 2005 Michal Migurski
|
55 |
+
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
|
56 |
+
* @license http://www.opensource.org/licenses/bsd-license.php
|
57 |
+
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
|
58 |
+
*/
|
59 |
+
|
60 |
+
/**
|
61 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
62 |
+
*/
|
63 |
+
define('SERVICES_JSON_SLICE', 1);
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
67 |
+
*/
|
68 |
+
define('SERVICES_JSON_IN_STR', 2);
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
72 |
+
*/
|
73 |
+
define('SERVICES_JSON_IN_ARR', 3);
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
77 |
+
*/
|
78 |
+
define('SERVICES_JSON_IN_OBJ', 4);
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
82 |
+
*/
|
83 |
+
define('SERVICES_JSON_IN_CMT', 5);
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Behavior switch for Services_JSON::decode()
|
87 |
+
*/
|
88 |
+
define('SERVICES_JSON_LOOSE_TYPE', 16);
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Behavior switch for Services_JSON::decode()
|
92 |
+
*/
|
93 |
+
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Converts to and from JSON format.
|
97 |
+
*
|
98 |
+
* Brief example of use:
|
99 |
+
*
|
100 |
+
* <code>
|
101 |
+
* // create a new instance of Services_JSON
|
102 |
+
* $json = new Services_JSON();
|
103 |
+
*
|
104 |
+
* // convert a complexe value to JSON notation, and send it to the browser
|
105 |
+
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
|
106 |
+
* $output = $json->encode($value);
|
107 |
+
*
|
108 |
+
* print($output);
|
109 |
+
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
|
110 |
+
*
|
111 |
+
* // accept incoming POST data, assumed to be in JSON notation
|
112 |
+
* $input = file_get_contents('php://input', 1000000);
|
113 |
+
* $value = $json->decode($input);
|
114 |
+
* </code>
|
115 |
+
*/
|
116 |
+
class Services_JSON
|
117 |
+
{
|
118 |
+
/**
|
119 |
+
* constructs a new JSON instance
|
120 |
+
*
|
121 |
+
* @param int $use object behavior flags; combine with boolean-OR
|
122 |
+
*
|
123 |
+
* possible values:
|
124 |
+
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
125 |
+
* "{...}" syntax creates associative arrays
|
126 |
+
* instead of objects in decode().
|
127 |
+
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
128 |
+
* Values which can't be encoded (e.g. resources)
|
129 |
+
* appear as NULL instead of throwing errors.
|
130 |
+
* By default, a deeply-nested resource will
|
131 |
+
* bubble up with an error, so all return values
|
132 |
+
* from encode() should be checked with isError()
|
133 |
+
*/
|
134 |
+
function Services_JSON($use = 0)
|
135 |
+
{
|
136 |
+
$this->use = $use;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* convert a string from one UTF-16 char to one UTF-8 char
|
141 |
+
*
|
142 |
+
* Normally should be handled by mb_convert_encoding, but
|
143 |
+
* provides a slower PHP-only method for installations
|
144 |
+
* that lack the multibye string extension.
|
145 |
+
*
|
146 |
+
* @param string $utf16 UTF-16 character
|
147 |
+
* @return string UTF-8 character
|
148 |
+
* @access private
|
149 |
+
*/
|
150 |
+
function utf162utf8($utf16)
|
151 |
+
{
|
152 |
+
// oh please oh please oh please oh please oh please
|
153 |
+
if(function_exists('mb_convert_encoding')) {
|
154 |
+
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
155 |
+
}
|
156 |
+
|
157 |
+
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
|
158 |
+
|
159 |
+
switch(true) {
|
160 |
+
case ((0x7F & $bytes) == $bytes):
|
161 |
+
// this case should never be reached, because we are in ASCII range
|
162 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
163 |
+
return chr(0x7F & $bytes);
|
164 |
+
|
165 |
+
case (0x07FF & $bytes) == $bytes:
|
166 |
+
// return a 2-byte UTF-8 character
|
167 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
168 |
+
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
169 |
+
. chr(0x80 | ($bytes & 0x3F));
|
170 |
+
|
171 |
+
case (0xFFFF & $bytes) == $bytes:
|
172 |
+
// return a 3-byte UTF-8 character
|
173 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
174 |
+
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
175 |
+
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
176 |
+
. chr(0x80 | ($bytes & 0x3F));
|
177 |
+
}
|
178 |
+
|
179 |
+
// ignoring UTF-32 for now, sorry
|
180 |
+
return '';
|
181 |
+
}
|
182 |
+
|
183 |
+
/**
|
184 |
+
* convert a string from one UTF-8 char to one UTF-16 char
|
185 |
+
*
|
186 |
+
* Normally should be handled by mb_convert_encoding, but
|
187 |
+
* provides a slower PHP-only method for installations
|
188 |
+
* that lack the multibye string extension.
|
189 |
+
*
|
190 |
+
* @param string $utf8 UTF-8 character
|
191 |
+
* @return string UTF-16 character
|
192 |
+
* @access private
|
193 |
+
*/
|
194 |
+
function utf82utf16($utf8)
|
195 |
+
{
|
196 |
+
// oh please oh please oh please oh please oh please
|
197 |
+
if(function_exists('mb_convert_encoding')) {
|
198 |
+
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
199 |
+
}
|
200 |
+
|
201 |
+
switch(strlen($utf8)) {
|
202 |
+
case 1:
|
203 |
+
// this case should never be reached, because we are in ASCII range
|
204 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
205 |
+
return $utf8;
|
206 |
+
|
207 |
+
case 2:
|
208 |
+
// return a UTF-16 character from a 2-byte UTF-8 char
|
209 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
210 |
+
return chr(0x07 & (ord($utf8{0}) >> 2))
|
211 |
+
. chr((0xC0 & (ord($utf8{0}) << 6))
|
212 |
+
| (0x3F & ord($utf8{1})));
|
213 |
+
|
214 |
+
case 3:
|
215 |
+
// return a UTF-16 character from a 3-byte UTF-8 char
|
216 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
217 |
+
return chr((0xF0 & (ord($utf8{0}) << 4))
|
218 |
+
| (0x0F & (ord($utf8{1}) >> 2)))
|
219 |
+
. chr((0xC0 & (ord($utf8{1}) << 6))
|
220 |
+
| (0x7F & ord($utf8{2})));
|
221 |
+
}
|
222 |
+
|
223 |
+
// ignoring UTF-32 for now, sorry
|
224 |
+
return '';
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* encodes an arbitrary variable into JSON format
|
229 |
+
*
|
230 |
+
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
231 |
+
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
232 |
+
* if var is a strng, note that encode() always expects it
|
233 |
+
* to be in ASCII or UTF-8 format!
|
234 |
+
*
|
235 |
+
* @return mixed JSON string representation of input var or an error if a problem occurs
|
236 |
+
* @access public
|
237 |
+
*/
|
238 |
+
function encode($var)
|
239 |
+
{
|
240 |
+
switch (gettype($var)) {
|
241 |
+
case 'boolean':
|
242 |
+
return $var ? 'true' : 'false';
|
243 |
+
|
244 |
+
case 'NULL':
|
245 |
+
return 'null';
|
246 |
+
|
247 |
+
case 'integer':
|
248 |
+
return (int) $var;
|
249 |
+
|
250 |
+
case 'double':
|
251 |
+
case 'float':
|
252 |
+
return (float) $var;
|
253 |
+
|
254 |
+
case 'string':
|
255 |
+
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
256 |
+
$ascii = '';
|
257 |
+
$strlen_var = strlen($var);
|
258 |
+
|
259 |
+
/*
|
260 |
+
* Iterate over every character in the string,
|
261 |
+
* escaping with a slash or encoding to UTF-8 where necessary
|
262 |
+
*/
|
263 |
+
for ($c = 0; $c < $strlen_var; ++$c) {
|
264 |
+
|
265 |
+
$ord_var_c = ord($var{$c});
|
266 |
+
|
267 |
+
switch (true) {
|
268 |
+
case $ord_var_c == 0x08:
|
269 |
+
$ascii .= '\b';
|
270 |
+
break;
|
271 |
+
case $ord_var_c == 0x09:
|
272 |
+
$ascii .= '\t';
|
273 |
+
break;
|
274 |
+
case $ord_var_c == 0x0A:
|
275 |
+
$ascii .= '\n';
|
276 |
+
break;
|
277 |
+
case $ord_var_c == 0x0C:
|
278 |
+
$ascii .= '\f';
|
279 |
+
break;
|
280 |
+
case $ord_var_c == 0x0D:
|
281 |
+
$ascii .= '\r';
|
282 |
+
break;
|
283 |
+
|
284 |
+
case $ord_var_c == 0x22:
|
285 |
+
case $ord_var_c == 0x2F:
|
286 |
+
case $ord_var_c == 0x5C:
|
287 |
+
// double quote, slash, slosh
|
288 |
+
$ascii .= '\\'.$var{$c};
|
289 |
+
break;
|
290 |
+
|
291 |
+
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
292 |
+
// characters U-00000000 - U-0000007F (same as ASCII)
|
293 |
+
$ascii .= $var{$c};
|
294 |
+
break;
|
295 |
+
|
296 |
+
case (($ord_var_c & 0xE0) == 0xC0):
|
297 |
+
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
298 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
299 |
+
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
|
300 |
+
$c += 1;
|
301 |
+
$utf16 = $this->utf82utf16($char);
|
302 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
303 |
+
break;
|
304 |
+
|
305 |
+
case (($ord_var_c & 0xF0) == 0xE0):
|
306 |
+
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
307 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
308 |
+
$char = pack('C*', $ord_var_c,
|
309 |
+
ord($var{$c + 1}),
|
310 |
+
ord($var{$c + 2}));
|
311 |
+
$c += 2;
|
312 |
+
$utf16 = $this->utf82utf16($char);
|
313 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
314 |
+
break;
|
315 |
+
|
316 |
+
case (($ord_var_c & 0xF8) == 0xF0):
|
317 |
+
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
318 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
319 |
+
$char = pack('C*', $ord_var_c,
|
320 |
+
ord($var{$c + 1}),
|
321 |
+
ord($var{$c + 2}),
|
322 |
+
ord($var{$c + 3}));
|
323 |
+
$c += 3;
|
324 |
+
$utf16 = $this->utf82utf16($char);
|
325 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
326 |
+
break;
|
327 |
+
|
328 |
+
case (($ord_var_c & 0xFC) == 0xF8):
|
329 |
+
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
330 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
331 |
+
$char = pack('C*', $ord_var_c,
|
332 |
+
ord($var{$c + 1}),
|
333 |
+
ord($var{$c + 2}),
|
334 |
+
ord($var{$c + 3}),
|
335 |
+
ord($var{$c + 4}));
|
336 |
+
$c += 4;
|
337 |
+
$utf16 = $this->utf82utf16($char);
|
338 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
339 |
+
break;
|
340 |
+
|
341 |
+
case (($ord_var_c & 0xFE) == 0xFC):
|
342 |
+
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
343 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
344 |
+
$char = pack('C*', $ord_var_c,
|
345 |
+
ord($var{$c + 1}),
|
346 |
+
ord($var{$c + 2}),
|
347 |
+
ord($var{$c + 3}),
|
348 |
+
ord($var{$c + 4}),
|
349 |
+
ord($var{$c + 5}));
|
350 |
+
$c += 5;
|
351 |
+
$utf16 = $this->utf82utf16($char);
|
352 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
353 |
+
break;
|
354 |
+
}
|
355 |
+
}
|
356 |
+
|
357 |
+
return '"'.$ascii.'"';
|
358 |
+
|
359 |
+
case 'array':
|
360 |
+
/*
|
361 |
+
* As per JSON spec if any array key is not an integer
|
362 |
+
* we must treat the the whole array as an object. We
|
363 |
+
* also try to catch a sparsely populated associative
|
364 |
+
* array with numeric keys here because some JS engines
|
365 |
+
* will create an array with empty indexes up to
|
366 |
+
* max_index which can cause memory issues and because
|
367 |
+
* the keys, which may be relevant, will be remapped
|
368 |
+
* otherwise.
|
369 |
+
*
|
370 |
+
* As per the ECMA and JSON specification an object may
|
371 |
+
* have any string as a property. Unfortunately due to
|
372 |
+
* a hole in the ECMA specification if the key is a
|
373 |
+
* ECMA reserved word or starts with a digit the
|
374 |
+
* parameter is only accessible using ECMAScript's
|
375 |
+
* bracket notation.
|
376 |
+
*/
|
377 |
+
|
378 |
+
// treat as a JSON object
|
379 |
+
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
380 |
+
$properties = array_map(array($this, 'name_value'),
|
381 |
+
array_keys($var),
|
382 |
+
array_values($var));
|
383 |
+
|
384 |
+
foreach($properties as $property) {
|
385 |
+
if(Services_JSON::isError($property)) {
|
386 |
+
return $property;
|
387 |
+
}
|
388 |
+
}
|
389 |
+
|
390 |
+
return '{' . join(',', $properties) . '}';
|
391 |
+
}
|
392 |
+
|
393 |
+
// treat it like a regular array
|
394 |
+
$elements = array_map(array($this, 'encode'), $var);
|
395 |
+
|
396 |
+
foreach($elements as $element) {
|
397 |
+
if(Services_JSON::isError($element)) {
|
398 |
+
return $element;
|
399 |
+
}
|
400 |
+
}
|
401 |
+
|
402 |
+
return '[' . join(',', $elements) . ']';
|
403 |
+
|
404 |
+
case 'object':
|
405 |
+
$vars = get_object_vars($var);
|
406 |
+
|
407 |
+
$properties = array_map(array($this, 'name_value'),
|
408 |
+
array_keys($vars),
|
409 |
+
array_values($vars));
|
410 |
+
|
411 |
+
foreach($properties as $property) {
|
412 |
+
if(Services_JSON::isError($property)) {
|
413 |
+
return $property;
|
414 |
+
}
|
415 |
+
}
|
416 |
+
|
417 |
+
return '{' . join(',', $properties) . '}';
|
418 |
+
|
419 |
+
default:
|
420 |
+
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
421 |
+
? 'null'
|
422 |
+
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
|
423 |
+
}
|
424 |
+
}
|
425 |
+
|
426 |
+
/**
|
427 |
+
* array-walking function for use in generating JSON-formatted name-value pairs
|
428 |
+
*
|
429 |
+
* @param string $name name of key to use
|
430 |
+
* @param mixed $value reference to an array element to be encoded
|
431 |
+
*
|
432 |
+
* @return string JSON-formatted name-value pair, like '"name":value'
|
433 |
+
* @access private
|
434 |
+
*/
|
435 |
+
function name_value($name, $value)
|
436 |
+
{
|
437 |
+
$encoded_value = $this->encode($value);
|
438 |
+
|
439 |
+
if(Services_JSON::isError($encoded_value)) {
|
440 |
+
return $encoded_value;
|
441 |
+
}
|
442 |
+
|
443 |
+
return $this->encode(strval($name)) . ':' . $encoded_value;
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* reduce a string by removing leading and trailing comments and whitespace
|
448 |
+
*
|
449 |
+
* @param $str string string value to strip of comments and whitespace
|
450 |
+
*
|
451 |
+
* @return string string value stripped of comments and whitespace
|
452 |
+
* @access private
|
453 |
+
*/
|
454 |
+
function reduce_string($str)
|
455 |
+
{
|
456 |
+
$str = preg_replace(array(
|
457 |
+
|
458 |
+
// eliminate single line comments in '// ...' form
|
459 |
+
'#^\s*//(.+)$#m',
|
460 |
+
|
461 |
+
// eliminate multi-line comments in '/* ... */' form, at start of string
|
462 |
+
'#^\s*/\*(.+)\*/#Us',
|
463 |
+
|
464 |
+
// eliminate multi-line comments in '/* ... */' form, at end of string
|
465 |
+
'#/\*(.+)\*/\s*$#Us'
|
466 |
+
|
467 |
+
), '', $str);
|
468 |
+
|
469 |
+
// eliminate extraneous space
|
470 |
+
return trim($str);
|
471 |
+
}
|
472 |
+
|
473 |
+
/**
|
474 |
+
* decodes a JSON string into appropriate variable
|
475 |
+
*
|
476 |
+
* @param string $str JSON-formatted string
|
477 |
+
*
|
478 |
+
* @return mixed number, boolean, string, array, or object
|
479 |
+
* corresponding to given JSON input string.
|
480 |
+
* See argument 1 to Services_JSON() above for object-output behavior.
|
481 |
+
* Note that decode() always returns strings
|
482 |
+
* in ASCII or UTF-8 format!
|
483 |
+
* @access public
|
484 |
+
*/
|
485 |
+
function decode($str)
|
486 |
+
{
|
487 |
+
$str = $this->reduce_string($str);
|
488 |
+
|
489 |
+
switch (strtolower($str)) {
|
490 |
+
case 'true':
|
491 |
+
return true;
|
492 |
+
|
493 |
+
case 'false':
|
494 |
+
return false;
|
495 |
+
|
496 |
+
case 'null':
|
497 |
+
return null;
|
498 |
+
|
499 |
+
default:
|
500 |
+
$m = array();
|
501 |
+
|
502 |
+
if (is_numeric($str)) {
|
503 |
+
// Lookie-loo, it's a number
|
504 |
+
|
505 |
+
// This would work on its own, but I'm trying to be
|
506 |
+
// good about returning integers where appropriate:
|
507 |
+
// return (float)$str;
|
508 |
+
|
509 |
+
// Return float or int, as appropriate
|
510 |
+
return ((float)$str == (integer)$str)
|
511 |
+
? (integer)$str
|
512 |
+
: (float)$str;
|
513 |
+
|
514 |
+
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
515 |
+
// STRINGS RETURNED IN UTF-8 FORMAT
|
516 |
+
$delim = substr($str, 0, 1);
|
517 |
+
$chrs = substr($str, 1, -1);
|
518 |
+
$utf8 = '';
|
519 |
+
$strlen_chrs = strlen($chrs);
|
520 |
+
|
521 |
+
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
522 |
+
|
523 |
+
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
524 |
+
$ord_chrs_c = ord($chrs{$c});
|
525 |
+
|
526 |
+
switch (true) {
|
527 |
+
case $substr_chrs_c_2 == '\b':
|
528 |
+
$utf8 .= chr(0x08);
|
529 |
+
++$c;
|
530 |
+
break;
|
531 |
+
case $substr_chrs_c_2 == '\t':
|
532 |
+
$utf8 .= chr(0x09);
|
533 |
+
++$c;
|
534 |
+
break;
|
535 |
+
case $substr_chrs_c_2 == '\n':
|
536 |
+
$utf8 .= chr(0x0A);
|
537 |
+
++$c;
|
538 |
+
break;
|
539 |
+
case $substr_chrs_c_2 == '\f':
|
540 |
+
$utf8 .= chr(0x0C);
|
541 |
+
++$c;
|
542 |
+
break;
|
543 |
+
case $substr_chrs_c_2 == '\r':
|
544 |
+
$utf8 .= chr(0x0D);
|
545 |
+
++$c;
|
546 |
+
break;
|
547 |
+
|
548 |
+
case $substr_chrs_c_2 == '\\"':
|
549 |
+
case $substr_chrs_c_2 == '\\\'':
|
550 |
+
case $substr_chrs_c_2 == '\\\\':
|
551 |
+
case $substr_chrs_c_2 == '\\/':
|
552 |
+
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
553 |
+
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
554 |
+
$utf8 .= $chrs{++$c};
|
555 |
+
}
|
556 |
+
break;
|
557 |
+
|
558 |
+
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
|
559 |
+
// single, escaped unicode character
|
560 |
+
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
|
561 |
+
. chr(hexdec(substr($chrs, ($c + 4), 2)));
|
562 |
+
$utf8 .= $this->utf162utf8($utf16);
|
563 |
+
$c += 5;
|
564 |
+
break;
|
565 |
+
|
566 |
+
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
567 |
+
$utf8 .= $chrs{$c};
|
568 |
+
break;
|
569 |
+
|
570 |
+
case ($ord_chrs_c & 0xE0) == 0xC0:
|
571 |
+
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
572 |
+
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
573 |
+
$utf8 .= substr($chrs, $c, 2);
|
574 |
+
++$c;
|
575 |
+
break;
|
576 |
+
|
577 |
+
case ($ord_chrs_c & 0xF0) == 0xE0:
|
578 |
+
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
579 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
580 |
+
$utf8 .= substr($chrs, $c, 3);
|
581 |
+
$c += 2;
|
582 |
+
break;
|
583 |
+
|
584 |
+
case ($ord_chrs_c & 0xF8) == 0xF0:
|
585 |
+
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
586 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
587 |
+
$utf8 .= substr($chrs, $c, 4);
|
588 |
+
$c += 3;
|
589 |
+
break;
|
590 |
+
|
591 |
+
case ($ord_chrs_c & 0xFC) == 0xF8:
|
592 |
+
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
593 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
594 |
+
$utf8 .= substr($chrs, $c, 5);
|
595 |
+
$c += 4;
|
596 |
+
break;
|
597 |
+
|
598 |
+
case ($ord_chrs_c & 0xFE) == 0xFC:
|
599 |
+
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
600 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
601 |
+
$utf8 .= substr($chrs, $c, 6);
|
602 |
+
$c += 5;
|
603 |
+
break;
|
604 |
+
|
605 |
+
}
|
606 |
+
|
607 |
+
}
|
608 |
+
|
609 |
+
return $utf8;
|
610 |
+
|
611 |
+
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
612 |
+
// array, or object notation
|
613 |
+
|
614 |
+
if ($str{0} == '[') {
|
615 |
+
$stk = array(SERVICES_JSON_IN_ARR);
|
616 |
+
$arr = array();
|
617 |
+
} else {
|
618 |
+
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
619 |
+
$stk = array(SERVICES_JSON_IN_OBJ);
|
620 |
+
$obj = array();
|
621 |
+
} else {
|
622 |
+
$stk = array(SERVICES_JSON_IN_OBJ);
|
623 |
+
$obj = new stdClass();
|
624 |
+
}
|
625 |
+
}
|
626 |
+
|
627 |
+
array_push($stk, array('what' => SERVICES_JSON_SLICE,
|
628 |
+
'where' => 0,
|
629 |
+
'delim' => false));
|
630 |
+
|
631 |
+
$chrs = substr($str, 1, -1);
|
632 |
+
$chrs = $this->reduce_string($chrs);
|
633 |
+
|
634 |
+
if ($chrs == '') {
|
635 |
+
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
636 |
+
return $arr;
|
637 |
+
|
638 |
+
} else {
|
639 |
+
return $obj;
|
640 |
+
|
641 |
+
}
|
642 |
+
}
|
643 |
+
|
644 |
+
//print("\nparsing {$chrs}\n");
|
645 |
+
|
646 |
+
$strlen_chrs = strlen($chrs);
|
647 |
+
|
648 |
+
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
649 |
+
|
650 |
+
$top = end($stk);
|
651 |
+
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
652 |
+
|
653 |
+
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
|
654 |
+
// found a comma that is not inside a string, array, etc.,
|
655 |
+
// OR we've reached the end of the character list
|
656 |
+
$slice = substr($chrs, $top['where'], ($c - $top['where']));
|
657 |
+
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
|
658 |
+
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
659 |
+
|
660 |
+
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
661 |
+
// we are in an array, so just push an element onto the stack
|
662 |
+
array_push($arr, $this->decode($slice));
|
663 |
+
|
664 |
+
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
665 |
+
// we are in an object, so figure
|
666 |
+
// out the property name and set an
|
667 |
+
// element in an associative array,
|
668 |
+
// for now
|
669 |
+
$parts = array();
|
670 |
+
|
671 |
+
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
672 |
+
// "name":value pair
|
673 |
+
$key = $this->decode($parts[1]);
|
674 |
+
$val = $this->decode($parts[2]);
|
675 |
+
|
676 |
+
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
677 |
+
$obj[$key] = $val;
|
678 |
+
} else {
|
679 |
+
$obj->$key = $val;
|
680 |
+
}
|
681 |
+
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
682 |
+
// name:value pair, where name is unquoted
|
683 |
+
$key = $parts[1];
|
684 |
+
$val = $this->decode($parts[2]);
|
685 |
+
|
686 |
+
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
687 |
+
$obj[$key] = $val;
|
688 |
+
} else {
|
689 |
+
$obj->$key = $val;
|
690 |
+
}
|
691 |
+
}
|
692 |
+
|
693 |
+
}
|
694 |
+
|
695 |
+
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
|
696 |
+
// found a quote, and we are not inside a string
|
697 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
|
698 |
+
//print("Found start of string at {$c}\n");
|
699 |
+
|
700 |
+
} elseif (($chrs{$c} == $top['delim']) &&
|
701 |
+
($top['what'] == SERVICES_JSON_IN_STR) &&
|
702 |
+
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
|
703 |
+
// found a quote, we're in a string, and it's not escaped
|
704 |
+
// we know that it's not escaped becase there is _not_ an
|
705 |
+
// odd number of backslashes at the end of the string so far
|
706 |
+
array_pop($stk);
|
707 |
+
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
708 |
+
|
709 |
+
} elseif (($chrs{$c} == '[') &&
|
710 |
+
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
711 |
+
// found a left-bracket, and we are in an array, object, or slice
|
712 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
|
713 |
+
//print("Found start of array at {$c}\n");
|
714 |
+
|
715 |
+
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
|
716 |
+
// found a right-bracket, and we're in an array
|
717 |
+
array_pop($stk);
|
718 |
+
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
719 |
+
|
720 |
+
} elseif (($chrs{$c} == '{') &&
|
721 |
+
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
722 |
+
// found a left-brace, and we are in an array, object, or slice
|
723 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
|
724 |
+
//print("Found start of object at {$c}\n");
|
725 |
+
|
726 |
+
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
|
727 |
+
// found a right-brace, and we're in an object
|
728 |
+
array_pop($stk);
|
729 |
+
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
730 |
+
|
731 |
+
} elseif (($substr_chrs_c_2 == '/*') &&
|
732 |
+
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
733 |
+
// found a comment start, and we are in an array, object, or slice
|
734 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
|
735 |
+
$c++;
|
736 |
+
//print("Found start of comment at {$c}\n");
|
737 |
+
|
738 |
+
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
|
739 |
+
// found a comment end, and we're in one now
|
740 |
+
array_pop($stk);
|
741 |
+
$c++;
|
742 |
+
|
743 |
+
for ($i = $top['where']; $i <= $c; ++$i)
|
744 |
+
$chrs = substr_replace($chrs, ' ', $i, 1);
|
745 |
+
|
746 |
+
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
747 |
+
|
748 |
+
}
|
749 |
+
|
750 |
+
}
|
751 |
+
|
752 |
+
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
753 |
+
return $arr;
|
754 |
+
|
755 |
+
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
756 |
+
return $obj;
|
757 |
+
|
758 |
+
}
|
759 |
+
|
760 |
+
}
|
761 |
+
}
|
762 |
+
}
|
763 |
+
|
764 |
+
/**
|
765 |
+
* @todo Ultimately, this should just call PEAR::isError()
|
766 |
+
*/
|
767 |
+
function isError($data, $code = null)
|
768 |
+
{
|
769 |
+
if (class_exists('pear')) {
|
770 |
+
return PEAR::isError($data, $code);
|
771 |
+
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
|
772 |
+
is_subclass_of($data, 'services_json_error'))) {
|
773 |
+
return true;
|
774 |
+
}
|
775 |
+
|
776 |
+
return false;
|
777 |
+
}
|
778 |
+
}
|
779 |
+
|
780 |
+
if (class_exists('PEAR_Error')) {
|
781 |
+
|
782 |
+
class Services_JSON_Error extends PEAR_Error
|
783 |
+
{
|
784 |
+
function Services_JSON_Error($message = 'unknown error', $code = null,
|
785 |
+
$mode = null, $options = null, $userinfo = null)
|
786 |
+
{
|
787 |
+
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
|
788 |
+
}
|
789 |
+
}
|
790 |
+
|
791 |
+
} else {
|
792 |
+
|
793 |
+
/**
|
794 |
+
* @todo Ultimately, this class shall be descended from PEAR_Error
|
795 |
+
*/
|
796 |
+
class Services_JSON_Error
|
797 |
+
{
|
798 |
+
function Services_JSON_Error($message = 'unknown error', $code = null,
|
799 |
+
$mode = null, $options = null, $userinfo = null)
|
800 |
+
{
|
801 |
+
|
802 |
+
}
|
803 |
+
}
|
804 |
+
|
805 |
+
}
|
806 |
+
endif;
|
807 |
+
?>
|
trunk/ZeroClipboard.js
ADDED
@@ -0,0 +1,302 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Simple Set Clipboard System
|
2 |
+
// Author: Joseph Huckaby
|
3 |
+
|
4 |
+
var ZeroClipboard = {
|
5 |
+
|
6 |
+
version: "1.0.5",
|
7 |
+
clients: {}, // registered upload clients on page, indexed by id
|
8 |
+
moviePath: 'ZeroClipboard.swf', // URL to movie
|
9 |
+
nextId: 1, // ID of next movie
|
10 |
+
|
11 |
+
$: function(thingy) {
|
12 |
+
// simple DOM lookup utility function
|
13 |
+
if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
|
14 |
+
if (!thingy.addClass) {
|
15 |
+
// extend element with a few useful methods
|
16 |
+
thingy.hide = function() { this.style.display = 'none'; };
|
17 |
+
thingy.show = function() { this.style.display = ''; };
|
18 |
+
thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
|
19 |
+
thingy.removeClass = function(name) {
|
20 |
+
this.className = this.className.replace( new RegExp("(^|\\s+)" + name + "(\\s+|$)"), "").replace(/^\s+|\s+$/g, '');
|
21 |
+
};
|
22 |
+
thingy.hasClass = function(name) {
|
23 |
+
return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
|
24 |
+
};
|
25 |
+
}
|
26 |
+
return thingy;
|
27 |
+
},
|
28 |
+
|
29 |
+
setMoviePath: function(path) {
|
30 |
+
// set path to ZeroClipboard.swf
|
31 |
+
this.moviePath = path;
|
32 |
+
},
|
33 |
+
|
34 |
+
dispatch: function(id, eventName, args) {
|
35 |
+
// receive event from flash movie, send to client
|
36 |
+
var client = this.clients[id];
|
37 |
+
if (client) {
|
38 |
+
client.receiveEvent(eventName, args);
|
39 |
+
}
|
40 |
+
},
|
41 |
+
|
42 |
+
register: function(id, client) {
|
43 |
+
// register new client to receive events
|
44 |
+
this.clients[id] = client;
|
45 |
+
},
|
46 |
+
|
47 |
+
getDOMObjectPosition: function(obj, stopObj) {
|
48 |
+
// get absolute coordinates for dom element
|
49 |
+
var info = {
|
50 |
+
left: 0,
|
51 |
+
top: 0,
|
52 |
+
width: obj.width ? obj.width : obj.offsetWidth,
|
53 |
+
height: obj.height ? obj.height : obj.offsetHeight
|
54 |
+
};
|
55 |
+
|
56 |
+
while (obj && (obj != stopObj)) {
|
57 |
+
info.left += obj.offsetLeft;
|
58 |
+
info.top += obj.offsetTop;
|
59 |
+
obj = obj.offsetParent;
|
60 |
+
}
|
61 |
+
|
62 |
+
return info;
|
63 |
+
},
|
64 |
+
|
65 |
+
Client: function(elem) {
|
66 |
+
// constructor for new simple upload client
|
67 |
+
this.handlers = {};
|
68 |
+
|
69 |
+
// unique ID
|
70 |
+
this.id = ZeroClipboard.nextId++;
|
71 |
+
this.movieId = 'ZeroClipboardMovie_' + this.id;
|
72 |
+
|
73 |
+
// register client with singleton to receive flash events
|
74 |
+
ZeroClipboard.register(this.id, this);
|
75 |
+
|
76 |
+
// create movie
|
77 |
+
if (elem) this.glue(elem);
|
78 |
+
}
|
79 |
+
};
|
80 |
+
|
81 |
+
ZeroClipboard.Client.prototype = {
|
82 |
+
|
83 |
+
id: 0, // unique ID for us
|
84 |
+
ready: false, // whether movie is ready to receive events or not
|
85 |
+
movie: null, // reference to movie object
|
86 |
+
clipText: '', // text to copy to clipboard
|
87 |
+
handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
|
88 |
+
cssEffects: true, // enable CSS mouse effects on dom container
|
89 |
+
handlers: null, // user event handlers
|
90 |
+
|
91 |
+
glue: function(elem, appendElem, stylesToAdd) {
|
92 |
+
// glue to DOM element
|
93 |
+
// elem can be ID or actual DOM element object
|
94 |
+
this.domElement = ZeroClipboard.$(elem);
|
95 |
+
|
96 |
+
// float just above object, or zIndex 99 if dom element isn't set
|
97 |
+
var zIndex = 99;
|
98 |
+
if (this.domElement.style.zIndex) {
|
99 |
+
zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
|
100 |
+
}
|
101 |
+
|
102 |
+
if (typeof(appendElem) == 'string') {
|
103 |
+
appendElem = ZeroClipboard.$(appendElem);
|
104 |
+
}
|
105 |
+
else if (typeof(appendElem) == 'undefined') {
|
106 |
+
appendElem = document.getElementsByTagName('body')[0];
|
107 |
+
}
|
108 |
+
|
109 |
+
// find X/Y position of domElement
|
110 |
+
var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem);
|
111 |
+
|
112 |
+
// create floating DIV above element
|
113 |
+
this.div = document.createElement('div');
|
114 |
+
var style = this.div.style;
|
115 |
+
style.position = 'absolute';
|
116 |
+
style.left = '' + box.left + 'px';
|
117 |
+
style.top = '' + box.top + 'px';
|
118 |
+
style.width = '' + box.width + 'px';
|
119 |
+
style.height = '' + box.height + 'px';
|
120 |
+
style.zIndex = zIndex;
|
121 |
+
|
122 |
+
if (typeof(stylesToAdd) == 'object') {
|
123 |
+
for (addedStyle in stylesToAdd) {
|
124 |
+
style[addedStyle] = stylesToAdd[addedStyle];
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
// style.backgroundColor = '#f00'; // debug
|
129 |
+
|
130 |
+
appendElem.appendChild(this.div);
|
131 |
+
|
132 |
+
this.div.innerHTML = this.getHTML( box.width, box.height );
|
133 |
+
},
|
134 |
+
|
135 |
+
getHTML: function(width, height) {
|
136 |
+
// return HTML for movie
|
137 |
+
var html = '';
|
138 |
+
var flashvars = 'id=' + this.id +
|
139 |
+
'&width=' + width +
|
140 |
+
'&height=' + height;
|
141 |
+
|
142 |
+
if (navigator.userAgent.match(/MSIE/)) {
|
143 |
+
// IE gets an OBJECT tag
|
144 |
+
var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
|
145 |
+
html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
|
146 |
+
}
|
147 |
+
else {
|
148 |
+
// all other browsers get an EMBED tag
|
149 |
+
html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
|
150 |
+
}
|
151 |
+
return html;
|
152 |
+
},
|
153 |
+
|
154 |
+
hide: function() {
|
155 |
+
// temporarily hide floater offscreen
|
156 |
+
if (this.div) {
|
157 |
+
this.div.style.left = '-2000px';
|
158 |
+
}
|
159 |
+
},
|
160 |
+
|
161 |
+
show: function() {
|
162 |
+
// show ourselves after a call to hide()
|
163 |
+
this.reposition();
|
164 |
+
},
|
165 |
+
|
166 |
+
destroy: function() {
|
167 |
+
// destroy control and floater
|
168 |
+
if (this.domElement && this.div) {
|
169 |
+
this.hide();
|
170 |
+
this.div.innerHTML = '';
|
171 |
+
|
172 |
+
var body = document.getElementsByTagName('body')[0];
|
173 |
+
try { body.removeChild( this.div ); } catch(e) {;}
|
174 |
+
|
175 |
+
this.domElement = null;
|
176 |
+
this.div = null;
|
177 |
+
}
|
178 |
+
},
|
179 |
+
|
180 |
+
reposition: function(elem) {
|
181 |
+
// reposition our floating div, optionally to new container
|
182 |
+
// warning: container CANNOT change size, only position
|
183 |
+
if (elem) {
|
184 |
+
this.domElement = ZeroClipboard.$(elem);
|
185 |
+
if (!this.domElement) this.hide();
|
186 |
+
}
|
187 |
+
|
188 |
+
if (this.domElement && this.div) {
|
189 |
+
var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
|
190 |
+
var style = this.div.style;
|
191 |
+
style.left = '' + box.left + 'px';
|
192 |
+
style.top = '' + box.top + 'px';
|
193 |
+
}
|
194 |
+
},
|
195 |
+
|
196 |
+
setText: function(newText) {
|
197 |
+
// set text to be copied to clipboard
|
198 |
+
this.clipText = newText;
|
199 |
+
if (this.ready) this.movie.setText(newText);
|
200 |
+
},
|
201 |
+
|
202 |
+
addEventListener: function(eventName, func) {
|
203 |
+
// add user event listener for event
|
204 |
+
// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
|
205 |
+
eventName = eventName.toString().toLowerCase().replace(/^on/, '');
|
206 |
+
if (!this.handlers[eventName]) this.handlers[eventName] = [];
|
207 |
+
this.handlers[eventName].push(func);
|
208 |
+
},
|
209 |
+
|
210 |
+
setHandCursor: function(enabled) {
|
211 |
+
// enable hand cursor (true), or default arrow cursor (false)
|
212 |
+
this.handCursorEnabled = enabled;
|
213 |
+
if (this.ready) this.movie.setHandCursor(enabled);
|
214 |
+
},
|
215 |
+
|
216 |
+
setCSSEffects: function(enabled) {
|
217 |
+
// enable or disable CSS effects on DOM container
|
218 |
+
this.cssEffects = !!enabled;
|
219 |
+
},
|
220 |
+
|
221 |
+
receiveEvent: function(eventName, args) {
|
222 |
+
// receive event from flash
|
223 |
+
eventName = eventName.toString().toLowerCase().replace(/^on/, '');
|
224 |
+
|
225 |
+
// special behavior for certain events
|
226 |
+
switch (eventName) {
|
227 |
+
case 'load':
|
228 |
+
// movie claims it is ready, but in IE this isn't always the case...
|
229 |
+
// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
|
230 |
+
this.movie = document.getElementById(this.movieId);
|
231 |
+
if (!this.movie) {
|
232 |
+
var self = this;
|
233 |
+
setTimeout( function() { self.receiveEvent('load', null); }, 1 );
|
234 |
+
return;
|
235 |
+
}
|
236 |
+
|
237 |
+
// firefox on pc needs a "kick" in order to set these in certain cases
|
238 |
+
if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
|
239 |
+
var self = this;
|
240 |
+
setTimeout( function() { self.receiveEvent('load', null); }, 100 );
|
241 |
+
this.ready = true;
|
242 |
+
return;
|
243 |
+
}
|
244 |
+
|
245 |
+
this.ready = true;
|
246 |
+
this.movie.setText( this.clipText );
|
247 |
+
this.movie.setHandCursor( this.handCursorEnabled );
|
248 |
+
break;
|
249 |
+
|
250 |
+
case 'mouseover':
|
251 |
+
if (this.domElement && this.cssEffects) {
|
252 |
+
this.domElement.addClass('hover');
|
253 |
+
if (this.recoverActive) this.domElement.addClass('active');
|
254 |
+
}
|
255 |
+
break;
|
256 |
+
|
257 |
+
case 'mouseout':
|
258 |
+
if (this.domElement && this.cssEffects) {
|
259 |
+
this.recoverActive = false;
|
260 |
+
if (this.domElement.hasClass('active')) {
|
261 |
+
this.domElement.removeClass('active');
|
262 |
+
this.recoverActive = true;
|
263 |
+
}
|
264 |
+
this.domElement.removeClass('hover');
|
265 |
+
}
|
266 |
+
break;
|
267 |
+
|
268 |
+
case 'mousedown':
|
269 |
+
if (this.domElement && this.cssEffects) {
|
270 |
+
this.domElement.addClass('active');
|
271 |
+
}
|
272 |
+
break;
|
273 |
+
|
274 |
+
case 'mouseup':
|
275 |
+
if (this.domElement && this.cssEffects) {
|
276 |
+
this.domElement.removeClass('active');
|
277 |
+
this.recoverActive = false;
|
278 |
+
}
|
279 |
+
break;
|
280 |
+
} // switch eventName
|
281 |
+
|
282 |
+
if (this.handlers[eventName]) {
|
283 |
+
for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
|
284 |
+
var func = this.handlers[eventName][idx];
|
285 |
+
|
286 |
+
if (typeof(func) == 'function') {
|
287 |
+
// actual function reference
|
288 |
+
func(this, args);
|
289 |
+
}
|
290 |
+
else if ((typeof(func) == 'object') && (func.length == 2)) {
|
291 |
+
// PHP style object + method, i.e. [myObject, 'myMethod']
|
292 |
+
func[0][ func[1] ](this, args);
|
293 |
+
}
|
294 |
+
else if (typeof(func) == 'string') {
|
295 |
+
// name of function
|
296 |
+
window[func](this, args);
|
297 |
+
}
|
298 |
+
} // foreach event handler defined
|
299 |
+
} // user defined handler for event
|
300 |
+
}
|
301 |
+
|
302 |
+
};
|
trunk/ZeroClipboard.swf
ADDED
Binary file
|
trunk/accountconfig.php
ADDED
@@ -0,0 +1,297 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// Settings page in the admin panel
|
4 |
+
function zopim_account_config() {
|
5 |
+
global $usernameToCodeURL, $languagesURL, $current_user;
|
6 |
+
|
7 |
+
?>
|
8 |
+
|
9 |
+
<div class="wrap">
|
10 |
+
|
11 |
+
<?php
|
12 |
+
|
13 |
+
if ($_GET["action"]=="deactivate") {
|
14 |
+
update_option('zopimSalt', "");
|
15 |
+
update_option('zopimCode', "zopim");
|
16 |
+
}
|
17 |
+
|
18 |
+
$message = "";
|
19 |
+
if ($_POST["action"]=="login") {
|
20 |
+
if ($_POST["zopimUseSSL"] == "") {
|
21 |
+
$_POST["zopimUseSSL"] = "nossl";
|
22 |
+
}
|
23 |
+
update_option('zopimUseSSL', $_POST["zopimUseSSL"]);
|
24 |
+
|
25 |
+
if ($_POST["zopimPassword"] != "password") {
|
26 |
+
|
27 |
+
$logindata = array("email" => $_POST["zopimUsername"], "password" => $_POST["zopimPassword"]);
|
28 |
+
$loginresult = json_to_array(do_post_request(ZOPIM_LOGIN_URL, $logindata));
|
29 |
+
|
30 |
+
if (isset($loginresult->error)) {
|
31 |
+
$error["login"] = "<b>Could not log in to Zopim. Please check your login details. If problem persists, try connecting without SSL enabled.</b>";
|
32 |
+
$gotologin = 1;
|
33 |
+
update_option('zopimSalt', "wronglogin");
|
34 |
+
} else if (isset($loginresult->salt)) {
|
35 |
+
update_option('zopimUsername', $_POST["zopimUsername"]);
|
36 |
+
update_option('zopimSalt', $loginresult->salt);
|
37 |
+
$account = getAccountDetails(get_option('zopimSalt'));
|
38 |
+
|
39 |
+
if (isset($account)) {
|
40 |
+
update_option('zopimCode', $account->account_key);
|
41 |
+
|
42 |
+
if (get_option('zopimGreetings') == "") {
|
43 |
+
$jsongreetings = to_json($account->settings->greetings);
|
44 |
+
update_option('zopimGreetings', $jsongreetings);
|
45 |
+
}
|
46 |
+
}
|
47 |
+
} else {
|
48 |
+
update_option('zopimSalt', "");
|
49 |
+
$error["login"] = "<b>Could not log in to Zopim. We were unable to contact Zopim servers. Please check with your server administrator to ensure that <a href='http://www.php.net/manual/en/book.curl.php'>PHP Curl</a> is installed and permissions are set correctly.</b>";
|
50 |
+
}
|
51 |
+
}
|
52 |
+
} else if ($_POST["action"]=="signup") {
|
53 |
+
|
54 |
+
if ($_POST["zopimUseSSL"] == "") {
|
55 |
+
$_POST["zopimUseSSL"] = "nossl";
|
56 |
+
}
|
57 |
+
update_option('zopimUseSSL', $_POST["zopimUseSSL"]);
|
58 |
+
|
59 |
+
$createdata = array(
|
60 |
+
"email" => $_POST["zopimnewemail"],
|
61 |
+
"first_name" => $_POST["zopimfirstname"],
|
62 |
+
"last_name" => $_POST["zopimlastname"],
|
63 |
+
"display_name" => $_POST["zopimfirstname"]." ".$_POST["zopimlastname"],
|
64 |
+
"eref" => $_POST["zopimeref"],
|
65 |
+
"source" => "wordpress",
|
66 |
+
"recaptcha_challenge_field" => $_POST["recaptcha_challenge_field"],
|
67 |
+
"recaptcha_response_field" => $_POST["recaptcha_response_field"]
|
68 |
+
);
|
69 |
+
|
70 |
+
$signupresult = json_to_array(do_post_request(ZOPIM_SIGNUP_URL, $createdata));
|
71 |
+
if (isset($signupresult->error)) {
|
72 |
+
$message = "<div style='color:#c33;'>Error during activation: <b>".$signupresult->error."</b>. Please try again.</div>";
|
73 |
+
} else if (isset($signupresult->account_key)) {
|
74 |
+
$message = "<b>Thank you for signing up. Please check your mail for your password to complete the process. </b>";
|
75 |
+
$gotologin = 1;
|
76 |
+
} else {
|
77 |
+
$message = "<b>Could not activate account. The wordpress installation was unable to contact Zopim servers. Please check with your server administrator to ensure that <a href='http://www.php.net/manual/en/book.curl.php'>PHP Curl</a> is installed and permissions are set correctly.</b>";
|
78 |
+
}
|
79 |
+
}
|
80 |